001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.util; 019 020import java.lang.reflect.Field; 021import java.lang.reflect.Method; 022import java.security.AccessController; 023import java.security.PrivilegedAction; 024 025import org.apache.yetus.audience.InterfaceAudience; 026import org.slf4j.Logger; 027import org.slf4j.LoggerFactory; 028 029@InterfaceAudience.Private 030public class UnsafeAvailChecker { 031 032 private static final String CLASS_NAME = "sun.misc.Unsafe"; 033 private static final Logger LOG = LoggerFactory.getLogger(UnsafeAvailChecker.class); 034 private static boolean avail = false; 035 private static boolean unaligned = false; 036 037 static { 038 avail = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { 039 @Override 040 public Boolean run() { 041 try { 042 Class<?> clazz = Class.forName(CLASS_NAME); 043 Field f = clazz.getDeclaredField("theUnsafe"); 044 f.setAccessible(true); 045 Object theUnsafe = f.get(null); 046 if (theUnsafe == null) { 047 LOG.warn("Could not get static instance from sun.misc.Unsafe"); 048 return false; 049 } 050 // Check for availability of all methods used by UnsafeAccess 051 Method m; 052 try { 053 m = clazz.getDeclaredMethod("arrayBaseOffset", Class.class); 054 if (m == null) { 055 LOG.warn("sun.misc.Unsafe is missing arrayBaseOffset(Class)"); 056 return false; 057 } 058 m = clazz.getDeclaredMethod("copyMemory", Object.class, long.class, Object.class, 059 long.class, long.class); 060 if (m == null) { 061 LOG.warn("sun.misc.Unsafe is missing copyMemory(Object,long,Object,long,long)"); 062 return false; 063 } 064 m = clazz.getDeclaredMethod("getByte", Object.class, long.class); 065 if (m == null) { 066 LOG.warn("sun.misc.Unsafe is missing getByte(Object,long)"); 067 return false; 068 } 069 m = clazz.getDeclaredMethod("getShort", long.class); 070 if (m == null) { 071 LOG.warn("sun.misc.Unsafe is missing getShort(long)"); 072 return false; 073 } 074 m = clazz.getDeclaredMethod("getShort", Object.class, long.class); 075 if (m == null) { 076 LOG.warn("sun.misc.Unsafe is missing getShort(Object,long)"); 077 return false; 078 } 079 m = clazz.getDeclaredMethod("getInt", long.class); 080 if (m == null) { 081 LOG.warn("sun.misc.Unsafe is missing getInt(long)"); 082 return false; 083 } 084 m = clazz.getDeclaredMethod("getInt", Object.class, long.class); 085 if (m == null) { 086 LOG.warn("sun.misc.Unsafe is missing getInt(Object,long)"); 087 return false; 088 } 089 m = clazz.getDeclaredMethod("getLong", long.class); 090 if (m == null) { 091 LOG.warn("sun.misc.Unsafe is missing getLong(long)"); 092 return false; 093 } 094 m = clazz.getDeclaredMethod("getLong", Object.class, long.class); 095 if (m == null) { 096 LOG.warn("sun.misc.Unsafe is missing getLong(Object,long)"); 097 return false; 098 } 099 m = clazz.getDeclaredMethod("putByte", long.class, byte.class); 100 if (m == null) { 101 LOG.warn("sun.misc.Unsafe is missing putByte(long,byte)"); 102 return false; 103 } 104 m = clazz.getDeclaredMethod("putByte", Object.class, long.class, byte.class); 105 if (m == null) { 106 LOG.warn("sun.misc.Unsafe is missing putByte(Object,long,byte)"); 107 return false; 108 } 109 m = clazz.getDeclaredMethod("putShort", long.class, short.class); 110 if (m == null) { 111 LOG.warn("sun.misc.Unsafe is missing putShort(long,short)"); 112 return false; 113 } 114 m = clazz.getDeclaredMethod("putShort", Object.class, long.class, short.class); 115 if (m == null) { 116 LOG.warn("sun.misc.Unsafe is missing putShort(Object,long,short)"); 117 return false; 118 } 119 m = clazz.getDeclaredMethod("putInt", long.class, int.class); 120 if (m == null) { 121 LOG.warn("sun.misc.Unsafe is missing putInt(long,int)"); 122 return false; 123 } 124 m = clazz.getDeclaredMethod("putInt", Object.class, long.class, int.class); 125 if (m == null) { 126 LOG.warn("sun.misc.Unsafe is missing putInt(Object,long,int)"); 127 return false; 128 } 129 m = clazz.getDeclaredMethod("putLong", long.class, long.class); 130 if (m == null) { 131 LOG.warn("sun.misc.Unsafe is missing putLong(long,long)"); 132 return false; 133 } 134 m = clazz.getDeclaredMethod("putLong", Object.class, long.class, long.class); 135 if (m == null) { 136 LOG.warn("sun.misc.Unsafe is missing putLong(Object,long,long)"); 137 return false; 138 } 139 // theUnsafe is accessible and all methods are available 140 return true; 141 } catch (Throwable e) { 142 LOG.warn("sun.misc.Unsafe is missing one or more required methods", e); 143 } 144 } catch (Throwable e) { 145 LOG.warn("sun.misc.Unsafe is not available/accessible", e); 146 } 147 return false; 148 } 149 }); 150 // When Unsafe itself is not available/accessible consider unaligned as false. 151 if (avail) { 152 String arch = System.getProperty("os.arch"); 153 if ("ppc64".equals(arch) || "ppc64le".equals(arch) || "aarch64".equals(arch)) { 154 // java.nio.Bits.unaligned() wrongly returns false on ppc (JDK-8165231), 155 unaligned = true; 156 } else { 157 try { 158 // Using java.nio.Bits#unaligned() to check for unaligned-access capability 159 Class<?> clazz = Class.forName("java.nio.Bits"); 160 Method m = clazz.getDeclaredMethod("unaligned"); 161 m.setAccessible(true); 162 unaligned = (Boolean) m.invoke(null); 163 } catch (Exception e) { 164 LOG.warn("java.nio.Bits#unaligned() check failed." 165 + "Unsafe based read/write of primitive types won't be used", e); 166 } 167 } 168 } 169 } 170 171 /** 172 * @return true when running JVM is having sun's Unsafe package available in it and it is 173 * accessible. 174 */ 175 public static boolean isAvailable() { 176 return avail; 177 } 178 179 /** 180 * @return true when running JVM is having sun's Unsafe package available in it and underlying 181 * system having unaligned-access capability. 182 */ 183 public static boolean unaligned() { 184 return unaligned; 185 } 186 187 private UnsafeAvailChecker() { 188 // private constructor to avoid instantiation 189 } 190}