blob: ffb07c52bb6ea2f821114355f9ebe8e1c47bd334 [file] [log] [blame]
/**
* 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.unsafe;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.function.BiConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Delegate all methods of {@link HBaseUnsafeInternal} and {@link HBaseSignalInternal} so we will
* not touch the actual {@code sun.misc.Unsafe} and {@code sun.misc.Signal} classes until we
* actually call the methods.
*/
public final class HBasePlatformDependent {
private static final String CLASS_NAME = "sun.misc.Unsafe";
private static final Logger LOG = LoggerFactory.getLogger(HBasePlatformDependent.class);
private static final boolean AVAIL;
private static final boolean UNALIGNED;
static {
AVAIL = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
return checkAvailable();
}
});
UNALIGNED = checkUnaligned();
}
private static boolean checkAvailable() {
try {
Class<?> clazz = Class.forName(CLASS_NAME);
Field f = clazz.getDeclaredField("theUnsafe");
f.setAccessible(true);
Object theUnsafe = f.get(null);
if (theUnsafe == null) {
LOG.warn("Could not get static instance from sun.misc.Unsafe");
return false;
}
// Check for availability of all methods used by UnsafeAccess
Method m;
try {
m = clazz.getDeclaredMethod("arrayBaseOffset", Class.class);
if (m == null) {
LOG.warn("sun.misc.Unsafe is missing arrayBaseOffset(Class)");
return false;
}
m = clazz.getDeclaredMethod("copyMemory", Object.class, long.class, Object.class,
long.class, long.class);
if (m == null) {
LOG.warn("sun.misc.Unsafe is missing copyMemory(Object,long,Object,long,long)");
return false;
}
m = clazz.getDeclaredMethod("getByte", Object.class, long.class);
if (m == null) {
LOG.warn("sun.misc.Unsafe is missing getByte(Object,long)");
return false;
}
m = clazz.getDeclaredMethod("getShort", long.class);
if (m == null) {
LOG.warn("sun.misc.Unsafe is missing getShort(long)");
return false;
}
m = clazz.getDeclaredMethod("getShort", Object.class, long.class);
if (m == null) {
LOG.warn("sun.misc.Unsafe is missing getShort(Object,long)");
return false;
}
m = clazz.getDeclaredMethod("getInt", long.class);
if (m == null) {
LOG.warn("sun.misc.Unsafe is missing getInt(long)");
return false;
}
m = clazz.getDeclaredMethod("getInt", Object.class, long.class);
if (m == null) {
LOG.warn("sun.misc.Unsafe is missing getInt(Object,long)");
return false;
}
m = clazz.getDeclaredMethod("getLong", long.class);
if (m == null) {
LOG.warn("sun.misc.Unsafe is missing getLong(long)");
return false;
}
m = clazz.getDeclaredMethod("getLong", Object.class, long.class);
if (m == null) {
LOG.warn("sun.misc.Unsafe is missing getLong(Object,long)");
return false;
}
m = clazz.getDeclaredMethod("putByte", long.class, byte.class);
if (m == null) {
LOG.warn("sun.misc.Unsafe is missing putByte(long,byte)");
return false;
}
m = clazz.getDeclaredMethod("putByte", Object.class, long.class, byte.class);
if (m == null) {
LOG.warn("sun.misc.Unsafe is missing putByte(Object,long,byte)");
return false;
}
m = clazz.getDeclaredMethod("putShort", long.class, short.class);
if (m == null) {
LOG.warn("sun.misc.Unsafe is missing putShort(long,short)");
return false;
}
m = clazz.getDeclaredMethod("putShort", Object.class, long.class, short.class);
if (m == null) {
LOG.warn("sun.misc.Unsafe is missing putShort(Object,long,short)");
return false;
}
m = clazz.getDeclaredMethod("putInt", long.class, int.class);
if (m == null) {
LOG.warn("sun.misc.Unsafe is missing putInt(long,int)");
return false;
}
m = clazz.getDeclaredMethod("putInt", Object.class, long.class, int.class);
if (m == null) {
LOG.warn("sun.misc.Unsafe is missing putInt(Object,long,int)");
return false;
}
m = clazz.getDeclaredMethod("putLong", long.class, long.class);
if (m == null) {
LOG.warn("sun.misc.Unsafe is missing putLong(long,long)");
return false;
}
m = clazz.getDeclaredMethod("putLong", Object.class, long.class, long.class);
if (m == null) {
LOG.warn("sun.misc.Unsafe is missing putLong(Object,long,long)");
return false;
}
// theUnsafe is accessible and all methods are available
return true;
} catch (Throwable e) {
LOG.warn("sun.misc.Unsafe is missing one or more required methods", e);
}
} catch (Throwable e) {
LOG.warn("sun.misc.Unsafe is not available/accessible", e);
}
return false;
}
private static boolean checkUnaligned() {
// When Unsafe itself is not available/accessible consider unaligned as false.
if (!AVAIL) {
return false;
}
String arch = System.getProperty("os.arch");
if ("ppc64".equals(arch) || "ppc64le".equals(arch) || "aarch64".equals(arch)) {
// java.nio.Bits.unaligned() wrongly returns false on ppc (JDK-8165231),
return true;
}
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);
return (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 false;
}
/**
* @return true when running JVM is having sun's Unsafe package available in it and it is
* accessible.
*/
public static boolean isUnsafeAvailable() {
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 HBasePlatformDependent() {
// private constructor to avoid instantiation
}
public static int getInt(Object o, long offset) {
return HBaseUnsafeInternal.getInt(o, offset);
}
public static void putInt(Object o, long offset, int x) {
HBaseUnsafeInternal.putInt(o, offset, x);
}
public static Object getObject(Object o, long offset) {
return HBaseUnsafeInternal.getObject(o, offset);
}
public static void putObject(Object o, long offset, Object x) {
HBaseUnsafeInternal.putObject(o, offset, x);
}
public static boolean getBoolean(Object o, long offset) {
return HBaseUnsafeInternal.getBoolean(o, offset);
}
public static void putBoolean(Object o, long offset, boolean x) {
HBaseUnsafeInternal.putBoolean(o, offset, x);
}
public static byte getByte(Object o, long offset) {
return HBaseUnsafeInternal.getByte(o, offset);
}
public static void putByte(Object o, long offset, byte x) {
HBaseUnsafeInternal.putByte(o, offset, x);
}
public static short getShort(Object o, long offset) {
return HBaseUnsafeInternal.getShort(o, offset);
}
public static void putShort(Object o, long offset, short x) {
HBaseUnsafeInternal.putShort(o, offset, x);
}
public static char getChar(Object o, long offset) {
return HBaseUnsafeInternal.getChar(o, offset);
}
public static void putChar(Object o, long offset, char x) {
HBaseUnsafeInternal.putChar(o, offset, x);
}
public static long getLong(Object o, long offset) {
return HBaseUnsafeInternal.getLong(o, offset);
}
public static void putLong(Object o, long offset, long x) {
HBaseUnsafeInternal.putLong(o, offset, x);
}
public static float getFloat(Object o, long offset) {
return HBaseUnsafeInternal.getFloat(o, offset);
}
public static void putFloat(Object o, long offset, float x) {
HBaseUnsafeInternal.putFloat(o, offset, x);
}
public static double getDouble(Object o, long offset) {
return HBaseUnsafeInternal.getDouble(o, offset);
}
public static void putDouble(Object o, long offset, double x) {
HBaseUnsafeInternal.putDouble(o, offset, x);
}
public static byte getByte(long address) {
return HBaseUnsafeInternal.getByte(address);
}
public static void putByte(long address, byte x) {
HBaseUnsafeInternal.putByte(address, x);
}
public static short getShort(long address) {
return HBaseUnsafeInternal.getShort(address);
}
public static void putShort(long address, short x) {
HBaseUnsafeInternal.putShort(address, x);
}
public static char getChar(long address) {
return HBaseUnsafeInternal.getChar(address);
}
public static void putChar(long address, char x) {
HBaseUnsafeInternal.putChar(address, x);
}
public static int getInt(long address) {
return HBaseUnsafeInternal.getInt(address);
}
public static void putInt(long address, int x) {
HBaseUnsafeInternal.putInt(address, x);
}
public static long getLong(long address) {
return HBaseUnsafeInternal.getLong(address);
}
public static void putLong(long address, long x) {
HBaseUnsafeInternal.putLong(address, x);
}
public static float getFloat(long address) {
return HBaseUnsafeInternal.getFloat(address);
}
public static void putFloat(long address, float x) {
HBaseUnsafeInternal.putFloat(address, x);
}
public static double getDouble(long address) {
return HBaseUnsafeInternal.getDouble(address);
}
public static void putDouble(long address, double x) {
HBaseUnsafeInternal.putDouble(address, x);
}
public static long getAddress(long address) {
return HBaseUnsafeInternal.getAddress(address);
}
public static void putAddress(long address, long x) {
HBaseUnsafeInternal.putAddress(address, x);
}
public static long allocateMemory(long bytes) {
return HBaseUnsafeInternal.allocateMemory(bytes);
}
public static long reallocateMemory(long address, long bytes) {
return HBaseUnsafeInternal.reallocateMemory(address, bytes);
}
public static void setMemory(Object o, long offset, long bytes, byte value) {
HBaseUnsafeInternal.setMemory(o, offset, bytes, value);
}
public static void setMemory(long address, long bytes, byte value) {
HBaseUnsafeInternal.setMemory(address, bytes, value);
}
public static void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset,
long bytes) {
HBaseUnsafeInternal.copyMemory(srcBase, srcOffset, destBase, destOffset, bytes);
}
public static void copyMemory(long srcAddress, long destAddress, long bytes) {
HBaseUnsafeInternal.copyMemory(srcAddress, destAddress, bytes);
}
public static void freeMemory(long address) {
HBaseUnsafeInternal.freeMemory(address);
}
public static long staticFieldOffset(Field f) {
return HBaseUnsafeInternal.staticFieldOffset(f);
}
public static long objectFieldOffset(Field f) {
return HBaseUnsafeInternal.objectFieldOffset(f);
}
public static Object staticFieldBase(Field f) {
return HBaseUnsafeInternal.staticFieldBase(f);
}
public static boolean shouldBeInitialized(Class<?> c) {
return HBaseUnsafeInternal.shouldBeInitialized(c);
}
public static void ensureClassInitialized(Class<?> c) {
HBaseUnsafeInternal.ensureClassInitialized(c);
}
public static int arrayBaseOffset(Class<?> arrayClass) {
return HBaseUnsafeInternal.arrayBaseOffset(arrayClass);
}
public static int arrayIndexScale(Class<?> arrayClass) {
return HBaseUnsafeInternal.arrayIndexScale(arrayClass);
}
public static int addressSize() {
return HBaseUnsafeInternal.addressSize();
}
public static int pageSize() {
return HBaseUnsafeInternal.pageSize();
}
public static Class<?> defineClass(String name, byte[] b, int off, int len, ClassLoader loader,
ProtectionDomain protectionDomain) {
return HBaseUnsafeInternal.defineClass(name, b, off, len, loader, protectionDomain);
}
public static Class<?> defineAnonymousClass(Class<?> hostClass, byte[] data, Object[] cpPatches) {
return HBaseUnsafeInternal.defineAnonymousClass(hostClass, data, cpPatches);
}
public static Object allocateInstance(Class<?> cls) throws InstantiationException {
return HBaseUnsafeInternal.allocateInstance(cls);
}
public static void throwException(Throwable ee) {
HBaseUnsafeInternal.throwException(ee);
}
public static boolean compareAndSwapObject(Object o, long offset, Object expected, Object x) {
return HBaseUnsafeInternal.compareAndSwapObject(o, offset, expected, x);
}
public static boolean compareAndSwapInt(Object o, long offset, int expected, int x) {
return HBaseUnsafeInternal.compareAndSwapInt(o, offset, expected, x);
}
public static boolean compareAndSwapLong(Object o, long offset, long expected, long x) {
return HBaseUnsafeInternal.compareAndSwapLong(o, offset, expected, x);
}
public static Object getObjectVolatile(Object o, long offset) {
return HBaseUnsafeInternal.getObjectVolatile(o, offset);
}
public static void putObjectVolatile(Object o, long offset, Object x) {
HBaseUnsafeInternal.putObjectVolatile(o, offset, x);
}
public static int getIntVolatile(Object o, long offset) {
return HBaseUnsafeInternal.getIntVolatile(o, offset);
}
public static void putIntVolatile(Object o, long offset, int x) {
HBaseUnsafeInternal.putIntVolatile(o, offset, x);
}
public static boolean getBooleanVolatile(Object o, long offset) {
return HBaseUnsafeInternal.getBooleanVolatile(o, offset);
}
public static void putBooleanVolatile(Object o, long offset, boolean x) {
HBaseUnsafeInternal.putBooleanVolatile(o, offset, x);
}
public static byte getByteVolatile(Object o, long offset) {
return HBaseUnsafeInternal.getByteVolatile(o, offset);
}
public static void putByteVolatile(Object o, long offset, byte x) {
HBaseUnsafeInternal.putByteVolatile(o, offset, x);
}
public static short getShortVolatile(Object o, long offset) {
return HBaseUnsafeInternal.getShortVolatile(o, offset);
}
public static void putShortVolatile(Object o, long offset, short x) {
HBaseUnsafeInternal.putShortVolatile(o, offset, x);
}
public static char getCharVolatile(Object o, long offset) {
return HBaseUnsafeInternal.getCharVolatile(o, offset);
}
public static void putCharVolatile(Object o, long offset, char x) {
HBaseUnsafeInternal.putCharVolatile(o, offset, x);
}
public static long getLongVolatile(Object o, long offset) {
return HBaseUnsafeInternal.getLongVolatile(o, offset);
}
public static void putLongVolatile(Object o, long offset, long x) {
HBaseUnsafeInternal.putLongVolatile(o, offset, x);
}
public static float getFloatVolatile(Object o, long offset) {
return HBaseUnsafeInternal.getFloatVolatile(o, offset);
}
public static void putFloatVolatile(Object o, long offset, float x) {
HBaseUnsafeInternal.putFloatVolatile(o, offset, x);
}
public static double getDoubleVolatile(Object o, long offset) {
return HBaseUnsafeInternal.getDoubleVolatile(o, offset);
}
public static void putDoubleVolatile(Object o, long offset, double x) {
HBaseUnsafeInternal.putDoubleVolatile(o, offset, x);
}
public static void putOrderedObject(Object o, long offset, Object x) {
HBaseUnsafeInternal.putOrderedObject(o, offset, x);
}
public static void putOrderedInt(Object o, long offset, int x) {
HBaseUnsafeInternal.putOrderedInt(o, offset, x);
}
public static void putOrderedLong(Object o, long offset, long x) {
HBaseUnsafeInternal.putOrderedLong(o, offset, x);
}
public static void unpark(Object thread) {
HBaseUnsafeInternal.unpark(thread);
}
public static void park(boolean isAbsolute, long time) {
HBaseUnsafeInternal.park(isAbsolute, time);
}
public static int getLoadAverage(double[] loadavg, int nelems) {
return HBaseUnsafeInternal.getLoadAverage(loadavg, nelems);
}
public static int getAndAddInt(Object o, long offset, int delta) {
return HBaseUnsafeInternal.getAndAddInt(o, offset, delta);
}
public static long getAndAddLong(Object o, long offset, long delta) {
return HBaseUnsafeInternal.getAndAddLong(o, offset, delta);
}
public static int getAndSetInt(Object o, long offset, int newValue) {
return HBaseUnsafeInternal.getAndSetInt(o, offset, newValue);
}
public static long getAndSetLong(Object o, long offset, long newValue) {
return HBaseUnsafeInternal.getAndSetLong(o, offset, newValue);
}
public static Object getAndSetObject(Object o, long offset, Object newValue) {
return HBaseUnsafeInternal.getAndSetObject(o, offset, newValue);
}
public static void loadFence() {
HBaseUnsafeInternal.loadFence();
}
public static void storeFence() {
HBaseUnsafeInternal.storeFence();
}
public static void fullFence() {
HBaseUnsafeInternal.fullFence();
}
/**
* Delegate {@code sun.misc.Signal}.
* @param signal the name of the signal, such as 'HUP'.
* @param handler the handler of the signal, the first parameter is the number of the signal,
* while the second one is the name of the sinal.
*/
public static void handle(String signal, BiConsumer<Integer, String> handler) {
HBaseSignalInternal.handle(signal, handler);
}
}