From 04c25e0f355aaa6ded37b0477ce126a693756b81 Mon Sep 17 00:00:00 2001 From: anoopsjohn Date: Sat, 20 Jun 2015 20:52:06 +0530 Subject: [PATCH] HBASE-13931 Move Unsafe based operations to UnsafeAccess. --- .../hadoop/hbase/filter/FuzzyRowFilter.java | 32 +-- .../hadoop/hbase/util/ByteBufferUtils.java | 80 +------ .../org/apache/hadoop/hbase/util/Bytes.java | 148 ++++--------- .../hadoop/hbase/util/UnsafeAccess.java | 209 +++++++++++++++++- 4 files changed, 262 insertions(+), 207 deletions(-) diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/filter/FuzzyRowFilter.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/filter/FuzzyRowFilter.java index 0510b9c9f9f..f208eb2869a 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/filter/FuzzyRowFilter.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/filter/FuzzyRowFilter.java @@ -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 diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/ByteBufferUtils.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/ByteBufferUtils.java index 9d1411744f5..66366797e95 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/ByteBufferUtils.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/ByteBufferUtils.java @@ -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); diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Bytes.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Bytes.java index 683b559e968..bc245a8c33f 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Bytes.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Bytes.java @@ -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 { 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 { 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 { * @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 { 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 { * @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 { * @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 { * @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 { 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 { * @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 { 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 { 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 { * @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 { 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() { - @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 { } } - 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 { * 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 { * 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 { * 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 { } 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 diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/UnsafeAccess.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/UnsafeAccess.java index c9a03d25c87..51dd6433fa1 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/UnsafeAccess.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/UnsafeAccess.java @@ -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() { @@ -63,11 +68,203 @@ 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); + } }