HBASE-13931 Move Unsafe based operations to UnsafeAccess.

This commit is contained in:
anoopsjohn 2015-06-20 20:52:06 +05:30
parent db08013ebe
commit 04c25e0f35
4 changed files with 262 additions and 207 deletions

View File

@ -331,19 +331,13 @@ public class FuzzyRowFilter extends FilterBase {
}
length = Math.min(length, fuzzyKeyBytes.length);
int numWords = length / Bytes.SIZEOF_LONG;
int offsetAdj = offset + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
int j = numWords << 3; // numWords * SIZEOF_LONG;
for (int i = 0; i < j; i += Bytes.SIZEOF_LONG) {
long fuzzyBytes =
UnsafeAccess.theUnsafe.getLong(fuzzyKeyBytes, UnsafeAccess.BYTE_ARRAY_BASE_OFFSET
+ (long) i);
long fuzzyMeta =
UnsafeAccess.theUnsafe.getLong(fuzzyKeyMeta, UnsafeAccess.BYTE_ARRAY_BASE_OFFSET
+ (long) i);
long rowValue = UnsafeAccess.theUnsafe.getLong(row, offsetAdj + (long) i);
long fuzzyBytes = UnsafeAccess.toLong(fuzzyKeyBytes, i);
long fuzzyMeta = UnsafeAccess.toLong(fuzzyKeyMeta, i);
long rowValue = UnsafeAccess.toLong(row, offset + i);
if ((rowValue & fuzzyMeta) != (fuzzyBytes)) {
// We always return NEXT_EXISTS
return SatisfiesCode.NEXT_EXISTS;
@ -353,13 +347,9 @@ public class FuzzyRowFilter extends FilterBase {
int off = j;
if (length - off >= Bytes.SIZEOF_INT) {
int fuzzyBytes =
UnsafeAccess.theUnsafe.getInt(fuzzyKeyBytes, UnsafeAccess.BYTE_ARRAY_BASE_OFFSET
+ (long) off);
int fuzzyMeta =
UnsafeAccess.theUnsafe.getInt(fuzzyKeyMeta, UnsafeAccess.BYTE_ARRAY_BASE_OFFSET
+ (long) off);
int rowValue = UnsafeAccess.theUnsafe.getInt(row, offsetAdj + (long) off);
int fuzzyBytes = UnsafeAccess.toInt(fuzzyKeyBytes, off);
int fuzzyMeta = UnsafeAccess.toInt(fuzzyKeyMeta, off);
int rowValue = UnsafeAccess.toInt(row, offset + off);
if ((rowValue & fuzzyMeta) != (fuzzyBytes)) {
// We always return NEXT_EXISTS
return SatisfiesCode.NEXT_EXISTS;
@ -368,13 +358,9 @@ public class FuzzyRowFilter extends FilterBase {
}
if (length - off >= Bytes.SIZEOF_SHORT) {
short fuzzyBytes =
UnsafeAccess.theUnsafe.getShort(fuzzyKeyBytes, UnsafeAccess.BYTE_ARRAY_BASE_OFFSET
+ (long) off);
short fuzzyMeta =
UnsafeAccess.theUnsafe.getShort(fuzzyKeyMeta, UnsafeAccess.BYTE_ARRAY_BASE_OFFSET
+ (long) off);
short rowValue = UnsafeAccess.theUnsafe.getShort(row, offsetAdj + (long) off);
short fuzzyBytes = UnsafeAccess.toShort(fuzzyKeyBytes, off);
short fuzzyMeta = UnsafeAccess.toShort(fuzzyKeyMeta, off);
short rowValue = UnsafeAccess.toShort(row, offset + off);
if ((rowValue & fuzzyMeta) != (fuzzyBytes)) {
// We always return NEXT_EXISTS
// even if it does not (in this case getNextForFuzzyRule

View File

@ -28,8 +28,6 @@ import org.apache.hadoop.hbase.classification.InterfaceStability;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.WritableUtils;
import sun.nio.ch.DirectBuffer;
/**
* Utility functions for working with byte buffers, such as reading/writing
* variable-length long numbers.
@ -519,26 +517,12 @@ public final class ByteBufferUtils {
*/
public static short toShort(ByteBuffer buffer, int offset) {
if (UnsafeAccess.isAvailable()) {
return toShortUnsafe(buffer, offset);
return UnsafeAccess.toShort(buffer, offset);
} else {
return buffer.getShort(offset);
}
}
private static short toShortUnsafe(ByteBuffer buf, long offset) {
short ret;
if (buf.isDirect()) {
ret = UnsafeAccess.theUnsafe.getShort(((DirectBuffer) buf).address() + offset);
} else {
ret = UnsafeAccess.theUnsafe.getShort(buf.array(),
UnsafeAccess.BYTE_ARRAY_BASE_OFFSET + buf.arrayOffset() + offset);
}
if (UnsafeAccess.littleEndian) {
return Short.reverseBytes(ret);
}
return ret;
}
/**
* Reads an int value at the given buffer's offset.
* @param buffer
@ -547,26 +531,12 @@ public final class ByteBufferUtils {
*/
public static int toInt(ByteBuffer buffer, int offset) {
if (UnsafeAccess.isAvailable()) {
return toIntUnsafe(buffer, offset);
return UnsafeAccess.toInt(buffer, offset);
} else {
return buffer.getInt(offset);
}
}
private static int toIntUnsafe(ByteBuffer buf, long offset) {
int ret;
if (buf.isDirect()) {
ret = UnsafeAccess.theUnsafe.getInt(((DirectBuffer) buf).address() + offset);
} else {
ret = UnsafeAccess.theUnsafe.getInt(buf.array(),
UnsafeAccess.BYTE_ARRAY_BASE_OFFSET + buf.arrayOffset() + offset);
}
if (UnsafeAccess.littleEndian) {
return Integer.reverseBytes(ret);
}
return ret;
}
/**
* Reads a long value at the given buffer's offset.
* @param buffer
@ -575,26 +545,12 @@ public final class ByteBufferUtils {
*/
public static long toLong(ByteBuffer buffer, int offset) {
if (UnsafeAccess.isAvailable()) {
return toLongUnsafe(buffer, offset);
return UnsafeAccess.toLong(buffer, offset);
} else {
return buffer.getLong(offset);
}
}
private static long toLongUnsafe(ByteBuffer buf, long offset) {
long ret;
if (buf.isDirect()) {
ret = UnsafeAccess.theUnsafe.getLong(((DirectBuffer) buf).address() + offset);
} else {
ret = UnsafeAccess.theUnsafe.getLong(buf.array(),
UnsafeAccess.BYTE_ARRAY_BASE_OFFSET + buf.arrayOffset() + offset);
}
if (UnsafeAccess.littleEndian) {
return Long.reverseBytes(ret);
}
return ret;
}
/**
* Copies the bytes from given array's offset to length part into the given buffer. Puts the bytes
* to buffer's current position. This also advances the position in the 'out' buffer by 'length'
@ -609,7 +565,7 @@ public final class ByteBufferUtils {
// Move the position in out by length
out.position(out.position() + length);
} else if (UnsafeAccess.isAvailable()) {
copyUnsafe(in, inOffset, out, out.position(), length);
UnsafeAccess.copy(in, inOffset, out, out.position(), length);
// Move the position in out by length
out.position(out.position() + length);
} else {
@ -617,32 +573,6 @@ public final class ByteBufferUtils {
}
}
static void copyUnsafe(byte[] src, int srcOffset, ByteBuffer dest, int destOffset, int length) {
long destAddress = destOffset;
Object destBase = null;
if (dest.isDirect()) {
destAddress = destAddress + ((DirectBuffer) dest).address();
} else {
destAddress = destAddress + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET + dest.arrayOffset();
destBase = dest.array();
}
long srcAddress = srcOffset + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
UnsafeAccess.theUnsafe.copyMemory(src, srcAddress, destBase, destAddress, length);
}
static void copyUnsafe(ByteBuffer src, int srcOffset, byte[] dest, int destOffset, int length) {
long srcAddress = srcOffset;
Object srcBase = null;
if (src.isDirect()) {
srcAddress = srcAddress + ((DirectBuffer) src).address();
} else {
srcAddress = srcAddress + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET + src.arrayOffset();
srcBase = src.array();
}
long destAddress = destOffset + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
UnsafeAccess.theUnsafe.copyMemory(srcBase, srcAddress, dest, destAddress, length);
}
/**
* Copies specified number of bytes from given offset of 'in' ByteBuffer to the array.
* @param out
@ -656,7 +586,7 @@ public final class ByteBufferUtils {
if (in.hasArray()) {
System.arraycopy(in.array(), sourceOffset + in.arrayOffset(), out, destinationOffset, length);
} else if (UnsafeAccess.isAvailable()) {
copyUnsafe(in, sourceOffset, out, destinationOffset, length);
UnsafeAccess.copy(in, sourceOffset, out, destinationOffset, length);
} else {
for (int i = 0; i < length; i++) {
out[destinationOffset + i] = in.get(sourceOffset + i);

View File

@ -24,14 +24,10 @@ import static com.google.common.base.Preconditions.checkPositionIndex;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.Charset;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Collection;
@ -57,8 +53,6 @@ import sun.misc.Unsafe;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
import org.apache.hadoop.hbase.util.Bytes.LexicographicalComparerHolder.UnsafeComparer;
/**
* Utility class that handles byte arrays, conversions to/from other types,
* comparisons, hash code generation, manufacturing keys for HashMaps or
@ -795,8 +789,8 @@ public class Bytes implements Comparable<Bytes> {
if (length != SIZEOF_LONG || offset + length > bytes.length) {
throw explainWrongLengthOrOffset(bytes, offset, length, SIZEOF_LONG);
}
if (UnsafeComparer.isAvailable()) {
return toLongUnsafe(bytes, offset);
if (UnsafeAccess.isAvailable()) {
return UnsafeAccess.toLong(bytes, offset);
} else {
long l = 0;
for(int i = offset; i < offset + length; i++) {
@ -836,8 +830,8 @@ public class Bytes implements Comparable<Bytes> {
throw new IllegalArgumentException("Not enough room to put a long at"
+ " offset " + offset + " in a " + bytes.length + " byte array");
}
if (UnsafeComparer.isAvailable()) {
return putLongUnsafe(bytes, offset, val);
if (UnsafeAccess.isAvailable()) {
return UnsafeAccess.putLong(bytes, offset, val);
} else {
for(int i = offset + 7; i > offset; i--) {
bytes[i] = (byte) val;
@ -854,15 +848,11 @@ public class Bytes implements Comparable<Bytes> {
* @param offset position in the array
* @param val long to write out
* @return incremented offset
* @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
*/
public static int putLongUnsafe(byte[] bytes, int offset, long val)
{
if (UnsafeComparer.littleEndian) {
val = Long.reverseBytes(val);
}
UnsafeComparer.theUnsafe.putLong(bytes, (long) offset +
UnsafeComparer.BYTE_ARRAY_BASE_OFFSET , val);
return offset + SIZEOF_LONG;
@Deprecated
public static int putLongUnsafe(byte[] bytes, int offset, long val) {
return UnsafeAccess.putLong(bytes, offset, val);
}
/**
@ -991,8 +981,8 @@ public class Bytes implements Comparable<Bytes> {
if (length != SIZEOF_INT || offset + length > bytes.length) {
throw explainWrongLengthOrOffset(bytes, offset, length, SIZEOF_INT);
}
if (UnsafeComparer.isAvailable()) {
return toIntUnsafe(bytes, offset);
if (UnsafeAccess.isAvailable()) {
return UnsafeAccess.toInt(bytes, offset);
} else {
int n = 0;
for(int i = offset; i < (offset + length); i++) {
@ -1008,15 +998,11 @@ public class Bytes implements Comparable<Bytes> {
* @param bytes byte array
* @param offset offset into array
* @return the int value
* @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
*/
@Deprecated
public static int toIntUnsafe(byte[] bytes, int offset) {
if (UnsafeComparer.littleEndian) {
return Integer.reverseBytes(UnsafeComparer.theUnsafe.getInt(bytes,
(long) offset + UnsafeComparer.BYTE_ARRAY_BASE_OFFSET));
} else {
return UnsafeComparer.theUnsafe.getInt(bytes,
(long) offset + UnsafeComparer.BYTE_ARRAY_BASE_OFFSET);
}
return UnsafeAccess.toInt(bytes, offset);
}
/**
@ -1024,15 +1010,11 @@ public class Bytes implements Comparable<Bytes> {
* @param bytes byte array
* @param offset offset into array
* @return the short value
* @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
*/
@Deprecated
public static short toShortUnsafe(byte[] bytes, int offset) {
if (UnsafeComparer.littleEndian) {
return Short.reverseBytes(UnsafeComparer.theUnsafe.getShort(bytes,
(long) offset + UnsafeComparer.BYTE_ARRAY_BASE_OFFSET));
} else {
return UnsafeComparer.theUnsafe.getShort(bytes,
(long) offset + UnsafeComparer.BYTE_ARRAY_BASE_OFFSET);
}
return UnsafeAccess.toShort(bytes, offset);
}
/**
@ -1040,15 +1022,11 @@ public class Bytes implements Comparable<Bytes> {
* @param bytes byte array
* @param offset offset into array
* @return the long value
* @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
*/
@Deprecated
public static long toLongUnsafe(byte[] bytes, int offset) {
if (UnsafeComparer.littleEndian) {
return Long.reverseBytes(UnsafeComparer.theUnsafe.getLong(bytes,
(long) offset + UnsafeComparer.BYTE_ARRAY_BASE_OFFSET));
} else {
return UnsafeComparer.theUnsafe.getLong(bytes,
(long) offset + UnsafeComparer.BYTE_ARRAY_BASE_OFFSET);
}
return UnsafeAccess.toLong(bytes, offset);
}
/**
@ -1087,8 +1065,8 @@ public class Bytes implements Comparable<Bytes> {
throw new IllegalArgumentException("Not enough room to put an int at"
+ " offset " + offset + " in a " + bytes.length + " byte array");
}
if (UnsafeComparer.isAvailable()) {
return putIntUnsafe(bytes, offset, val);
if (UnsafeAccess.isAvailable()) {
return UnsafeAccess.putInt(bytes, offset, val);
} else {
for(int i= offset + 3; i > offset; i--) {
bytes[i] = (byte) val;
@ -1105,15 +1083,11 @@ public class Bytes implements Comparable<Bytes> {
* @param offset position in the array
* @param val int to write out
* @return incremented offset
* @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
*/
public static int putIntUnsafe(byte[] bytes, int offset, int val)
{
if (UnsafeComparer.littleEndian) {
val = Integer.reverseBytes(val);
}
UnsafeComparer.theUnsafe.putInt(bytes, (long) offset +
UnsafeComparer.BYTE_ARRAY_BASE_OFFSET , val);
return offset + SIZEOF_INT;
@Deprecated
public static int putIntUnsafe(byte[] bytes, int offset, int val) {
return UnsafeAccess.putInt(bytes, offset, val);
}
/**
@ -1161,8 +1135,8 @@ public class Bytes implements Comparable<Bytes> {
if (length != SIZEOF_SHORT || offset + length > bytes.length) {
throw explainWrongLengthOrOffset(bytes, offset, length, SIZEOF_SHORT);
}
if (UnsafeComparer.isAvailable()) {
return toShortUnsafe(bytes, offset);
if (UnsafeAccess.isAvailable()) {
return UnsafeAccess.toShort(bytes, offset);
} else {
short n = 0;
n ^= bytes[offset] & 0xFF;
@ -1199,8 +1173,8 @@ public class Bytes implements Comparable<Bytes> {
throw new IllegalArgumentException("Not enough room to put a short at"
+ " offset " + offset + " in a " + bytes.length + " byte array");
}
if (UnsafeComparer.isAvailable()) {
return putShortUnsafe(bytes, offset, val);
if (UnsafeAccess.isAvailable()) {
return UnsafeAccess.putShort(bytes, offset, val);
} else {
bytes[offset+1] = (byte) val;
val >>= 8;
@ -1215,15 +1189,11 @@ public class Bytes implements Comparable<Bytes> {
* @param offset position in the array
* @param val short to write out
* @return incremented offset
* @deprecated As of release 2.0.0, this will be removed in HBase 3.0.0.
*/
public static int putShortUnsafe(byte[] bytes, int offset, short val)
{
if (UnsafeComparer.littleEndian) {
val = Short.reverseBytes(val);
}
UnsafeComparer.theUnsafe.putShort(bytes, (long) offset +
UnsafeComparer.BYTE_ARRAY_BASE_OFFSET , val);
return offset + SIZEOF_SHORT;
@Deprecated
public static int putShortUnsafe(byte[] bytes, int offset, short val) {
return UnsafeAccess.putShort(bytes, offset, val);
}
/**
@ -1506,30 +1476,14 @@ public class Bytes implements Comparable<Bytes> {
INSTANCE;
static final Unsafe theUnsafe;
/** The offset to the first element in a byte array. */
static final int BYTE_ARRAY_BASE_OFFSET;
static {
theUnsafe = (Unsafe) AccessController.doPrivileged(
new PrivilegedAction<Object>() {
@Override
public Object run() {
try {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
return f.get(null);
} catch (NoSuchFieldException e) {
// It doesn't matter what we throw;
// it's swallowed in getBestComparer().
throw new Error();
} catch (IllegalAccessException e) {
throw new Error();
}
}
});
BYTE_ARRAY_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class);
if (UnsafeAccess.isAvailable()) {
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) {
@ -1537,9 +1491,6 @@ public class Bytes implements Comparable<Bytes> {
}
}
static final boolean littleEndian =
ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN);
/**
* Returns true if x1 is less than x2, when both values are treated as
* unsigned long.
@ -1548,7 +1499,7 @@ public class Bytes implements Comparable<Bytes> {
* Big Endian format.
*/
static boolean lessThanUnsignedLong(long x1, long x2) {
if (littleEndian) {
if (UnsafeAccess.littleEndian) {
x1 = Long.reverseBytes(x1);
x2 = Long.reverseBytes(x2);
}
@ -1563,7 +1514,7 @@ public class Bytes implements Comparable<Bytes> {
* Big Endian format.
*/
static boolean lessThanUnsignedInt(int x1, int x2) {
if (littleEndian) {
if (UnsafeAccess.littleEndian) {
x1 = Integer.reverseBytes(x1);
x2 = Integer.reverseBytes(x2);
}
@ -1578,22 +1529,13 @@ public class Bytes implements Comparable<Bytes> {
* Big Endian format.
*/
static boolean lessThanUnsignedShort(short x1, short x2) {
if (littleEndian) {
if (UnsafeAccess.littleEndian) {
x1 = Short.reverseBytes(x1);
x2 = Short.reverseBytes(x2);
}
return (x1 & 0xffff) < (x2 & 0xffff);
}
/**
* Checks if Unsafe is available
* @return true, if available, false - otherwise
*/
public static boolean isAvailable()
{
return theUnsafe != null;
}
/**
* Lexicographically compare two arrays.
*
@ -1617,8 +1559,8 @@ public class Bytes implements Comparable<Bytes> {
}
final int minLength = Math.min(length1, length2);
final int minWords = minLength / SIZEOF_LONG;
final long offset1Adj = offset1 + BYTE_ARRAY_BASE_OFFSET;
final long offset2Adj = offset2 + BYTE_ARRAY_BASE_OFFSET;
final long offset1Adj = offset1 + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
final long offset2Adj = offset2 + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
/*
* Compare 8 bytes at a time. Benchmarking shows comparing 8 bytes at a

View File

@ -18,6 +18,7 @@
package org.apache.hadoop.hbase.util;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.AccessController;
import java.security.PrivilegedAction;
@ -28,6 +29,7 @@ import org.apache.hadoop.hbase.classification.InterfaceAudience;
import org.apache.hadoop.hbase.classification.InterfaceStability;
import sun.misc.Unsafe;
import sun.nio.ch.DirectBuffer;
@InterfaceAudience.Private
@InterfaceStability.Evolving
@ -35,10 +37,13 @@ public final class UnsafeAccess {
private static final Log LOG = LogFactory.getLog(UnsafeAccess.class);
public static final Unsafe theUnsafe;
static final Unsafe theUnsafe;
/** The offset to the first element in a byte array. */
public static final int BYTE_ARRAY_BASE_OFFSET;
static final long BYTE_ARRAY_BASE_OFFSET;
static final boolean littleEndian = ByteOrder.nativeOrder()
.equals(ByteOrder.LITTLE_ENDIAN);
static {
theUnsafe = (Unsafe) AccessController.doPrivileged(new PrivilegedAction<Object>() {
@ -64,10 +69,202 @@ public final class UnsafeAccess {
private UnsafeAccess(){}
/**
* @return true when the running JVM is having sun's Unsafe package available in it.
*/
public static boolean isAvailable() {
return theUnsafe != null;
}
public static final boolean littleEndian = ByteOrder.nativeOrder()
.equals(ByteOrder.LITTLE_ENDIAN);
// APIs to read primitive data from a byte[] using Unsafe way
/**
* Converts a byte array to a short value.
* @param bytes byte array
* @param offset offset into array
* @return the short value
*/
public static short toShort(byte[] bytes, int offset) {
if (littleEndian) {
return Short.reverseBytes(theUnsafe.getShort(bytes, offset + BYTE_ARRAY_BASE_OFFSET));
} else {
return theUnsafe.getShort(bytes, offset + BYTE_ARRAY_BASE_OFFSET);
}
}
/**
* Converts a byte array to an int value.
* @param bytes byte array
* @param offset offset into array
* @return the int value
*/
public static int toInt(byte[] bytes, int offset) {
if (littleEndian) {
return Integer.reverseBytes(theUnsafe.getInt(bytes, offset + BYTE_ARRAY_BASE_OFFSET));
} else {
return theUnsafe.getInt(bytes, offset + BYTE_ARRAY_BASE_OFFSET);
}
}
/**
* Converts a byte array to a long value.
* @param bytes byte array
* @param offset offset into array
* @return the long value
*/
public static long toLong(byte[] bytes, int offset) {
if (littleEndian) {
return Long.reverseBytes(theUnsafe.getLong(bytes, offset + BYTE_ARRAY_BASE_OFFSET));
} else {
return theUnsafe.getLong(bytes, offset + BYTE_ARRAY_BASE_OFFSET);
}
}
// APIs to write primitive data to a byte[] using Unsafe way
/**
* Put a short value out to the specified byte array position.
* @param bytes the byte array
* @param offset position in the array
* @param val short to write out
* @return incremented offset
*/
public static int putShort(byte[] bytes, int offset, short val) {
if (littleEndian) {
val = Short.reverseBytes(val);
}
theUnsafe.putShort(bytes, offset + BYTE_ARRAY_BASE_OFFSET, val);
return offset + Bytes.SIZEOF_SHORT;
}
/**
* Put an int value out to the specified byte array position.
* @param bytes the byte array
* @param offset position in the array
* @param val int to write out
* @return incremented offset
*/
public static int putInt(byte[] bytes, int offset, int val) {
if (littleEndian) {
val = Integer.reverseBytes(val);
}
theUnsafe.putInt(bytes, offset + BYTE_ARRAY_BASE_OFFSET, val);
return offset + Bytes.SIZEOF_INT;
}
/**
* Put a long value out to the specified byte array position.
* @param bytes the byte array
* @param offset position in the array
* @param val long to write out
* @return incremented offset
*/
public static int putLong(byte[] bytes, int offset, long val) {
if (littleEndian) {
val = Long.reverseBytes(val);
}
theUnsafe.putLong(bytes, offset + BYTE_ARRAY_BASE_OFFSET, val);
return offset + Bytes.SIZEOF_LONG;
}
// APIs to read primitive data from a ByteBuffer using Unsafe way
/**
* Reads a short value at the given buffer's offset.
* @param buf
* @param offset
* @return short value at offset
*/
public static short toShort(ByteBuffer buf, int offset) {
short ret;
if (buf.isDirect()) {
ret = theUnsafe.getShort(((DirectBuffer) buf).address() + offset);
} else {
ret = theUnsafe.getShort(buf.array(), BYTE_ARRAY_BASE_OFFSET + buf.arrayOffset() + offset);
}
if (littleEndian) {
return Short.reverseBytes(ret);
}
return ret;
}
/**
* Reads an int value at the given buffer's offset.
* @param buf
* @param offset
* @return int value at offset
*/
public static int toInt(ByteBuffer buf, int offset) {
int ret;
if (buf.isDirect()) {
ret = theUnsafe.getInt(((DirectBuffer) buf).address() + offset);
} else {
ret = theUnsafe.getInt(buf.array(), BYTE_ARRAY_BASE_OFFSET + buf.arrayOffset() + offset);
}
if (littleEndian) {
return Integer.reverseBytes(ret);
}
return ret;
}
/**
* Reads a long value at the given buffer's offset.
* @param buf
* @param offset
* @return long value at offset
*/
public static long toLong(ByteBuffer buf, int offset) {
long ret;
if (buf.isDirect()) {
ret = theUnsafe.getLong(((DirectBuffer) buf).address() + offset);
} else {
ret = theUnsafe.getLong(buf.array(), BYTE_ARRAY_BASE_OFFSET + buf.arrayOffset() + offset);
}
if (littleEndian) {
return Long.reverseBytes(ret);
}
return ret;
}
// APIs to copy data. This will be direct memory location copy and will be much faster
/**
* Copies the bytes from given array's offset to length part into the given buffer. Puts the bytes
* to buffer's current position.
* @param src
* @param srcOffset
* @param dest
* @param destOffset
* @param length
*/
public static void copy(byte[] src, int srcOffset, ByteBuffer dest, int destOffset, int length) {
long destAddress = destOffset;
Object destBase = null;
if (dest.isDirect()) {
destAddress = destAddress + ((DirectBuffer) dest).address();
} else {
destAddress = destAddress + BYTE_ARRAY_BASE_OFFSET + dest.arrayOffset();
destBase = dest.array();
}
long srcAddress = srcOffset + BYTE_ARRAY_BASE_OFFSET;
theUnsafe.copyMemory(src, srcAddress, destBase, destAddress, length);
}
/**
* Copies specified number of bytes from given offset of 'in' ByteBuffer to the array.
* @param src
* @param srcOffset
* @param dest
* @param destOffset
* @param length
*/
public static void copy(ByteBuffer src, int srcOffset, byte[] dest, int destOffset,
int length) {
long srcAddress = srcOffset;
Object srcBase = null;
if (src.isDirect()) {
srcAddress = srcAddress + ((DirectBuffer) src).address();
} else {
srcAddress = srcAddress + BYTE_ARRAY_BASE_OFFSET + src.arrayOffset();
srcBase = src.array();
}
long destAddress = destOffset + BYTE_ARRAY_BASE_OFFSET;
theUnsafe.copyMemory(srcBase, srcAddress, dest, destAddress, length);
}
}