From 4a7565af9cf8ef7e40ef3c592d6815d1b671fb5e Mon Sep 17 00:00:00 2001 From: anoopsjohn Date: Thu, 24 Dec 2015 07:56:27 +0530 Subject: [PATCH] HBASE-14940 Make our unsafe based ops more safe. --- .../hadoop/hbase/filter/FuzzyRowFilter.java | 6 +-- .../org/apache/hadoop/hbase/util/Bytes.java | 46 +++++++++---------- .../hadoop/hbase/util/UnsafeAccess.java | 19 ++++++++ 3 files changed, 45 insertions(+), 26 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 3bc5b7440c2..0158680e782 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 @@ -93,7 +93,7 @@ public class FuzzyRowFilter extends FilterBase { } private void preprocessSearchKey(Pair p) { - if (UnsafeAccess.isAvailable() == false) { + if (UnsafeAccess.unaligned() == false) { return; } byte[] key = p.getFirst(); @@ -111,7 +111,7 @@ public class FuzzyRowFilter extends FilterBase { * @return mask array */ private byte[] preprocessMask(byte[] mask) { - if (UnsafeAccess.isAvailable() == false) { + if (UnsafeAccess.unaligned() == false) { return mask; } if (isPreprocessedMask(mask)) return mask; @@ -320,7 +320,7 @@ public class FuzzyRowFilter extends FilterBase { static SatisfiesCode satisfies(boolean reverse, byte[] row, int offset, int length, byte[] fuzzyKeyBytes, byte[] fuzzyKeyMeta) { - if (UnsafeAccess.isAvailable() == false) { + if (UnsafeAccess.unaligned() == false) { return satisfiesNoUnsafe(reverse, row, offset, length, fuzzyKeyBytes, fuzzyKeyMeta); } 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 a5a6cca8c2a..3d709a5a3c3 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 @@ -604,7 +604,7 @@ public class Bytes { if (length != SIZEOF_LONG || offset + length > bytes.length) { throw explainWrongLengthOrOffset(bytes, offset, length, SIZEOF_LONG); } - if (UnsafeComparer.isAvailable()) { + if (UnsafeComparer.unaligned()) { return toLongUnsafe(bytes, offset); } else { long l = 0; @@ -645,7 +645,7 @@ public class Bytes { throw new IllegalArgumentException("Not enough room to put a long at" + " offset " + offset + " in a " + bytes.length + " byte array"); } - if (UnsafeComparer.isAvailable()) { + if (UnsafeComparer.unaligned()) { return putLongUnsafe(bytes, offset, val); } else { for(int i = offset + 7; i > offset; i--) { @@ -800,7 +800,7 @@ public class Bytes { if (length != SIZEOF_INT || offset + length > bytes.length) { throw explainWrongLengthOrOffset(bytes, offset, length, SIZEOF_INT); } - if (UnsafeComparer.isAvailable()) { + if (UnsafeComparer.unaligned()) { return toIntUnsafe(bytes, offset); } else { int n = 0; @@ -896,7 +896,7 @@ public class Bytes { throw new IllegalArgumentException("Not enough room to put an int at" + " offset " + offset + " in a " + bytes.length + " byte array"); } - if (UnsafeComparer.isAvailable()) { + if (UnsafeComparer.unaligned()) { return putIntUnsafe(bytes, offset, val); } else { for(int i= offset + 3; i > offset; i--) { @@ -970,7 +970,7 @@ public class Bytes { if (length != SIZEOF_SHORT || offset + length > bytes.length) { throw explainWrongLengthOrOffset(bytes, offset, length, SIZEOF_SHORT); } - if (UnsafeComparer.isAvailable()) { + if (UnsafeComparer.unaligned()) { return toShortUnsafe(bytes, offset); } else { short n = 0; @@ -1008,7 +1008,7 @@ public class Bytes { throw new IllegalArgumentException("Not enough room to put a short at" + " offset " + offset + " in a " + bytes.length + " byte array"); } - if (UnsafeComparer.isAvailable()) { + if (UnsafeComparer.unaligned()) { return putShortUnsafe(bytes, offset, val); } else { bytes[offset+1] = (byte) val; @@ -1315,28 +1315,19 @@ public class Bytes { INSTANCE; static final Unsafe theUnsafe; + private static boolean unaligned = false; /** 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(); - } - } - }); + if (UnsafeAccess.unaligned()) { + theUnsafe = UnsafeAccess.theUnsafe; + } else { + // It doesn't matter what we throw; + // it's swallowed in getBestComparer(). + throw new Error(); + } BYTE_ARRAY_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class); @@ -1344,6 +1335,7 @@ public class Bytes { if (theUnsafe.arrayIndexScale(byte[].class) != 1) { throw new AssertionError(); } + unaligned = UnsafeAccess.unaligned(); } static final boolean littleEndian = @@ -1403,6 +1395,14 @@ public class Bytes { return theUnsafe != null; } + /** + * @return true when running JVM is having sun's Unsafe package available in it and underlying + * system having unaligned-access capability. + */ + public static boolean unaligned() { + return unaligned; + } + /** * Lexicographically compare two arrays. * 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 680bee4da80..1a3460795cd 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.lang.reflect.Method; import java.nio.ByteOrder; import java.security.AccessController; import java.security.PrivilegedAction; @@ -39,6 +40,7 @@ public final class UnsafeAccess { /** The offset to the first element in a byte array. */ public static final int BYTE_ARRAY_BASE_OFFSET; + private static boolean unaligned = false; static { theUnsafe = (Unsafe) AccessController.doPrivileged(new PrivilegedAction() { @@ -57,6 +59,15 @@ public final class UnsafeAccess { if(theUnsafe != null){ BYTE_ARRAY_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class); + try { + // Using java.nio.Bits#unaligned() to check for unaligned-access capability + Class clazz = Class.forName("java.nio.Bits"); + Method m = clazz.getDeclaredMethod("unaligned"); + m.setAccessible(true); + unaligned = (boolean) m.invoke(null); + } catch (Exception e) { + unaligned = false; + } } else{ BYTE_ARRAY_BASE_OFFSET = -1; } @@ -68,6 +79,14 @@ public final class UnsafeAccess { return theUnsafe != null; } + /** + * @return true when running JVM is having sun's Unsafe package available in it and underlying + * system having unaligned-access capability. + */ + public static boolean unaligned() { + return unaligned; + } + public static final boolean littleEndian = ByteOrder.nativeOrder() .equals(ByteOrder.LITTLE_ENDIAN); }