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.nio.ByteBuffer;
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  import org.apache.hadoop.hbase.classification.InterfaceStability;
29  
30  import sun.misc.Unsafe;
31  import sun.nio.ch.DirectBuffer;
32  
33  @InterfaceAudience.Private
34  @InterfaceStability.Evolving
35  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="REC_CATCH_EXCEPTION",
36    justification="If exception, presume unaligned")
37  public final class UnsafeAccess {
38  
39    private static final Log LOG = LogFactory.getLog(UnsafeAccess.class);
40  
41    public static final Unsafe theUnsafe;
42  
43    /** The offset to the first element in a byte array. */
44    public static final int BYTE_ARRAY_BASE_OFFSET;
45  
46    // This number limits the number of bytes to copy per call to Unsafe's
47    // copyMemory method. A limit is imposed to allow for safepoint polling
48    // during a large copy
49    static final long UNSAFE_COPY_THRESHOLD = 1024L * 1024L;
50    static {
51      theUnsafe = (Unsafe) AccessController.doPrivileged(new PrivilegedAction<Object>() {
52        @Override
53        public Object run() {
54          try {
55            Field f = Unsafe.class.getDeclaredField("theUnsafe");
56            f.setAccessible(true);
57            return f.get(null);
58          } catch (Throwable e) {
59            LOG.warn("sun.misc.Unsafe is not accessible", e);
60          }
61          return null;
62        }
63      });
64  
65      if(theUnsafe != null){
66        BYTE_ARRAY_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class);
67      } else{
68        BYTE_ARRAY_BASE_OFFSET = -1;
69      }
70    }
71  
72    private UnsafeAccess(){}
73  
74    // APIs to copy data. This will be direct memory location copy and will be much faster
75    /**
76     * Copies the bytes from given array's offset to length part into the given buffer.
77     * @param src
78     * @param srcOffset
79     * @param dest
80     * @param destOffset
81     * @param length
82     */
83    public static void copy(byte[] src, int srcOffset, ByteBuffer dest, int destOffset, int length) {
84      long destAddress = destOffset;
85      Object destBase = null;
86      if (dest.isDirect()) {
87        destAddress = destAddress + ((DirectBuffer) dest).address();
88      } else {
89        destAddress = destAddress + BYTE_ARRAY_BASE_OFFSET + dest.arrayOffset();
90        destBase = dest.array();
91      }
92      long srcAddress = srcOffset + BYTE_ARRAY_BASE_OFFSET;
93      unsafeCopy(src, srcAddress, destBase, destAddress, length);
94    }
95  
96    private static void unsafeCopy(Object src, long srcAddr, Object dst, long destAddr, long len) {
97      while (len > 0) {
98        long size = (len > UNSAFE_COPY_THRESHOLD) ? UNSAFE_COPY_THRESHOLD : len;
99        theUnsafe.copyMemory(src, srcAddr, dst, destAddr, len);
100       len -= size;
101       srcAddr += size;
102       destAddr += size;
103     }
104   }
105 
106   /**
107    * Copies specified number of bytes from given offset of {@code src} ByteBuffer to the
108    * {@code dest} array.
109    *
110    * @param src
111    * @param srcOffset
112    * @param dest
113    * @param destOffset
114    * @param length
115    */
116   public static void copy(ByteBuffer src, int srcOffset, byte[] dest, int destOffset,
117       int length) {
118     long srcAddress = srcOffset;
119     Object srcBase = null;
120     if (src.isDirect()) {
121       srcAddress = srcAddress + ((DirectBuffer) src).address();
122     } else {
123       srcAddress = srcAddress + BYTE_ARRAY_BASE_OFFSET + src.arrayOffset();
124       srcBase = src.array();
125     }
126     long destAddress = destOffset + BYTE_ARRAY_BASE_OFFSET;
127     unsafeCopy(srcBase, srcAddress, dest, destAddress, length);
128   }
129 
130   /**
131    * Copies specified number of bytes from given offset of {@code src} buffer into the {@code dest}
132    * buffer.
133    *
134    * @param src
135    * @param srcOffset
136    * @param dest
137    * @param destOffset
138    * @param length
139    */
140   public static void copy(ByteBuffer src, int srcOffset, ByteBuffer dest, int destOffset,
141       int length) {
142     long srcAddress, destAddress;
143     Object srcBase = null, destBase = null;
144     if (src.isDirect()) {
145       srcAddress = srcOffset + ((DirectBuffer) src).address();
146     } else {
147       srcAddress = srcOffset +  src.arrayOffset() + BYTE_ARRAY_BASE_OFFSET;
148       srcBase = src.array();
149     }
150     if (dest.isDirect()) {
151       destAddress = destOffset + ((DirectBuffer) dest).address();
152     } else {
153       destAddress = destOffset + BYTE_ARRAY_BASE_OFFSET + dest.arrayOffset();
154       destBase = dest.array();
155     }
156     unsafeCopy(srcBase, srcAddress, destBase, destAddress, length);
157   }
158 }