HBASE-10771 Primitive type put/get APIs in ByteRange (Anoop)

This commit is contained in:
anoopsjohn 2014-06-15 16:22:11 +05:30
parent 63f0dffdba
commit 14c2c00296
7 changed files with 490 additions and 0 deletions

View File

@ -144,6 +144,34 @@ public interface ByteRange extends Comparable<ByteRange> {
*/
public byte get(int index);
/**
* Retrieve the short value at {@code index}
* @param index zero-based index into this range
* @return the short value at {@code index}
*/
public short getShort(int index);
/**
* Retrieve the int value at {@code index}
* @param index zero-based index into this range
* @return the int value at {@code index}
*/
public int getInt(int index);
/**
* Retrieve the long value at {@code index}
* @param index zero-based index into this range
* @return the long value at {@code index}
*/
public long getLong(int index);
/**
* Retrieve the long value at {@code index} which is stored as VLong
* @param index zero-based index into this range
* @return the long value at {@code index} which is stored as VLong
*/
public long getVLong(int index);
/**
* Fill {@code dst} with bytes from the range, starting from {@code index}.
* @param index zero-based index into this range.
@ -171,6 +199,38 @@ public interface ByteRange extends Comparable<ByteRange> {
*/
public ByteRange put(int index, byte val);
/**
* Store the short value at {@code index}
* @param index the index in the range where {@code val} is stored
* @param val the value to store
* @return this
*/
public ByteRange putShort(int index, short val);
/**
* Store the int value at {@code index}
* @param index the index in the range where {@code val} is stored
* @param val the value to store
* @return this
*/
public ByteRange putInt(int index, int val);
/**
* Store the long value at {@code index}
* @param index the index in the range where {@code val} is stored
* @param val the value to store
* @return this
*/
public ByteRange putLong(int index, long val);
/**
* Store the long value at {@code index} as a VLong
* @param index the index in the range where {@code val} is stored
* @param val the value to store
* @return number of bytes written
*/
public int putVLong(int index, long val);
/**
* Store {@code val} at {@code index}.
* @param index the index in the range where {@code val} is stored.

View File

@ -69,6 +69,27 @@ public interface PositionedByteRange extends ByteRange {
*/
public byte get();
/**
* Retrieve the next short value from this range.
*/
public short getShort();
/**
* Retrieve the next int value from this range.
*/
public int getInt();
/**
* Retrieve the next long value from this range.
*/
public long getLong();
/**
* Retrieve the next long value, which is stored as VLong, from this range
* @return the long value which is stored as VLong
*/
public long getVLong();
/**
* Fill {@code dst} with bytes from the range, starting from {@code position}.
* This range's {@code position} is incremented by the length of {@code dst},
@ -97,6 +118,34 @@ public interface PositionedByteRange extends ByteRange {
*/
public PositionedByteRange put(byte val);
/**
* Store short {@code val} at the next position in this range.
* @param val the new value.
* @return this.
*/
public PositionedByteRange putShort(short val);
/**
* Store int {@code val} at the next position in this range.
* @param val the new value.
* @return this.
*/
public PositionedByteRange putInt(int val);
/**
* Store long {@code val} at the next position in this range.
* @param val the new value.
* @return this.
*/
public PositionedByteRange putLong(long val);
/**
* Store the long {@code val} at the next position as a VLong
* @param val the value to store
* @return number of bytes written
*/
public int putVLong(long val);
/**
* Store the content of {@code val} in this range, starting at the next position.
* @param val the new value.
@ -144,6 +193,15 @@ public interface PositionedByteRange extends ByteRange {
@Override
public PositionedByteRange put(int index, byte val);
@Override
public PositionedByteRange putShort(int index, short val);
@Override
public PositionedByteRange putInt(int index, int val);
@Override
public PositionedByteRange putLong(int index, long val);
@Override
public PositionedByteRange put(int index, byte[] val);

View File

@ -180,6 +180,63 @@ public class SimpleByteRange implements ByteRange {
return bytes[offset + index];
}
@Override
public short getShort(int index) {
int offset = this.offset + index;
short n = 0;
n ^= bytes[offset] & 0xFF;
n <<= 8;
n ^= bytes[offset + 1] & 0xFF;
return n;
}
@Override
public int getInt(int index) {
int offset = this.offset + index;
int n = 0;
for (int i = offset; i < (offset + Bytes.SIZEOF_INT); i++) {
n <<= 8;
n ^= bytes[i] & 0xFF;
}
return n;
}
@Override
public long getLong(int index) {
int offset = this.offset + index;
long l = 0;
for (int i = offset; i < offset + Bytes.SIZEOF_LONG; i++) {
l <<= 8;
l ^= bytes[i] & 0xFF;
}
return l;
}
// Copied from com.google.protobuf.CodedInputStream
@Override
public long getVLong(int index) {
int shift = 0;
long result = 0;
while (shift < 64) {
final byte b = get(index++);
result |= (long) (b & 0x7F) << shift;
if ((b & 0x80) == 0) {
break;
}
shift += 7;
}
return result;
}
public static int getVLongSize(long val) {
int rPos = 0;
while ((val & ~0x7F) != 0) {
val >>>= 7;
rPos++;
}
return rPos + 1;
}
@Override
public ByteRange get(int index, byte[] dst) {
if (0 == dst.length) return this;
@ -196,9 +253,65 @@ public class SimpleByteRange implements ByteRange {
@Override
public ByteRange put(int index, byte val) {
bytes[offset + index] = val;
clearHashCache();
return this;
}
@Override
public ByteRange putShort(int index, short val) {
// This writing is same as BB's putShort. When byte[] is wrapped in a BB and call putShort(),
// one can get the same result.
bytes[offset + index + 1] = (byte) val;
val >>= 8;
bytes[offset + index] = (byte) val;
clearHashCache();
return this;
}
@Override
public ByteRange putInt(int index, int val) {
// This writing is same as BB's putInt. When byte[] is wrapped in a BB and call getInt(), one
// can get the same result.
for (int i = Bytes.SIZEOF_INT - 1; i > 0; i--) {
bytes[offset + index + i] = (byte) val;
val >>>= 8;
}
bytes[offset + index] = (byte) val;
clearHashCache();
return this;
}
@Override
public ByteRange putLong(int index, long val) {
// This writing is same as BB's putLong. When byte[] is wrapped in a BB and call putLong(), one
// can get the same result.
for (int i = Bytes.SIZEOF_LONG - 1; i > 0; i--) {
bytes[offset + index + i] = (byte) val;
val >>>= 8;
}
bytes[offset + index] = (byte) val;
clearHashCache();
return this;
}
// Copied from com.google.protobuf.CodedOutputStream
@Override
public int putVLong(int index, long val) {
int rPos = 0;
while (true) {
if ((val & ~0x7F) == 0) {
bytes[offset + index + rPos] = (byte) val;
break;
} else {
bytes[offset + index + rPos] = (byte) ((val & 0x7F) | 0x80);
val >>>= 7;
}
rPos++;
}
clearHashCache();
return rPos + 1;
}
@Override
public ByteRange put(int index, byte[] val) {
if (0 == val.length) return this;
@ -209,6 +322,7 @@ public class SimpleByteRange implements ByteRange {
public ByteRange put(int index, byte[] val, int offset, int length) {
if (0 == length) return this;
System.arraycopy(val, offset, this.bytes, this.offset + index, length);
clearHashCache();
return this;
}

View File

@ -18,6 +18,7 @@
package org.apache.hadoop.hbase.util;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.apache.hadoop.classification.InterfaceAudience;
@ -156,6 +157,34 @@ public class SimplePositionedByteRange extends SimpleByteRange implements Positi
@Override
public byte get() { return get(position++); }
@Override
public short getShort() {
short s = getShort(position);
position += Bytes.SIZEOF_SHORT;
return s;
}
@Override
public int getInt() {
int i = getInt(position);
position += Bytes.SIZEOF_INT;
return i;
}
@Override
public long getLong() {
long l = getLong(position);
position += Bytes.SIZEOF_LONG;
return l;
}
@Override
public long getVLong() {
long p = getVLong(position);
position += getVLongSize(p);
return p;
}
@Override
public PositionedByteRange get(byte[] dst) {
if (0 == dst.length) return this;
@ -176,6 +205,34 @@ public class SimplePositionedByteRange extends SimpleByteRange implements Positi
return this;
}
@Override
public PositionedByteRange putShort(short val) {
putShort(position, val);
position += Bytes.SIZEOF_SHORT;
return this;
}
@Override
public PositionedByteRange putInt(int val) {
putInt(position, val);
position += Bytes.SIZEOF_INT;
return this;
}
@Override
public PositionedByteRange putLong(long val) {
putLong(position, val);
position += Bytes.SIZEOF_LONG;
return this;
}
@Override
public int putVLong(long val) {
int len = putVLong(position, val);
position += len;
return len;
}
@Override
public PositionedByteRange put(byte[] val) {
if (0 == val.length) return this;
@ -228,6 +285,24 @@ public class SimplePositionedByteRange extends SimpleByteRange implements Positi
@Override
public PositionedByteRange put(int index, byte val) { super.put(index, val); return this; }
@Override
public PositionedByteRange putShort(int index, short val) {
super.putShort(index, val);
return this;
}
@Override
public PositionedByteRange putInt(int index, int val) {
super.putInt(index, val);
return this;
}
@Override
public PositionedByteRange putLong(int index, long val) {
super.putLong(index, val);
return this;
}
@Override
public PositionedByteRange put(int index, byte[] val) { super.put(index, val); return this; }

View File

@ -0,0 +1,89 @@
/**
* 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.util;
import java.util.ArrayList;
import java.util.List;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.SmallTests;
import org.apache.hadoop.hbase.Tag;
import org.junit.Assert;
import org.junit.Test;
import org.junit.experimental.categories.Category;
@Category(SmallTests.class)
public class TestByteRangeWithKVSerialization {
static void writeCell(PositionedByteRange pbr, KeyValue kv) throws Exception {
pbr.putInt(kv.getKeyLength());
pbr.putInt(kv.getValueLength());
pbr.put(kv.getBuffer(), kv.getKeyOffset(), kv.getKeyLength());
pbr.put(kv.getBuffer(), kv.getValueOffset(), kv.getValueLength());
pbr.putShort(kv.getTagsLength());
pbr.put(kv.getTagsArray(), kv.getTagsOffset(), kv.getTagsLength());
pbr.putVLong(kv.getMvccVersion());
}
static KeyValue readCell(PositionedByteRange pbr) throws Exception {
int kvStartPos = pbr.getPosition();
int keyLen = pbr.getInt();
int valLen = pbr.getInt();
pbr.setPosition(pbr.getPosition() + keyLen + valLen); // Skip the key and value section
short tagsLen = pbr.getShort();
pbr.setPosition(pbr.getPosition() + tagsLen); // Skip the tags section
long mvcc = pbr.getVLong();
KeyValue kv = new KeyValue(pbr.getBytes(), kvStartPos,
(int) KeyValue.getKeyValueDataStructureSize(keyLen, valLen, tagsLen));
kv.setMvccVersion(mvcc);
return kv;
}
@Test
public void testWritingAndReadingCells() throws Exception {
final byte[] FAMILY = Bytes.toBytes("f1");
final byte[] QUALIFIER = Bytes.toBytes("q1");
final byte[] VALUE = Bytes.toBytes("v");
int kvCount = 1000000;
List<KeyValue> kvs = new ArrayList<KeyValue>(kvCount);
int totalSize = 0;
Tag[] tags = new Tag[] { new Tag((byte) 1, "tag1") };
for (int i = 0; i < kvCount; i++) {
KeyValue kv = new KeyValue(Bytes.toBytes(i), FAMILY, QUALIFIER, i, VALUE, tags);
kv.setMvccVersion(i);
kvs.add(kv);
totalSize += kv.getLength() + Bytes.SIZEOF_LONG;
}
PositionedByteRange pbr = new SimplePositionedByteRange(totalSize);
for (KeyValue kv : kvs) {
writeCell(pbr, kv);
}
PositionedByteRange pbr1 = new SimplePositionedByteRange(pbr.getBytes(), 0, pbr.getPosition());
for (int i = 0; i < kvCount; i++) {
KeyValue kv = readCell(pbr1);
KeyValue kv1 = kvs.get(i);
Assert.assertTrue(kv.equals(kv1));
Assert.assertTrue(Bytes.equals(kv.getValueArray(), kv.getValueOffset(), kv.getValueLength(),
kv1.getValueArray(), kv1.getValueOffset(), kv1.getValueLength()));
Assert.assertTrue(Bytes.equals(kv.getTagsArray(), kv.getTagsOffset(), kv.getTagsLength(),
kv1.getTagsArray(), kv1.getTagsOffset(), kv1.getTagsLength()));
Assert.assertEquals(kv1.getMvccVersion(), kv.getMvccVersion());
}
}
}

View File

@ -17,6 +17,8 @@
*/
package org.apache.hadoop.hbase.util;
import java.nio.ByteBuffer;
import org.apache.hadoop.hbase.SmallTests;
import org.junit.Assert;
import org.junit.Test;
@ -65,4 +67,55 @@ public class TestPositionedByteRange {
// set position to the end of the range; this should not throw.
r.setPosition(3);
}
@Test
public void testPutAndGetPrimitiveTypes() throws Exception {
PositionedByteRange pbr = new SimplePositionedByteRange(100);
int i1 = 18, i2 = 2;
short s1 = 0;
long l1 = 1234L;
pbr.putInt(i1);
pbr.putInt(i2);
pbr.putShort(s1);
pbr.putLong(l1);
pbr.putVLong(0);
pbr.putVLong(l1);
pbr.putVLong(Long.MAX_VALUE);
pbr.putVLong(Long.MIN_VALUE);
// rewind
pbr.setPosition(0);
Assert.assertEquals(i1, pbr.getInt());
Assert.assertEquals(i2, pbr.getInt());
Assert.assertEquals(s1, pbr.getShort());
Assert.assertEquals(l1, pbr.getLong());
Assert.assertEquals(0, pbr.getVLong());
Assert.assertEquals(l1, pbr.getVLong());
Assert.assertEquals(Long.MAX_VALUE, pbr.getVLong());
Assert.assertEquals(Long.MIN_VALUE, pbr.getVLong());
}
@Test
public void testPutGetAPIsCompareWithBBAPIs() throws Exception {
// confirm that the long/int/short writing is same as BBs
PositionedByteRange pbr = new SimplePositionedByteRange(100);
int i1 = -234, i2 = 2;
short s1 = 0;
long l1 = 1234L;
pbr.putInt(i1);
pbr.putShort(s1);
pbr.putInt(i2);
pbr.putLong(l1);
// rewind
pbr.setPosition(0);
Assert.assertEquals(i1, pbr.getInt());
Assert.assertEquals(s1, pbr.getShort());
Assert.assertEquals(i2, pbr.getInt());
Assert.assertEquals(l1, pbr.getLong());
// Read back using BB APIs
ByteBuffer bb = ByteBuffer.wrap(pbr.getBytes());
Assert.assertEquals(i1, bb.getInt());
Assert.assertEquals(s1, bb.getShort());
Assert.assertEquals(i2, bb.getInt());
Assert.assertEquals(l1, bb.getLong());
}
}

