/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.hadoop.hbase.codec.prefixtree.decode; import java.nio.ByteBuffer; import org.apache.hadoop.hbase.ByteBufferCell; import org.apache.hadoop.hbase.Cell; import org.apache.hadoop.hbase.CellComparator; import org.apache.hadoop.hbase.CellUtil; import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.KeyValueUtil; import org.apache.hadoop.hbase.SettableSequenceId; import org.apache.hadoop.hbase.classification.InterfaceAudience; import org.apache.hadoop.hbase.nio.ByteBuff; import org.apache.hadoop.hbase.util.ByteBufferUtils; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.ObjectIntPair; /** * As the PrefixTreeArrayScanner moves through the tree bytes, it changes the * values in the fields of this class so that Cell logic can be applied, but * without allocating new memory for every Cell iterated through. */ @InterfaceAudience.Private public class PrefixTreeCell extends ByteBufferCell implements SettableSequenceId, Comparable<Cell> { // Create a reference here? Can be removed too protected CellComparator comparator = CellComparator.COMPARATOR; /********************** static **********************/ public static final KeyValue.Type[] TYPES = new KeyValue.Type[256]; static { for (KeyValue.Type type : KeyValue.Type.values()) { TYPES[type.getCode() & 0xff] = type; } } // Same as KeyValue constructor. Only used to avoid NPE's when full cell // hasn't been initialized. public static final KeyValue.Type DEFAULT_TYPE = KeyValue.Type.Put; /******************** fields ************************/ protected ByteBuff block; // we could also avoid setting the mvccVersion in the scanner/searcher, but // this is simpler protected boolean includeMvccVersion; protected byte[] rowBuffer; protected int rowLength; protected byte[] familyBuffer; protected int familyOffset; protected int familyLength; protected byte[] qualifierBuffer;// aligned to the end of the array protected int qualifierOffset; protected int qualifierLength; protected Long timestamp; protected Long mvccVersion; protected KeyValue.Type type; protected int absoluteValueOffset; protected int valueLength; protected byte[] tagsBuffer; protected int tagsOffset; protected int tagsLength; // Pair to set the value ByteBuffer and its offset protected ObjectIntPair<ByteBuffer> pair = new ObjectIntPair<>(); /********************** Cell methods ******************/ /** * For debugging. Currently creates new KeyValue to utilize its toString() * method. */ @Override public String toString() { return getKeyValueString(); } @Override public boolean equals(Object obj) { if (!(obj instanceof Cell)) { return false; } // Temporary hack to maintain backwards compatibility with KeyValue.equals return CellUtil.equalsIgnoreMvccVersion(this, (Cell) obj); // TODO return CellComparator.equals(this, (Cell)obj);//see HBASE-6907 } @Override public int hashCode() { return calculateHashForKey(this); } private int calculateHashForKey(Cell cell) { // pre-calculate the 3 hashes made of byte ranges int rowHash = Bytes.hashCode(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength()); int familyHash = Bytes.hashCode(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength()); int qualifierHash = Bytes.hashCode(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()); // combine the 6 sub-hashes int hash = 31 * rowHash + familyHash; hash = 31 * hash + qualifierHash; hash = 31 * hash + (int) cell.getTimestamp(); hash = 31 * hash + cell.getTypeByte(); return hash; } @Override public int compareTo(Cell other) { return comparator.compare(this, other); } @Override public long getTimestamp() { return timestamp; } @Override public long getSequenceId() { if (!includeMvccVersion) { return 0L; } return mvccVersion; } @Override public int getValueLength() { return valueLength; } @Override public byte[] getRowArray() { return rowBuffer; } @Override public int getRowOffset() { return 0; } @Override public short getRowLength() { return (short) rowLength; } @Override public byte[] getFamilyArray() { return familyBuffer; } @Override public int getFamilyOffset() { return familyOffset; } @Override public byte getFamilyLength() { return (byte) familyLength; } @Override public byte[] getQualifierArray() { return qualifierBuffer; } @Override public int getQualifierOffset() { return qualifierOffset; } @Override public int getQualifierLength() { return qualifierLength; } @Override public byte[] getValueArray() { if (this.pair.getFirst().hasArray()) { return this.pair.getFirst().array(); } else { // Just in case getValueArray is called on offheap BB byte[] val = new byte[valueLength]; ByteBufferUtils.copyFromBufferToArray(val, this.pair.getFirst(), this.pair.getSecond(), 0, valueLength); return val; } } @Override public int getValueOffset() { if (this.pair.getFirst().hasArray()) { return this.pair.getSecond() + this.pair.getFirst().arrayOffset(); } else { return 0; } } @Override public byte getTypeByte() { return type.getCode(); } /************************* helper methods *************************/ /** * Need this separate method so we can call it from subclasses' toString() * methods */ protected String getKeyValueString() { KeyValue kv = KeyValueUtil.copyToNewKeyValue(this); return kv.toString(); } @Override public int getTagsOffset() { return tagsOffset; } @Override public int getTagsLength() { return tagsLength; } @Override public byte[] getTagsArray() { return this.tagsBuffer; } @Override public void setSequenceId(long seqId) { mvccVersion = seqId; } @Override public ByteBuffer getRowByteBuffer() { return ByteBuffer.wrap(rowBuffer); } @Override public int getRowPosition() { return 0; } @Override public ByteBuffer getFamilyByteBuffer() { return ByteBuffer.wrap(familyBuffer); } @Override public int getFamilyPosition() { return getFamilyOffset(); } @Override public ByteBuffer getQualifierByteBuffer() { return ByteBuffer.wrap(qualifierBuffer); } @Override public int getQualifierPosition() { return getQualifierOffset(); } @Override public ByteBuffer getValueByteBuffer() { return pair.getFirst(); } @Override public int getValuePosition() { return pair.getSecond(); } @Override public ByteBuffer getTagsByteBuffer() { return ByteBuffer.wrap(tagsBuffer); } @Override public int getTagsPosition() { return getTagsOffset(); } }