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:
parent
c744dd84cc
commit
b972b9a2d9
|
@ -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
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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}.
|
||||||
|
|
Loading…
Reference in New Issue