diff --git hbase-common/src/main/java/org/apache/hadoop/hbase/io/encoding/BufferedDataBlockEncoder.java hbase-common/src/main/java/org/apache/hadoop/hbase/io/encoding/BufferedDataBlockEncoder.java index a063324..de57061 100644 --- hbase-common/src/main/java/org/apache/hadoop/hbase/io/encoding/BufferedDataBlockEncoder.java +++ hbase-common/src/main/java/org/apache/hadoop/hbase/io/encoding/BufferedDataBlockEncoder.java @@ -29,6 +29,7 @@ import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.KeyValue.KVComparator; import org.apache.hadoop.hbase.KeyValue.SamePrefixComparator; import org.apache.hadoop.hbase.KeyValue.Type; +import org.apache.hadoop.hbase.KeyValueUtil; import org.apache.hadoop.hbase.io.TagCompressionContext; import org.apache.hadoop.hbase.io.hfile.BlockType; import org.apache.hadoop.hbase.io.hfile.HFileContext; @@ -74,7 +75,17 @@ abstract class BufferedDataBlockEncoder implements DataBlockEncoder { return internalDecodeKeyValues(source, 0, 0, decodingCtx); } - protected static class SeekerState { + protected static class SeekerState implements Cell, Comparable { + protected ByteBuffer currentBuffer; + protected TagCompressionContext tagCompressionContext; + protected short rowLength; + protected int familyOffset = -1; + protected byte familyLength; + protected int qualifierOffset = -1; + protected int qualifierLength; + protected long timestamp; + protected byte typeByte; + protected int valueOffset = -1; protected int keyLength; protected int valueLength; @@ -98,7 +109,10 @@ abstract class BufferedDataBlockEncoder implements DataBlockEncoder { protected void invalidate() { valueOffset = -1; tagsCompressedLength = 0; + familyOffset = -1; + qualifierOffset = -1; uncompressTags = true; + currentBuffer = null; } protected void ensureSpaceForKey() { @@ -127,6 +141,18 @@ abstract class BufferedDataBlockEncoder implements DataBlockEncoder { } } + protected void extractOffsetsAndLengthsFromKey(byte[] keyBuffer) { + rowLength = Bytes.toShort(keyBuffer); + familyOffset = Bytes.SIZEOF_SHORT + getRowLength() + Bytes.SIZEOF_BYTE; + familyLength = keyBuffer[getFamilyOffset() - Bytes.SIZEOF_BYTE]; + qualifierOffset = familyOffset + familyLength; + qualifierLength = keyLength + - (int) KeyValue.getKeyDataStructureSize(rowLength, familyLength, 0); + int tsOffset = keyLength - KeyValue.TIMESTAMP_TYPE_SIZE; + timestamp = Bytes.toLong(keyBuffer, tsOffset); + typeByte = keyBuffer[keyLength - 1]; + } + /** * Copy the state from the next one into this instance (the previous state * placeholder). Used to save the previous state when we are advancing the @@ -147,12 +173,175 @@ abstract class BufferedDataBlockEncoder implements DataBlockEncoder { - nextState.lastCommonPrefix); } + rowLength = nextState.rowLength; + familyOffset = nextState.familyOffset; + familyLength = nextState.familyLength; + qualifierOffset = nextState.qualifierOffset; + qualifierLength = nextState.qualifierLength; + timestamp = nextState.timestamp; + typeByte = nextState.typeByte; + valueOffset = nextState.valueOffset; keyLength = nextState.keyLength; valueLength = nextState.valueLength; lastCommonPrefix = nextState.lastCommonPrefix; nextKvOffset = nextState.nextKvOffset; memstoreTS = nextState.memstoreTS; + currentBuffer = nextState.currentBuffer; + if (nextState.tagCompressionContext != null) { + tagCompressionContext = nextState.tagCompressionContext; + } + } + + @Override + public byte[] getRowArray() { + return keyBuffer; + } + + @Override + public int getRowOffset() { + return Bytes.SIZEOF_SHORT; + } + + @Override + public short getRowLength() { + return rowLength; + } + + @Override + public byte[] getFamilyArray() { + return keyBuffer; + } + + @Override + public int getFamilyOffset() { + return familyOffset; + } + + @Override + public byte getFamilyLength() { + return familyLength; + } + + @Override + public byte[] getQualifierArray() { + return keyBuffer; + } + + @Override + public int getQualifierOffset() { + return qualifierOffset; + } + + @Override + public int getQualifierLength() { + return qualifierLength; + } + + @Override + public long getTimestamp() { + return timestamp; + } + + @Override + public byte getTypeByte() { + return typeByte; + } + + @Override + public long getMvccVersion() { + return memstoreTS; + } + + @Override + public byte[] getValueArray() { + return currentBuffer.array(); + } + + @Override + public int getValueOffset() { + return currentBuffer.arrayOffset() + valueOffset; + } + + @Override + public int getValueLength() { + return valueLength; + } + + @Override + public byte[] getTagsArray() { + if (tagCompressionContext != null) { + return tagsBuffer; + } + return currentBuffer.array(); + } + + @Override + public int getTagsOffset() { + if (tagCompressionContext != null) { + return 0; + } + return currentBuffer.arrayOffset() + tagsOffset; + } + + @Override + public short getTagsLength() { + return (short) tagsLength; + } + + @Override + @Deprecated + public byte[] getValue() { + // TODO Auto-generated method stub + return null; + } + + @Override + @Deprecated + public byte[] getFamily() { + // TODO Auto-generated method stub + return null; + } + + @Override + @Deprecated + public byte[] getQualifier() { + // TODO Auto-generated method stub + return null; + } + + @Override + @Deprecated + public byte[] getRow() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String toString() { + KeyValue kv = KeyValueUtil.copyToNewKeyValue(this); + if (kv == null) { + return "null"; + } + return kv.toString(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Cell)) { + return false; + } + return CellComparator.equals(this, (Cell) obj); + } + + @Override + public int hashCode() { + return CellComparator.hashCode(this); + } + + @Override + public int compareTo(Cell other) { + return CellComparator.compareStatic(this, other, true); } } @@ -208,7 +397,12 @@ abstract class BufferedDataBlockEncoder implements DataBlockEncoder { this.tagCompressionContext.clear(); } currentBuffer = buffer; + current.currentBuffer = currentBuffer; + if(tagCompressionContext != null) { + current.tagCompressionContext = tagCompressionContext; + } decodeFirst(); + current.extractOffsetsAndLengthsFromKey(current.keyBuffer); previous.invalidate(); } @@ -260,11 +454,13 @@ abstract class BufferedDataBlockEncoder implements DataBlockEncoder { @Override public KeyValue getKeyValue() { - ByteBuffer kvBuf = getKeyValueBuffer(); - KeyValue kv = new KeyValue(kvBuf.array(), kvBuf.arrayOffset(), kvBuf.array().length - - kvBuf.arrayOffset()); - kv.setMvccVersion(current.memstoreTS); - return kv; + // Internally there is a copy happening inside ensureKeyValue. + // TODO : Changing to cell everywhere in the read would be helping in + // using this directly without copying and finally convert to keyvalue + // just + // before returning to the client + KeyValue ensureKeyValue = KeyValueUtil.ensureKeyValue(current); + return ensureKeyValue; } @Override @@ -274,6 +470,7 @@ abstract class BufferedDataBlockEncoder implements DataBlockEncoder { tagCompressionContext.clear(); } decodeFirst(); + current.extractOffsetsAndLengthsFromKey(current.keyBuffer); previous.invalidate(); } @@ -283,6 +480,7 @@ abstract class BufferedDataBlockEncoder implements DataBlockEncoder { return false; } decodeNext(); + current.extractOffsetsAndLengthsFromKey(current.keyBuffer); previous.invalidate(); return true; } @@ -416,6 +614,7 @@ abstract class BufferedDataBlockEncoder implements DataBlockEncoder { if (currentBuffer.hasRemaining()) { previous.copyFromNext(current); decodeNext(); + current.extractOffsetsAndLengthsFromKey(current.keyBuffer); } else { break; }