HBASE-14940 Make our unsafe based ops more safe.

This commit is contained in:
anoopsjohn 2015-12-24 07:56:27 +05:30
parent fdeca854ec
commit 4a7565af9c
3 changed files with 45 additions and 26 deletions

View File

@ -93,7 +93,7 @@ public class FuzzyRowFilter extends FilterBase {
} }
private void preprocessSearchKey(Pair<byte[], byte[]> p) { private void preprocessSearchKey(Pair<byte[], byte[]> p) {
if (UnsafeAccess.isAvailable() == false) { if (UnsafeAccess.unaligned() == false) {
return; return;
} }
byte[] key = p.getFirst(); byte[] key = p.getFirst();
@ -111,7 +111,7 @@ public class FuzzyRowFilter extends FilterBase {
* @return mask array * @return mask array
*/ */
private byte[] preprocessMask(byte[] mask) { private byte[] preprocessMask(byte[] mask) {
if (UnsafeAccess.isAvailable() == false) { if (UnsafeAccess.unaligned() == false) {
return mask; return mask;
} }
if (isPreprocessedMask(mask)) 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, static SatisfiesCode satisfies(boolean reverse, byte[] row, int offset, int length,
byte[] fuzzyKeyBytes, byte[] fuzzyKeyMeta) { byte[] fuzzyKeyBytes, byte[] fuzzyKeyMeta) {
if (UnsafeAccess.isAvailable() == false) { if (UnsafeAccess.unaligned() == false) {
return satisfiesNoUnsafe(reverse, row, offset, length, fuzzyKeyBytes, fuzzyKeyMeta); return satisfiesNoUnsafe(reverse, row, offset, length, fuzzyKeyBytes, fuzzyKeyMeta);
} }

View File

@ -604,7 +604,7 @@ public class 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 (UnsafeComparer.isAvailable()) { if (UnsafeComparer.unaligned()) {
return toLongUnsafe(bytes, offset); return toLongUnsafe(bytes, offset);
} else { } else {
long l = 0; long l = 0;
@ -645,7 +645,7 @@ public class 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 (UnsafeComparer.isAvailable()) { if (UnsafeComparer.unaligned()) {
return putLongUnsafe(bytes, offset, val); return putLongUnsafe(bytes, offset, val);
} else { } else {
for(int i = offset + 7; i > offset; i--) { for(int i = offset + 7; i > offset; i--) {
@ -800,7 +800,7 @@ public class 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 (UnsafeComparer.isAvailable()) { if (UnsafeComparer.unaligned()) {
return toIntUnsafe(bytes, offset); return toIntUnsafe(bytes, offset);
} else { } else {
int n = 0; int n = 0;
@ -896,7 +896,7 @@ public class 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 (UnsafeComparer.isAvailable()) { if (UnsafeComparer.unaligned()) {
return putIntUnsafe(bytes, offset, val); return putIntUnsafe(bytes, offset, val);
} else { } else {
for(int i= offset + 3; i > offset; i--) { for(int i= offset + 3; i > offset; i--) {
@ -970,7 +970,7 @@ public class 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 (UnsafeComparer.isAvailable()) { if (UnsafeComparer.unaligned()) {
return toShortUnsafe(bytes, offset); return toShortUnsafe(bytes, offset);
} else { } else {
short n = 0; short n = 0;
@ -1008,7 +1008,7 @@ public class 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 (UnsafeComparer.isAvailable()) { if (UnsafeComparer.unaligned()) {
return putShortUnsafe(bytes, offset, val); return putShortUnsafe(bytes, offset, val);
} else { } else {
bytes[offset+1] = (byte) val; bytes[offset+1] = (byte) val;
@ -1315,28 +1315,19 @@ public class Bytes {
INSTANCE; INSTANCE;
static final Unsafe theUnsafe; static final Unsafe theUnsafe;
private static boolean unaligned = false;
/** The offset to the first element in a byte array. */ /** The offset to the first element in a byte array. */
static final int BYTE_ARRAY_BASE_OFFSET; static final int BYTE_ARRAY_BASE_OFFSET;
static { static {
theUnsafe = (Unsafe) AccessController.doPrivileged( if (UnsafeAccess.unaligned()) {
new PrivilegedAction<Object>() { theUnsafe = UnsafeAccess.theUnsafe;
@Override } else {
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 doesn't matter what we throw;
// it's swallowed in getBestComparer(). // it's swallowed in getBestComparer().
throw new Error(); throw new Error();
} catch (IllegalAccessException e) {
throw new Error();
} }
}
});
BYTE_ARRAY_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class); BYTE_ARRAY_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class);
@ -1344,6 +1335,7 @@ public class Bytes {
if (theUnsafe.arrayIndexScale(byte[].class) != 1) { if (theUnsafe.arrayIndexScale(byte[].class) != 1) {
throw new AssertionError(); throw new AssertionError();
} }
unaligned = UnsafeAccess.unaligned();
} }
static final boolean littleEndian = static final boolean littleEndian =
@ -1403,6 +1395,14 @@ public class Bytes {
return theUnsafe != null; 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. * Lexicographically compare two arrays.
* *

View File

@ -18,6 +18,7 @@
package org.apache.hadoop.hbase.util; package org.apache.hadoop.hbase.util;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
@ -39,6 +40,7 @@ public final class UnsafeAccess {
/** The offset to the first element in a byte array. */ /** The offset to the first element in a byte array. */
public static final int BYTE_ARRAY_BASE_OFFSET; public static final int BYTE_ARRAY_BASE_OFFSET;
private static boolean unaligned = false;
static { static {
theUnsafe = (Unsafe) AccessController.doPrivileged(new PrivilegedAction<Object>() { theUnsafe = (Unsafe) AccessController.doPrivileged(new PrivilegedAction<Object>() {
@ -57,6 +59,15 @@ public final class UnsafeAccess {
if(theUnsafe != null){ if(theUnsafe != null){
BYTE_ARRAY_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class); 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{ } else{
BYTE_ARRAY_BASE_OFFSET = -1; BYTE_ARRAY_BASE_OFFSET = -1;
} }
@ -68,6 +79,14 @@ public final class UnsafeAccess {
return theUnsafe != null; 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() public static final boolean littleEndian = ByteOrder.nativeOrder()
.equals(ByteOrder.LITTLE_ENDIAN); .equals(ByteOrder.LITTLE_ENDIAN);
} }