View File

@ -68,4 +68,45 @@ public class TestSimpleByteRange {
r.setLength(2);//verify we retained the 2nd byte, but dangerous in real code
Assert.assertTrue(Bytes.equals(new byte[]{1, 3}, r.deepCopyToNewArray()));
}
@Test
public void testPutandGetPrimitiveTypes() throws Exception {
ByteRange r = new SimpleByteRange(100);
int offset = 0;
int i1 = 18, i2 = 2;
short s1 = 0;
long l1 = 1234L, l2 = 0;
r.putInt(offset, i1);
offset += Bytes.SIZEOF_INT;
r.putInt(offset, i2);
offset += Bytes.SIZEOF_INT;
r.putShort(offset, s1);
offset += Bytes.SIZEOF_SHORT;
r.putLong(offset, l1);
offset += Bytes.SIZEOF_LONG;
int len = r.putVLong(offset, l1);
offset += len;
len = r.putVLong(offset, l2);
offset += len;
len = r.putVLong(offset, Long.MAX_VALUE);
offset += len;
len = r.putVLong(offset, Long.MIN_VALUE);
offset = 0;
Assert.assertEquals(i1, r.getInt(offset));
offset += Bytes.SIZEOF_INT;
Assert.assertEquals(i2, r.getInt(offset));
offset += Bytes.SIZEOF_INT;
Assert.assertEquals(s1, r.getShort(offset));
offset += Bytes.SIZEOF_SHORT;
Assert.assertEquals(l1, r.getLong(offset));
offset += Bytes.SIZEOF_LONG;
Assert.assertEquals(l1, r.getVLong(offset));
offset += SimpleByteRange.getVLongSize(l1);
Assert.assertEquals(l2, r.getVLong(offset));
offset += SimpleByteRange.getVLongSize(l2);
Assert.assertEquals(Long.MAX_VALUE, r.getVLong(offset));
offset += SimpleByteRange.getVLongSize(Long.MAX_VALUE);
Assert.assertEquals(Long.MIN_VALUE, r.getVLong(offset));
}
}