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          return f.get(null) != null;
046        } catch (Throwable e) {
047          LOG.warn("sun.misc.Unsafe is not available/accessible", e);
048        }
049        return false;
050      }
051    });
052    // When Unsafe itself is not available/accessible consider unaligned as false.
053    if (avail) {
054      String arch = System.getProperty("os.arch");
055      if ("ppc64".equals(arch) || "ppc64le".equals(arch) || "aarch64".equals(arch)) {
056        // java.nio.Bits.unaligned() wrongly returns false on ppc (JDK-8165231),
057        unaligned = true;
058      } else {
059        try {
060          // Using java.nio.Bits#unaligned() to check for unaligned-access capability
061          Class<?> clazz = Class.forName("java.nio.Bits");
062          Method m = clazz.getDeclaredMethod("unaligned");
063          m.setAccessible(true);
064          unaligned = (Boolean) m.invoke(null);
065        } catch (Exception e) {
066          LOG.warn("java.nio.Bits#unaligned() check failed."
067              + "Unsafe based read/write of primitive types won't be used", e);
068        }
069      }
070    }
071  }
072
073  /**
074   * @return true when running JVM is having sun's Unsafe package available in it and it is
075   *         accessible.
076   */
077  public static boolean isAvailable() {
078    return avail;
079  }
080
081  /**
082   * @return true when running JVM is having sun's Unsafe package available in it and underlying
083   *         system having unaligned-access capability.
084   */
085  public static boolean unaligned() {
086    return unaligned;
087  }
088
089  private UnsafeAvailChecker() {
090    // private constructor to avoid instantiation
091  }
092}