HBASE-20716: Changes the bytes[] conversion done in Bytes and ByteBufferUtils. Instead of doing check unsafe_aligned available everytime, choose the best converter at startup.

This commit is contained in:
Sahil Aggarwal 2018-10-09 22:41:36 +05:30 committed by Michael Stack
parent c744dd84cc
commit b972b9a2d9
No known key found for this signature in database
GPG Key ID: 9816C7FC8ACC93D2
3 changed files with 439 additions and 196 deletions

View File

@ -34,7 +34,6 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.FilterProtos;
import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.BytesBytesPair; import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.BytesBytesPair;
import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.Pair; import org.apache.hadoop.hbase.util.Pair;
import org.apache.hadoop.hbase.util.UnsafeAccess;
import org.apache.hadoop.hbase.util.UnsafeAvailChecker; import org.apache.hadoop.hbase.util.UnsafeAvailChecker;
import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting; import org.apache.hbase.thirdparty.com.google.common.annotations.VisibleForTesting;
@ -351,9 +350,9 @@ public class FuzzyRowFilter extends FilterBase {
int j = numWords << 3; // numWords * SIZEOF_LONG; int j = numWords << 3; // numWords * SIZEOF_LONG;
for (int i = 0; i < j; i += Bytes.SIZEOF_LONG) { for (int i = 0; i < j; i += Bytes.SIZEOF_LONG) {
long fuzzyBytes = UnsafeAccess.toLong(fuzzyKeyBytes, i); long fuzzyBytes = Bytes.toLong(fuzzyKeyBytes, i);
long fuzzyMeta = UnsafeAccess.toLong(fuzzyKeyMeta, i); long fuzzyMeta = Bytes.toLong(fuzzyKeyMeta, i);
long rowValue = UnsafeAccess.toLong(row, offset + i); long rowValue = Bytes.toLong(row, offset + i);
if ((rowValue & fuzzyMeta) != (fuzzyBytes)) { if ((rowValue & fuzzyMeta) != (fuzzyBytes)) {
// We always return NEXT_EXISTS // We always return NEXT_EXISTS
return SatisfiesCode.NEXT_EXISTS; return SatisfiesCode.NEXT_EXISTS;
@ -363,9 +362,9 @@ public class FuzzyRowFilter extends FilterBase {
int off = j; int off = j;
if (length - off >= Bytes.SIZEOF_INT) { if (length - off >= Bytes.SIZEOF_INT) {
int fuzzyBytes = UnsafeAccess.toInt(fuzzyKeyBytes, off); int fuzzyBytes = Bytes.toInt(fuzzyKeyBytes, off);
int fuzzyMeta = UnsafeAccess.toInt(fuzzyKeyMeta, off); int fuzzyMeta = Bytes.toInt(fuzzyKeyMeta, off);
int rowValue = UnsafeAccess.toInt(row, offset + off); int rowValue = Bytes.toInt(row, offset + off);
if ((rowValue & fuzzyMeta) != (fuzzyBytes)) { if ((rowValue & fuzzyMeta) != (fuzzyBytes)) {
// We always return NEXT_EXISTS // We always return NEXT_EXISTS
return SatisfiesCode.NEXT_EXISTS; return SatisfiesCode.NEXT_EXISTS;
@ -374,9 +373,9 @@ public class FuzzyRowFilter extends FilterBase {
} }
if (length - off >= Bytes.SIZEOF_SHORT) { if (length - off >= Bytes.SIZEOF_SHORT) {
short fuzzyBytes = UnsafeAccess.toShort(fuzzyKeyBytes, off); short fuzzyBytes = Bytes.toShort(fuzzyKeyBytes, off);
short fuzzyMeta = UnsafeAccess.toShort(fuzzyKeyMeta, off); short fuzzyMeta = Bytes.toShort(fuzzyKeyMeta, off);
short rowValue = UnsafeAccess.toShort(row, offset + off); short rowValue = Bytes.toShort(row, offset + off);
if ((rowValue & fuzzyMeta) != (fuzzyBytes)) { if ((rowValue & fuzzyMeta) != (fuzzyBytes)) {
// We always return NEXT_EXISTS // We always return NEXT_EXISTS
// even if it does not (in this case getNextForFuzzyRule // even if it does not (in this case getNextForFuzzyRule

View File

@ -55,7 +55,267 @@ public final class ByteBufferUtils {
private ByteBufferUtils() { private ByteBufferUtils() {
} }
/**
static abstract class Comparer {
abstract int compareTo(byte [] buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2);
abstract int compareTo(ByteBuffer buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2);
}
static abstract class Converter {
abstract short toShort(ByteBuffer buffer, int offset);
abstract int toInt(ByteBuffer buffer);
abstract int toInt(ByteBuffer buffer, int offset);
abstract long toLong(ByteBuffer buffer, int offset);
abstract void putInt(ByteBuffer buffer, int val);
abstract int putInt(ByteBuffer buffer, int index, int val);
abstract void putShort(ByteBuffer buffer, short val);
abstract int putShort(ByteBuffer buffer, int index, short val);
abstract void putLong(ByteBuffer buffer, long val);
abstract int putLong(ByteBuffer buffer, int index, long val);
}
static class ComparerHolder {
static final String UNSAFE_COMPARER_NAME = ComparerHolder.class.getName() + "$UnsafeComparer";
static final Comparer BEST_COMPARER = getBestComparer();
static Comparer getBestComparer() {
try {
Class<?> theClass = Class.forName(UNSAFE_COMPARER_NAME);
@SuppressWarnings("unchecked")
Comparer comparer = (Comparer) theClass.getConstructor().newInstance();
return comparer;
} catch (Throwable t) { // ensure we really catch *everything*
return PureJavaComparer.INSTANCE;
}
}
static final class PureJavaComparer extends Comparer {
static final PureJavaComparer INSTANCE = new PureJavaComparer();
private PureJavaComparer() {}
@Override
public int compareTo(byte [] buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) {
int end1 = o1 + l1;
int end2 = o2 + l2;
for (int i = o1, j = o2; i < end1 && j < end2; i++, j++) {
int a = buf1[i] & 0xFF;
int b = buf2.get(j) & 0xFF;
if (a != b) {
return a - b;
}
}
return l1 - l2;
}
@Override
public int compareTo(ByteBuffer buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) {
int end1 = o1 + l1;
int end2 = o2 + l2;
for (int i = o1, j = o2; i < end1 && j < end2; i++, j++) {
int a = buf1.get(i) & 0xFF;
int b = buf2.get(j) & 0xFF;
if (a != b) {
return a - b;
}
}
return l1 - l2;
}
}
static final class UnsafeComparer extends Comparer {
public UnsafeComparer() {}
static {
if(!UNSAFE_UNALIGNED) {
throw new Error();
}
}
@Override
public int compareTo(byte[] buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) {
long offset2Adj;
Object refObj2 = null;
if (buf2.isDirect()) {
offset2Adj = o2 + ((DirectBuffer)buf2).address();
} else {
offset2Adj = o2 + buf2.arrayOffset() + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
refObj2 = buf2.array();
}
return compareToUnsafe(buf1, o1 + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET, l1,
refObj2, offset2Adj, l2);
}
@Override
public int compareTo(ByteBuffer buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) {
long offset1Adj, offset2Adj;
Object refObj1 = null, refObj2 = null;
if (buf1.isDirect()) {
offset1Adj = o1 + ((DirectBuffer) buf1).address();
} else {
offset1Adj = o1 + buf1.arrayOffset() + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
refObj1 = buf1.array();
}
if (buf2.isDirect()) {
offset2Adj = o2 + ((DirectBuffer) buf2).address();
} else {
offset2Adj = o2 + buf2.arrayOffset() + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
refObj2 = buf2.array();
}
return compareToUnsafe(refObj1, offset1Adj, l1, refObj2, offset2Adj, l2);
}
}
}
static class ConverterHolder {
static final String UNSAFE_CONVERTER_NAME =
ConverterHolder.class.getName() + "$UnsafeConverter";
static final Converter BEST_CONVERTER = getBestConverter();
static Converter getBestConverter() {
try {
Class<?> theClass = Class.forName(UNSAFE_CONVERTER_NAME);
// yes, UnsafeComparer does implement Comparer<byte[]>
@SuppressWarnings("unchecked")
Converter converter = (Converter) theClass.getConstructor().newInstance();
return converter;
} catch (Throwable t) { // ensure we really catch *everything*
return PureJavaConverter.INSTANCE;
}
}
static final class PureJavaConverter extends Converter {
static final PureJavaConverter INSTANCE = new PureJavaConverter();
private PureJavaConverter() {}
@Override
short toShort(ByteBuffer buffer, int offset) {
return buffer.getShort(offset);
}
@Override
int toInt(ByteBuffer buffer) {
return buffer.getInt();
}
@Override
int toInt(ByteBuffer buffer, int offset) {
return buffer.getInt(offset);
}
@Override
long toLong(ByteBuffer buffer, int offset) {
return buffer.getLong(offset);
}
@Override
void putInt(ByteBuffer buffer, int val) {
buffer.putInt(val);
}
@Override
int putInt(ByteBuffer buffer, int index, int val) {
buffer.putInt(index, val);
return index + Bytes.SIZEOF_INT;
}
@Override
void putShort(ByteBuffer buffer, short val) {
buffer.putShort(val);
}
@Override
int putShort(ByteBuffer buffer, int index, short val) {
buffer.putShort(index, val);
return index + Bytes.SIZEOF_SHORT;
}
@Override
void putLong(ByteBuffer buffer, long val) {
buffer.putLong(val);
}
@Override
int putLong(ByteBuffer buffer, int index, long val) {
buffer.putLong(index, val);
return index + Bytes.SIZEOF_LONG;
}
}
static final class UnsafeConverter extends Converter {
public UnsafeConverter() {}
static {
if(!UNSAFE_UNALIGNED) {
throw new Error();
}
}
@Override
short toShort(ByteBuffer buffer, int offset) {
return UnsafeAccess.toShort(buffer, offset);
}
@Override
int toInt(ByteBuffer buffer) {
int i = UnsafeAccess.toInt(buffer, buffer.position());
buffer.position(buffer.position() + Bytes.SIZEOF_INT);
return i;
}
@Override
int toInt(ByteBuffer buffer, int offset) {
return UnsafeAccess.toInt(buffer, offset);
}
@Override
long toLong(ByteBuffer buffer, int offset) {
return UnsafeAccess.toLong(buffer, offset);
}
@Override
void putInt(ByteBuffer buffer, int val) {
int newPos = UnsafeAccess.putInt(buffer, buffer.position(), val);
buffer.position(newPos);
}
@Override
int putInt(ByteBuffer buffer, int index, int val) {
return UnsafeAccess.putInt(buffer, index, val);
}
@Override
void putShort(ByteBuffer buffer, short val) {
int newPos = UnsafeAccess.putShort(buffer, buffer.position(), val);
buffer.position(newPos);
}
@Override
int putShort(ByteBuffer buffer, int index, short val) {
return UnsafeAccess.putShort(buffer, index, val);
}
@Override
void putLong(ByteBuffer buffer, long val) {
int newPos = UnsafeAccess.putLong(buffer, buffer.position(), val);
buffer.position(newPos);
}
@Override
int putLong(ByteBuffer buffer, int index, long val) {
return UnsafeAccess.putLong(buffer, index, val);
}
}
}
/**
* Similar to {@link WritableUtils#writeVLong(java.io.DataOutput, long)}, * Similar to {@link WritableUtils#writeVLong(java.io.DataOutput, long)},
* but writes to a {@link ByteBuffer}. * but writes to a {@link ByteBuffer}.
*/ */
@ -629,35 +889,7 @@ public final class ByteBufferUtils {
} }
public static int compareTo(ByteBuffer buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) { public static int compareTo(ByteBuffer buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) {
// NOTE: This method is copied over in BBKVComparator!!!!! For perf reasons. If you make return ComparerHolder.BEST_COMPARER.compareTo(buf1, o1, l1, buf2, o2, l2);
// changes here, make them there too!!!!
if (UNSAFE_UNALIGNED) {
long offset1Adj, offset2Adj;
Object refObj1 = null, refObj2 = null;
if (buf1.isDirect()) {
offset1Adj = o1 + ((DirectBuffer) buf1).address();
} else {
offset1Adj = o1 + buf1.arrayOffset() + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
refObj1 = buf1.array();
}
if (buf2.isDirect()) {
offset2Adj = o2 + ((DirectBuffer) buf2).address();
} else {
offset2Adj = o2 + buf2.arrayOffset() + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
refObj2 = buf2.array();
}
return compareToUnsafe(refObj1, offset1Adj, l1, refObj2, offset2Adj, l2);
}
int end1 = o1 + l1;
int end2 = o2 + l2;
for (int i = o1, j = o2; i < end1 && j < end2; i++, j++) {
int a = buf1.get(i) & 0xFF;
int b = buf2.get(j) & 0xFF;
if (a != b) {
return a - b;
}
}
return l1 - l2;
} }
public static boolean equals(ByteBuffer buf1, int o1, int l1, byte[] buf2, int o2, int l2) { public static boolean equals(ByteBuffer buf1, int o1, int l1, byte[] buf2, int o2, int l2) {
@ -678,53 +910,11 @@ public final class ByteBufferUtils {
// of compiled code via jitwatch). // of compiled code via jitwatch).
public static int compareTo(byte [] buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) { public static int compareTo(byte [] buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) {
if (UNSAFE_UNALIGNED) { return ComparerHolder.BEST_COMPARER.compareTo(buf1, o1, l1, buf2, o2, l2);
long offset2Adj;
Object refObj2 = null;
if (buf2.isDirect()) {
offset2Adj = o2 + ((DirectBuffer)buf2).address();
} else {
offset2Adj = o2 + buf2.arrayOffset() + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
refObj2 = buf2.array();
}
return compareToUnsafe(buf1, o1 + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET, l1,
refObj2, offset2Adj, l2);
}
int end1 = o1 + l1;
int end2 = o2 + l2;
for (int i = o1, j = o2; i < end1 && j < end2; i++, j++) {
int a = buf1[i] & 0xFF;
int b = buf2.get(j) & 0xFF;
if (a != b) {
return a - b;
}
}
return l1 - l2;
} }
public static int compareTo(ByteBuffer buf1, int o1, int l1, byte[] buf2, int o2, int l2) { public static int compareTo(ByteBuffer buf1, int o1, int l1, byte[] buf2, int o2, int l2) {
if (UNSAFE_UNALIGNED) { return compareTo(buf2, o2, l2, buf1, o1, l1)*-1;
long offset1Adj;
Object refObj1 = null;
if (buf1.isDirect()) {
offset1Adj = o1 + ((DirectBuffer) buf1).address();
} else {
offset1Adj = o1 + buf1.arrayOffset() + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
refObj1 = buf1.array();
}
return compareToUnsafe(refObj1, offset1Adj, l1,
buf2, o2 + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET, l2);
}
int end1 = o1 + l1;
int end2 = o2 + l2;
for (int i = o1, j = o2; i < end1 && j < end2; i++, j++) {
int a = buf1.get(i) & 0xFF;
int b = buf2[j] & 0xFF;
if (a != b) {
return a - b;
}
}
return l1 - l2;
} }
static int compareToUnsafe(Object obj1, long o1, int l1, Object obj2, long o2, int l2) { static int compareToUnsafe(Object obj1, long o1, int l1, Object obj2, long o2, int l2) {
@ -777,24 +967,14 @@ public final class ByteBufferUtils {
* @return short value at offset * @return short value at offset
*/ */
public static short toShort(ByteBuffer buffer, int offset) { public static short toShort(ByteBuffer buffer, int offset) {
if (UNSAFE_UNALIGNED) { return ConverterHolder.BEST_CONVERTER.toShort(buffer, offset);
return UnsafeAccess.toShort(buffer, offset);
} else {
return buffer.getShort(offset);
}
} }
/** /**
* Reads an int value at the given buffer's current position. Also advances the buffer's position * Reads an int value at the given buffer's current position. Also advances the buffer's position
*/ */
public static int toInt(ByteBuffer buffer) { public static int toInt(ByteBuffer buffer) {
if (UNSAFE_UNALIGNED) { return ConverterHolder.BEST_CONVERTER.toInt(buffer);
int i = UnsafeAccess.toInt(buffer, buffer.position());
buffer.position(buffer.position() + Bytes.SIZEOF_INT);
return i;
} else {
return buffer.getInt();
}
} }
/** /**
@ -804,11 +984,7 @@ public final class ByteBufferUtils {
* @return int value at offset * @return int value at offset
*/ */
public static int toInt(ByteBuffer buffer, int offset) { public static int toInt(ByteBuffer buffer, int offset) {
if (UNSAFE_UNALIGNED) { return ConverterHolder.BEST_CONVERTER.toInt(buffer, offset);
return UnsafeAccess.toInt(buffer, offset);
} else {
return buffer.getInt(offset);
}
} }
/** /**
@ -841,11 +1017,7 @@ public final class ByteBufferUtils {
* @return long value at offset * @return long value at offset
*/ */
public static long toLong(ByteBuffer buffer, int offset) { public static long toLong(ByteBuffer buffer, int offset) {
if (UNSAFE_UNALIGNED) { return ConverterHolder.BEST_CONVERTER.toLong(buffer, offset);
return UnsafeAccess.toLong(buffer, offset);
} else {
return buffer.getLong(offset);
}
} }
/** /**
@ -855,20 +1027,11 @@ public final class ByteBufferUtils {
* @param val int to write out * @param val int to write out
*/ */
public static void putInt(ByteBuffer buffer, int val) { public static void putInt(ByteBuffer buffer, int val) {
if (UNSAFE_UNALIGNED) { ConverterHolder.BEST_CONVERTER.putInt(buffer, val);
int newPos = UnsafeAccess.putInt(buffer, buffer.position(), val);
buffer.position(newPos);
} else {
buffer.putInt(val);
}
} }
public static int putInt(ByteBuffer buffer, int index, int val) { public static int putInt(ByteBuffer buffer, int index, int val) {
if (UNSAFE_UNALIGNED) { return ConverterHolder.BEST_CONVERTER.putInt(buffer, index, val);
return UnsafeAccess.putInt(buffer, index, val);
}
buffer.putInt(index, val);
return index + Bytes.SIZEOF_INT;
} }
/** /**
@ -906,20 +1069,11 @@ public final class ByteBufferUtils {
* @param val short to write out * @param val short to write out
*/ */
public static void putShort(ByteBuffer buffer, short val) { public static void putShort(ByteBuffer buffer, short val) {
if (UNSAFE_UNALIGNED) { ConverterHolder.BEST_CONVERTER.putShort(buffer, val);
int newPos = UnsafeAccess.putShort(buffer, buffer.position(), val);
buffer.position(newPos);
} else {
buffer.putShort(val);
}
} }
public static int putShort(ByteBuffer buffer, int index, short val) { public static int putShort(ByteBuffer buffer, int index, short val) {
if (UNSAFE_UNALIGNED) { return ConverterHolder.BEST_CONVERTER.putShort(buffer, index, val);
return UnsafeAccess.putShort(buffer, index, val);
}
buffer.putShort(index, val);
return index + Bytes.SIZEOF_SHORT;
} }
public static int putAsShort(ByteBuffer buf, int index, int val) { public static int putAsShort(ByteBuffer buf, int index, int val) {
@ -936,20 +1090,11 @@ public final class ByteBufferUtils {
* @param val long to write out * @param val long to write out
*/ */
public static void putLong(ByteBuffer buffer, long val) { public static void putLong(ByteBuffer buffer, long val) {
if (UNSAFE_UNALIGNED) { ConverterHolder.BEST_CONVERTER.putLong(buffer, val);
int newPos = UnsafeAccess.putLong(buffer, buffer.position(), val);
buffer.position(newPos);
} else {
buffer.putLong(val);
}
} }
public static int putLong(ByteBuffer buffer, int index, long val) { public static int putLong(ByteBuffer buffer, int index, long val) {
if (UNSAFE_UNALIGNED) { return ConverterHolder.BEST_CONVERTER.putLong(buffer, index, val);
return UnsafeAccess.putLong(buffer, index, val);
}
buffer.putLong(index, val);
return index + Bytes.SIZEOF_LONG;
} }
/** /**

View File

@ -812,16 +812,7 @@ public class Bytes implements Comparable<Bytes> {
if (length != SIZEOF_LONG || offset + length > bytes.length) { if (length != SIZEOF_LONG || offset + length > bytes.length) {
throw explainWrongLengthOrOffset(bytes, offset, length, SIZEOF_LONG); throw explainWrongLengthOrOffset(bytes, offset, length, SIZEOF_LONG);
} }
if (UNSAFE_UNALIGNED) { return ConverterHolder.BEST_CONVERTER.toLong(bytes, offset, length);
return UnsafeAccess.toLong(bytes, offset);
} else {
long l = 0;
for(int i = offset; i < offset + length; i++) {
l <<= 8;
l ^= bytes[i] & 0xFF;
}
return l;
}
} }
private static IllegalArgumentException private static IllegalArgumentException
@ -853,16 +844,7 @@ public class Bytes implements Comparable<Bytes> {
throw new IllegalArgumentException("Not enough room to put a long at" throw new IllegalArgumentException("Not enough room to put a long at"
+ " offset " + offset + " in a " + bytes.length + " byte array"); + " offset " + offset + " in a " + bytes.length + " byte array");
} }
if (UNSAFE_UNALIGNED) { return ConverterHolder.BEST_CONVERTER.putLong(bytes, offset, val);
return UnsafeAccess.putLong(bytes, offset, val);
} else {
for(int i = offset + 7; i > offset; i--) {
bytes[i] = (byte) val;
val >>>= 8;
}
bytes[offset] = (byte) val;
return offset + SIZEOF_LONG;
}
} }
/** /**
@ -1004,16 +986,7 @@ public class Bytes implements Comparable<Bytes> {
if (length != SIZEOF_INT || offset + length > bytes.length) { if (length != SIZEOF_INT || offset + length > bytes.length) {
throw explainWrongLengthOrOffset(bytes, offset, length, SIZEOF_INT); throw explainWrongLengthOrOffset(bytes, offset, length, SIZEOF_INT);
} }
if (UNSAFE_UNALIGNED) { return ConverterHolder.BEST_CONVERTER.toInt(bytes, offset, length);
return UnsafeAccess.toInt(bytes, offset);
} else {
int n = 0;
for(int i = offset; i < (offset + length); i++) {
n <<= 8;
n ^= bytes[i] & 0xFF;
}
return n;
}
} }
/** /**
@ -1088,16 +1061,7 @@ public class Bytes implements Comparable<Bytes> {
throw new IllegalArgumentException("Not enough room to put an int at" throw new IllegalArgumentException("Not enough room to put an int at"
+ " offset " + offset + " in a " + bytes.length + " byte array"); + " offset " + offset + " in a " + bytes.length + " byte array");
} }
if (UNSAFE_UNALIGNED) { return ConverterHolder.BEST_CONVERTER.putInt(bytes, offset, val);
return UnsafeAccess.putInt(bytes, offset, val);
} else {
for(int i= offset + 3; i > offset; i--) {
bytes[i] = (byte) val;
val >>>= 8;
}
bytes[offset] = (byte) val;
return offset + SIZEOF_INT;
}
} }
/** /**
@ -1158,15 +1122,7 @@ public class Bytes implements Comparable<Bytes> {
if (length != SIZEOF_SHORT || offset + length > bytes.length) { if (length != SIZEOF_SHORT || offset + length > bytes.length) {
throw explainWrongLengthOrOffset(bytes, offset, length, SIZEOF_SHORT); throw explainWrongLengthOrOffset(bytes, offset, length, SIZEOF_SHORT);
} }
if (UNSAFE_UNALIGNED) { return ConverterHolder.BEST_CONVERTER.toShort(bytes, offset, length);
return UnsafeAccess.toShort(bytes, offset);
} else {
short n = 0;
n = (short) (n ^ (bytes[offset] & 0xFF));
n = (short) (n << 8);
n = (short) (n ^ (bytes[offset + 1] & 0xFF));
return n;
}
} }
/** /**
@ -1196,14 +1152,7 @@ public class Bytes implements Comparable<Bytes> {
throw new IllegalArgumentException("Not enough room to put a short at" throw new IllegalArgumentException("Not enough room to put a short at"
+ " offset " + offset + " in a " + bytes.length + " byte array"); + " offset " + offset + " in a " + bytes.length + " byte array");
} }
if (UNSAFE_UNALIGNED) { return ConverterHolder.BEST_CONVERTER.putShort(bytes, offset, val);
return UnsafeAccess.putShort(bytes, offset, val);
} else {
bytes[offset+1] = (byte) val;
val >>= 8;
bytes[offset] = (byte) val;
return offset + SIZEOF_SHORT;
}
} }
/** /**
@ -1432,11 +1381,161 @@ public class Bytes implements Comparable<Bytes> {
); );
} }
static abstract class Converter {
abstract long toLong(byte[] bytes, int offset, int length);
abstract int putLong(byte[] bytes, int offset, long val);
abstract int toInt(byte[] bytes, int offset, final int length);
abstract int putInt(byte[] bytes, int offset, int val);
abstract short toShort(byte[] bytes, int offset, final int length);
abstract int putShort(byte[] bytes, int offset, short val);
}
@VisibleForTesting @VisibleForTesting
static Comparer<byte[]> lexicographicalComparerJavaImpl() { static Comparer<byte[]> lexicographicalComparerJavaImpl() {
return LexicographicalComparerHolder.PureJavaComparer.INSTANCE; return LexicographicalComparerHolder.PureJavaComparer.INSTANCE;
} }
static class ConverterHolder {
static final String UNSAFE_CONVERTER_NAME =
ConverterHolder.class.getName() + "$UnsafeConverter";
static final Converter BEST_CONVERTER = getBestConverter();
/**
* Returns the Unsafe-using Converter, or falls back to the pure-Java
* implementation if unable to do so.
*/
static Converter getBestConverter() {
try {
Class<?> theClass = Class.forName(UNSAFE_CONVERTER_NAME);
// yes, UnsafeComparer does implement Comparer<byte[]>
@SuppressWarnings("unchecked")
Converter converter = (Converter) theClass.getConstructor().newInstance();
return converter;
} catch (Throwable t) { // ensure we really catch *everything*
return PureJavaConverter.INSTANCE;
}
}
protected static final class PureJavaConverter extends Converter {
static final PureJavaConverter INSTANCE = new PureJavaConverter();
private PureJavaConverter() {}
@Override
long toLong(byte[] bytes, int offset, int length) {
long l = 0;
for(int i = offset; i < offset + length; i++) {
l <<= 8;
l ^= bytes[i] & 0xFF;
}
return l;
}
@Override
int putLong(byte[] bytes, int offset, long val) {
for(int i = offset + 7; i > offset; i--) {
bytes[i] = (byte) val;
val >>>= 8;
}
bytes[offset] = (byte) val;
return offset + SIZEOF_LONG;
}
@Override
int toInt(byte[] bytes, int offset, int length) {
int n = 0;
for(int i = offset; i < (offset + length); i++) {
n <<= 8;
n ^= bytes[i] & 0xFF;
}
return n;
}
@Override
int putInt(byte[] bytes, int offset, int val) {
for(int i= offset + 3; i > offset; i--) {
bytes[i] = (byte) val;
val >>>= 8;
}
bytes[offset] = (byte) val;
return offset + SIZEOF_INT;
}
@Override
short toShort(byte[] bytes, int offset, int length) {
short n = 0;
n = (short) ((n ^ bytes[offset]) & 0xFF);
n = (short) (n << 8);
n ^= (short) (bytes[offset+1] & 0xFF);
return n;
}
@Override
int putShort(byte[] bytes, int offset, short val) {
bytes[offset+1] = (byte) val;
val >>= 8;
bytes[offset] = (byte) val;
return offset + SIZEOF_SHORT;
}
}
protected static final class UnsafeConverter extends Converter {
static final Unsafe theUnsafe;
public UnsafeConverter() {}
static {
if (UNSAFE_UNALIGNED) {
theUnsafe = UnsafeAccess.theUnsafe;
} else {
// It doesn't matter what we throw;
// it's swallowed in getBestComparer().
throw new Error();
}
// sanity check - this should never fail
if (theUnsafe.arrayIndexScale(byte[].class) != 1) {
throw new AssertionError();
}
}
@Override
long toLong(byte[] bytes, int offset, int length) {
return UnsafeAccess.toLong(bytes, offset);
}
@Override
int putLong(byte[] bytes, int offset, long val) {
return UnsafeAccess.putLong(bytes, offset, val);
}
@Override
int toInt(byte[] bytes, int offset, int length) {
return UnsafeAccess.toInt(bytes, offset);
}
@Override
int putInt(byte[] bytes, int offset, int val) {
return UnsafeAccess.putInt(bytes, offset, val);
}
@Override
short toShort(byte[] bytes, int offset, int length) {
return UnsafeAccess.toShort(bytes, offset);
}
@Override
int putShort(byte[] bytes, int offset, short val) {
return UnsafeAccess.putShort(bytes, offset, val);
}
}
}
/** /**
* Provides a lexicographical comparer implementation; either a Java * Provides a lexicographical comparer implementation; either a Java
* implementation or a faster implementation based on {@link Unsafe}. * implementation or a faster implementation based on {@link Unsafe}.