HBASE-15322 Operations using Unsafe path broken for platforms not having sun.misc.Unsafe.

This commit is contained in:
anoopsjohn 2016-03-11 09:38:24 +05:30
parent e445272724
commit 75547a42b9
5 changed files with 101 additions and 51 deletions

View File

@ -34,6 +34,7 @@ import org.apache.hadoop.hbase.util.ByteStringer;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.Pair;
import org.apache.hadoop.hbase.util.UnsafeAccess;
import org.apache.hadoop.hbase.util.UnsafeAvailChecker;
import com.google.common.annotations.VisibleForTesting;
import com.google.protobuf.InvalidProtocolBufferException;
@ -59,6 +60,7 @@ import com.google.protobuf.InvalidProtocolBufferException;
@InterfaceAudience.Public
@InterfaceStability.Evolving
public class FuzzyRowFilter extends FilterBase {
private static final boolean UNSAFE_UNALIGNED = UnsafeAvailChecker.unaligned();
private List<Pair<byte[], byte[]>> fuzzyKeysData;
private boolean done = false;
@ -93,7 +95,7 @@ public class FuzzyRowFilter extends FilterBase {
}
private void preprocessSearchKey(Pair<byte[], byte[]> p) {
if (UnsafeAccess.unaligned() == false) {
if (!UNSAFE_UNALIGNED) {
return;
}
byte[] key = p.getFirst();
@ -111,7 +113,7 @@ public class FuzzyRowFilter extends FilterBase {
* @return mask array
*/
private byte[] preprocessMask(byte[] mask) {
if (UnsafeAccess.unaligned() == false) {
if (!UNSAFE_UNALIGNED) {
return mask;
}
if (isPreprocessedMask(mask)) return mask;
@ -316,7 +318,7 @@ public class FuzzyRowFilter extends FilterBase {
static SatisfiesCode satisfies(boolean reverse, byte[] row, int offset, int length,
byte[] fuzzyKeyBytes, byte[] fuzzyKeyMeta) {
if (UnsafeAccess.unaligned() == false) {
if (!UNSAFE_UNALIGNED) {
return satisfiesNoUnsafe(reverse, row, offset, length, fuzzyKeyBytes, fuzzyKeyMeta);
}

View File

@ -41,8 +41,7 @@ public final class ByteBufferUtils {
private final static int VALUE_MASK = 0x7f;
private final static int NEXT_BIT_SHIFT = 7;
private final static int NEXT_BIT_MASK = 1 << 7;
private static final boolean UNSAFE_AVAIL = UnsafeAccess.isAvailable();
private static final boolean UNSAFE_UNALIGNED = UnsafeAccess.unaligned();
private static final boolean UNSAFE_AVAIL = UnsafeAvailChecker.isAvailable();
private ByteBufferUtils() {
}

View File

@ -24,14 +24,11 @@ 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;
@ -132,7 +129,8 @@ public class Bytes {
// SizeOf which uses java.lang.instrument says 24 bytes. (3 longs?)
public static final int ESTIMATED_HEAP_TAX = 16;
private static final boolean UNSAFE_UNALIGNED = UnsafeAvailChecker.unaligned();
/**
* Returns length of the byte array, returning 0 if the array is null.
* Useful for calculating sizes.
@ -604,7 +602,7 @@ public class Bytes {
if (length != SIZEOF_LONG || offset + length > bytes.length) {
throw explainWrongLengthOrOffset(bytes, offset, length, SIZEOF_LONG);
}
if (UnsafeComparer.unaligned()) {
if (UNSAFE_UNALIGNED) {
return toLongUnsafe(bytes, offset);
} else {
long l = 0;
@ -645,7 +643,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.unaligned()) {
if (UNSAFE_UNALIGNED) {
return putLongUnsafe(bytes, offset, val);
} else {
for(int i = offset + 7; i > offset; i--) {
@ -800,7 +798,7 @@ public class Bytes {
if (length != SIZEOF_INT || offset + length > bytes.length) {
throw explainWrongLengthOrOffset(bytes, offset, length, SIZEOF_INT);
}
if (UnsafeComparer.unaligned()) {
if (UNSAFE_UNALIGNED) {
return toIntUnsafe(bytes, offset);
} else {
int n = 0;
@ -896,7 +894,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.unaligned()) {
if (UNSAFE_UNALIGNED) {
return putIntUnsafe(bytes, offset, val);
} else {
for(int i= offset + 3; i > offset; i--) {
@ -970,7 +968,7 @@ public class Bytes {
if (length != SIZEOF_SHORT || offset + length > bytes.length) {
throw explainWrongLengthOrOffset(bytes, offset, length, SIZEOF_SHORT);
}
if (UnsafeComparer.unaligned()) {
if (UNSAFE_UNALIGNED) {
return toShortUnsafe(bytes, offset);
} else {
short n = 0;
@ -1008,7 +1006,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.unaligned()) {
if (UNSAFE_UNALIGNED) {
return putShortUnsafe(bytes, offset, val);
} else {
bytes[offset+1] = (byte) val;
@ -1315,13 +1313,12 @@ 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 {
if (UnsafeAccess.unaligned()) {
if (UNSAFE_UNALIGNED) {
theUnsafe = UnsafeAccess.theUnsafe;
} else {
// It doesn't matter what we throw;
@ -1335,7 +1332,6 @@ public class Bytes {
if (theUnsafe.arrayIndexScale(byte[].class) != 1) {
throw new AssertionError();
}
unaligned = UnsafeAccess.unaligned();
}
static final boolean littleEndian =
@ -1395,14 +1391,6 @@ 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.
*

View File

@ -18,9 +18,7 @@
package org.apache.hadoop.hbase.util;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.AccessController;
import java.security.PrivilegedAction;
@ -41,7 +39,6 @@ public final class UnsafeAccess {
private static final Log LOG = LogFactory.getLog(UnsafeAccess.class);
public static final Unsafe theUnsafe;
private static boolean unaligned = false;
/** The offset to the first element in a byte array. */
public static final int BYTE_ARRAY_BASE_OFFSET;
@ -67,34 +64,12 @@ 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; // FindBugs: Causes REC_CATCH_EXCEPTION. Suppressed.
}
} else{
BYTE_ARRAY_BASE_OFFSET = -1;
}
}
private UnsafeAccess(){}
public static boolean isAvailable() {
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;
}
// APIs to copy data. This will be direct memory location copy and will be much faster
/**

View File

@ -0,0 +1,86 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.util;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hbase.classification.InterfaceAudience;
@InterfaceAudience.Private
public class UnsafeAvailChecker {
private static final String CLASS_NAME = "sun.misc.Unsafe";
private static final Log LOG = LogFactory.getLog(UnsafeAvailChecker.class);
private static boolean avail = false;
private static boolean unaligned = false;
static {
avail = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
try {
Class<?> clazz = Class.forName(CLASS_NAME);
Field f = clazz.getDeclaredField("theUnsafe");
f.setAccessible(true);
return f.get(null) != null;
} catch (Throwable e) {
LOG.warn("sun.misc.Unsafe is not available/accessible", e);
}
return false;
}
});
// When Unsafe itself is not available/accessible consider unaligned as false.
if (avail) {
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) {
LOG.warn("java.nio.Bits#unaligned() check failed."
+ "Unsafe based read/write of primitive types won't be used", e);
}
}
}
/**
* @return true when running JVM is having sun's Unsafe package available in it and it is
* accessible.
*/
public static boolean isAvailable() {
return avail;
}
/**
* @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;
}
private UnsafeAvailChecker() {
// private constructor to avoid instantiation
}
}