Index: hbase-common/src/main/java/org/apache/hadoop/hbase/util/ByteRange.java =================================================================== --- hbase-common/src/main/java/org/apache/hadoop/hbase/util/ByteRange.java (revision 1581257) +++ hbase-common/src/main/java/org/apache/hadoop/hbase/util/ByteRange.java (working copy) @@ -18,6 +18,8 @@ package org.apache.hadoop.hbase.util; +import java.io.IOException; + import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceStability; @@ -67,6 +69,11 @@ public byte[] getBytes(); /** + * Tells whether or not this ByteRange is backed by an accessible byte array. + */ + public boolean hasBytes(); + + /** * Nullifies this ByteRange. That is, it becomes a husk, being a range over * no byte[] whatsoever. * @return this @@ -145,6 +152,35 @@ 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 A pair of long value and the number of bytes taken by it for storage + * @throws IOException + */ + public Pair getVLong(int index) throws IOException; + + /** * Fill {@code dst} with bytes from the range, starting from {@code index}. * @param index zero-based index into this range. * @param dst the destination of the copy. @@ -172,6 +208,38 @@ 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. * @param val the value to store. @@ -192,6 +260,25 @@ public ByteRange put(int index, byte[] val, int offset, int length); /** + * Store {@code val} 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 put(int index, ByteRange val); + + /** + * Store the {@code offset} to {@code length} bytes of {@code val} into this range, starting at + * {@code index}. + * @param index position in this range to start the copy. + * @param val the value to store. + * @param offset the offset in {@code val} from which to start copying. + * @param length the number of bytes to copy from {@code val}. + * @return this. + */ + public ByteRange put(int index, ByteRange val, int offset, int length); + + /** * Instantiate a new byte[] with exact length, which is at least 24 bytes + * length. Copy the contents of this range into it. * @return The newly cloned byte[]. Index: hbase-common/src/main/java/org/apache/hadoop/hbase/util/PositionedByteRange.java =================================================================== --- hbase-common/src/main/java/org/apache/hadoop/hbase/util/PositionedByteRange.java (revision 1581257) +++ hbase-common/src/main/java/org/apache/hadoop/hbase/util/PositionedByteRange.java (working copy) @@ -18,6 +18,7 @@ package org.apache.hadoop.hbase.util; +import java.io.IOException; import java.nio.ByteBuffer; import org.apache.hadoop.classification.InterfaceAudience; @@ -70,6 +71,28 @@ 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 A pair of long value and the number of bytes taken by it for storage + * @throws IOException + */ + public Pair getVLong() throws IOException; + + /** * 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}, * the number of bytes copied. @@ -98,6 +121,34 @@ 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. * @return this. @@ -115,6 +166,23 @@ */ public PositionedByteRange put(byte[] val, int offset, int length); + /** + * Store the content of {@code val} in this range, starting at the next position + * @param val the value to store. + * @return this. + */ + public PositionedByteRange put(ByteRange val); + + /** + * Store the {@code offset} to {@code length} bytes of {@code val} into this range, starting at + * {@code index}. + * @param val the value to store. + * @param offset the offset in {@code val} from which to start copying. + * @param length the number of bytes to copy from {@code val}. + * @return this. + */ + public PositionedByteRange put(ByteRange val, int offset, int length); + // override parent interface declarations to return this interface. @Override @@ -145,6 +213,15 @@ 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); @Override Index: hbase-common/src/main/java/org/apache/hadoop/hbase/util/SimpleByteRange.java =================================================================== --- hbase-common/src/main/java/org/apache/hadoop/hbase/util/SimpleByteRange.java (revision 1581257) +++ hbase-common/src/main/java/org/apache/hadoop/hbase/util/SimpleByteRange.java (working copy) @@ -18,6 +18,8 @@ package org.apache.hadoop.hbase.util; +import java.io.IOException; + import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceStability; @@ -102,6 +104,11 @@ } @Override + public boolean hasBytes() { + return false; + } + + @Override public ByteRange unset() { clearHashCache(); this.bytes = null; @@ -181,6 +188,39 @@ } @Override + public short getShort(int index) { + return Bytes.toShort(bytes, index); + } + + @Override + public int getInt(int index) { + return Bytes.toInt(bytes, index); + } + + @Override + public long getLong(int index) { + return Bytes.toLong(bytes, index); + } + + // Copied from com.google.protobuf.CodedInputStream + @Override + public Pair getVLong(int index) throws IOException { + int shift = 0; + long result = 0; + int len = 1; + while (shift < 64) { + final byte b = get(index++); + result |= (long) (b & 0x7F) << shift; + if ((b & 0x80) == 0) { + return new Pair(result, len); + } + shift += 7; + len++; + } + throw new IOException("Malformed VLong"); + } + + @Override public ByteRange get(int index, byte[] dst) { if (0 == dst.length) return this; return get(index, dst, 0, dst.length); @@ -196,10 +236,60 @@ @Override public ByteRange put(int index, byte val) { bytes[offset + index] = val; + clearHashCache(); return this; } @Override + public ByteRange putShort(int index, short val) { + bytes[offset + index + 1] = (byte) val; + val >>= 8; + bytes[offset + index] = (byte) val; + clearHashCache(); + return this; + } + + @Override + public ByteRange putInt(int index, int val) { + 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) { + 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; return put(index, val, 0, val.length); @@ -209,9 +299,30 @@ 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; } + @Override + public ByteRange put(int index, ByteRange val) { + return put(index, val, 0, val.getLength()); + } + + @Override + public ByteRange put(int index, ByteRange val, int offset, int length) { + if (0 == length) return this; + if (val.hasBytes()) { + System.arraycopy(val.getBytes(), val.getOffset() + offset, this.bytes, this.offset + index, + length); + } else { + for (int i = 0; i < length; i++) { + this.bytes[this.offset + index + i] = val.get(offset + i); + } + } + clearHashCache(); + return this; + } + // // methods for duplicating the current instance // Index: hbase-common/src/main/java/org/apache/hadoop/hbase/util/SimplePositionedByteRange.java =================================================================== --- hbase-common/src/main/java/org/apache/hadoop/hbase/util/SimplePositionedByteRange.java (revision 1581257) +++ hbase-common/src/main/java/org/apache/hadoop/hbase/util/SimplePositionedByteRange.java (working copy) @@ -18,6 +18,7 @@ package org.apache.hadoop.hbase.util; +import java.io.IOException; import java.nio.ByteBuffer; import org.apache.hadoop.classification.InterfaceAudience; @@ -157,6 +158,34 @@ 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 Pair getVLong() throws IOException { + Pair p = getVLong(position); + position += p.getSecond(); + return p; + } + + @Override public PositionedByteRange get(byte[] dst) { if (0 == dst.length) return this; return this.get(dst, 0, dst.length); // be clear we're calling self, not super @@ -177,6 +206,34 @@ } @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; return this.put(val, 0, val.length); @@ -190,6 +247,19 @@ return this; } + @Override + public PositionedByteRange put(ByteRange val) { + return put(val, 0, val.getLength()); + } + + @Override + public PositionedByteRange put(ByteRange val, int offset, int length) { + if (0 == length) return this; + super.put(position, val, offset, length); + this.position += length; + return this; + } + /** * Similar to {@link ByteBuffer#flip()}. Sets length to position, position * to offset. @@ -229,6 +299,24 @@ 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; } @Override Index: hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestPositionedByteRange.java =================================================================== --- hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestPositionedByteRange.java (revision 1581257) +++ hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestPositionedByteRange.java (working copy) @@ -65,4 +65,51 @@ // 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().getFirst().longValue()); + Assert.assertEquals(l1, pbr.getVLong().getFirst().longValue()); + Assert.assertEquals(Long.MAX_VALUE, pbr.getVLong().getFirst().longValue()); + Assert.assertEquals(Long.MIN_VALUE, pbr.getVLong().getFirst().longValue()); + } + + @Test + public void testPutByteRange() { + PositionedByteRange pbr1 = new SimplePositionedByteRange(100); + int i1 = 18, i2 = 2; + long l1 = 1234L; + pbr1.putInt(i1); + pbr1.putInt(i2); + pbr1.putLong(l1); + byte[] bb = new byte[110]; + int offset = 10; + System.arraycopy(pbr1.getBytes(), pbr1.getOffset(), bb, offset, pbr1.getLength()); + PositionedByteRange src = new SimplePositionedByteRange(bb, offset, pbr1.getLength()); + PositionedByteRange pbr2 = new SimplePositionedByteRange(100); + pbr2.put(src); + // rewind pbr2 + pbr2.setPosition(0); + Assert.assertEquals(i1, pbr2.getInt()); + Assert.assertEquals(i2, pbr2.getInt()); + Assert.assertEquals(l1, pbr2.getLong()); + } } Index: hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestSimpleByteRange.java =================================================================== --- hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestSimpleByteRange.java (revision 1581257) +++ hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestSimpleByteRange.java (working copy) @@ -68,4 +68,49 @@ 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; + Pair p = r.getVLong(offset); + Assert.assertEquals(l1, p.getFirst().longValue()); + offset += p.getSecond(); + p = r.getVLong(offset); + Assert.assertEquals(l2, p.getFirst().longValue()); + offset += p.getSecond(); + p = r.getVLong(offset); + Assert.assertEquals(Long.MAX_VALUE, p.getFirst().longValue()); + offset += p.getSecond(); + p = r.getVLong(offset); + Assert.assertEquals(Long.MIN_VALUE, p.getFirst().longValue()); + } }