View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.hadoop.hbase.util;
19  
20  import java.lang.reflect.Field;
21  import java.lang.reflect.Method;
22  import java.security.AccessController;
23  import java.security.PrivilegedAction;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.apache.hadoop.hbase.classification.InterfaceAudience;
28  
29  @InterfaceAudience.Private
30  public class UnsafeAvailChecker {
31  
32    private static final String CLASS_NAME = "sun.misc.Unsafe";
33    private static final Log LOG = LogFactory.getLog(UnsafeAvailChecker.class);
34    private static boolean avail = false;
35    private static boolean unaligned = false;
36  
37    static {
38      avail = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
39        @Override
40        public Boolean run() {
41          try {
42            Class<?> clazz = Class.forName(CLASS_NAME);
43            Field f = clazz.getDeclaredField("theUnsafe");
44            f.setAccessible(true);
45            Object theUnsafe = f.get(null);
46            if (theUnsafe == null) {
47              LOG.warn("Could not get static instance from sun.misc.Unsafe");
48              return false;
49            }
50            // Check for availability of all methods used by UnsafeAccess
51            Method m;
52            try {
53              m = clazz.getDeclaredMethod("arrayBaseOffset", Class.class);
54              if (m == null) {
55                LOG.warn("sun.misc.Unsafe is missing arrayBaseOffset(Class)");
56                return false;
57              }
58              m = clazz.getDeclaredMethod("copyMemory", Object.class, long.class, Object.class,
59                long.class, long.class);
60              if (m == null) {
61                LOG.warn("sun.misc.Unsafe is missing copyMemory(Object,long,Object,long,long)");
62                return false;
63              }
64              m = clazz.getDeclaredMethod("getByte", Object.class, long.class);
65              if (m == null) {
66                LOG.warn("sun.misc.Unsafe is missing getByte(Object,long)");
67                return false;
68              }
69              m = clazz.getDeclaredMethod("getShort", long.class);
70              if (m == null) {
71                LOG.warn("sun.misc.Unsafe is missing getShort(long)");
72                return false;
73              }
74              m = clazz.getDeclaredMethod("getShort", Object.class, long.class);
75              if (m == null) {
76                LOG.warn("sun.misc.Unsafe is missing getShort(Object,long)");
77                return false;
78              }
79              m = clazz.getDeclaredMethod("getInt", long.class);
80              if (m == null) {
81                LOG.warn("sun.misc.Unsafe is missing getInt(long)");
82                return false;
83              }
84              m = clazz.getDeclaredMethod("getInt", Object.class, long.class);
85              if (m == null) {
86                LOG.warn("sun.misc.Unsafe is missing getInt(Object,long)");
87                return false;
88              }
89              m = clazz.getDeclaredMethod("getLong", long.class);
90              if (m == null) {
91                LOG.warn("sun.misc.Unsafe is missing getLong(long)");
92                return false;
93              }
94              m = clazz.getDeclaredMethod("getLong", Object.class, long.class);
95              if (m == null) {
96                LOG.warn("sun.misc.Unsafe is missing getLong(Object,long)");
97                return false;
98              }
99              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)) {
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 }