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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 package org
.apache
.hadoop
.hbase
.util
;
20 import java
.lang
.reflect
.Field
;
21 import java
.nio
.ByteBuffer
;
22 import java
.nio
.ByteOrder
;
23 import java
.security
.AccessController
;
24 import java
.security
.PrivilegedAction
;
26 import org
.apache
.yetus
.audience
.InterfaceAudience
;
27 import org
.apache
.yetus
.audience
.InterfaceStability
;
28 import org
.slf4j
.Logger
;
29 import org
.slf4j
.LoggerFactory
;
31 import sun
.misc
.Unsafe
;
32 import sun
.nio
.ch
.DirectBuffer
;
34 @InterfaceAudience.Private
35 @InterfaceStability.Evolving
36 public final class UnsafeAccess
{
38 private static final Logger LOG
= LoggerFactory
.getLogger(UnsafeAccess
.class);
40 public static final Unsafe theUnsafe
;
42 /** The offset to the first element in a byte array. */
43 public static final long BYTE_ARRAY_BASE_OFFSET
;
45 public static final boolean LITTLE_ENDIAN
= ByteOrder
.nativeOrder()
46 .equals(ByteOrder
.LITTLE_ENDIAN
);
48 // This number limits the number of bytes to copy per call to Unsafe's
49 // copyMemory method. A limit is imposed to allow for safepoint polling
50 // during a large copy
51 static final long UNSAFE_COPY_THRESHOLD
= 1024L * 1024L;
53 theUnsafe
= (Unsafe
) AccessController
.doPrivileged(new PrivilegedAction
<Object
>() {
57 Field f
= Unsafe
.class.getDeclaredField("theUnsafe");
58 f
.setAccessible(true);
60 } catch (Throwable e
) {
61 LOG
.warn("sun.misc.Unsafe is not accessible", e
);
67 if (theUnsafe
!= null) {
68 BYTE_ARRAY_BASE_OFFSET
= theUnsafe
.arrayBaseOffset(byte[].class);
70 BYTE_ARRAY_BASE_OFFSET
= -1;
74 private UnsafeAccess(){}
76 // APIs to read primitive data from a byte[] using Unsafe way
78 * Converts a byte array to a short value considering it was written in big-endian format.
79 * @param bytes byte array
80 * @param offset offset into array
81 * @return the short value
83 public static short toShort(byte[] bytes
, int offset
) {
85 return Short
.reverseBytes(theUnsafe
.getShort(bytes
, offset
+ BYTE_ARRAY_BASE_OFFSET
));
87 return theUnsafe
.getShort(bytes
, offset
+ BYTE_ARRAY_BASE_OFFSET
);
92 * Converts a byte array to an int value considering it was written in big-endian format.
93 * @param bytes byte array
94 * @param offset offset into array
95 * @return the int value
97 public static int toInt(byte[] bytes
, int offset
) {
99 return Integer
.reverseBytes(theUnsafe
.getInt(bytes
, offset
+ BYTE_ARRAY_BASE_OFFSET
));
101 return theUnsafe
.getInt(bytes
, offset
+ BYTE_ARRAY_BASE_OFFSET
);
106 * Converts a byte array to a long value considering it was written in big-endian format.
107 * @param bytes byte array
108 * @param offset offset into array
109 * @return the long value
111 public static long toLong(byte[] bytes
, int offset
) {
113 return Long
.reverseBytes(theUnsafe
.getLong(bytes
, offset
+ BYTE_ARRAY_BASE_OFFSET
));
115 return theUnsafe
.getLong(bytes
, offset
+ BYTE_ARRAY_BASE_OFFSET
);
119 // APIs to write primitive data to a byte[] using Unsafe way
121 * Put a short value out to the specified byte array position in big-endian format.
122 * @param bytes the byte array
123 * @param offset position in the array
124 * @param val short to write out
125 * @return incremented offset
127 public static int putShort(byte[] bytes
, int offset
, short val
) {
129 val
= Short
.reverseBytes(val
);
131 theUnsafe
.putShort(bytes
, offset
+ BYTE_ARRAY_BASE_OFFSET
, val
);
132 return offset
+ Bytes
.SIZEOF_SHORT
;
136 * Put an int value out to the specified byte array position in big-endian format.
137 * @param bytes the byte array
138 * @param offset position in the array
139 * @param val int to write out
140 * @return incremented offset
142 public static int putInt(byte[] bytes
, int offset
, int val
) {
144 val
= Integer
.reverseBytes(val
);
146 theUnsafe
.putInt(bytes
, offset
+ BYTE_ARRAY_BASE_OFFSET
, val
);
147 return offset
+ Bytes
.SIZEOF_INT
;
151 * Put a long value out to the specified byte array position in big-endian format.
152 * @param bytes the byte array
153 * @param offset position in the array
154 * @param val long to write out
155 * @return incremented offset
157 public static int putLong(byte[] bytes
, int offset
, long val
) {
159 val
= Long
.reverseBytes(val
);
161 theUnsafe
.putLong(bytes
, offset
+ BYTE_ARRAY_BASE_OFFSET
, val
);
162 return offset
+ Bytes
.SIZEOF_LONG
;
165 // APIs to read primitive data from a ByteBuffer using Unsafe way
167 * Reads a short value at the given buffer's offset considering it was written in big-endian
172 * @return short value at offset
174 public static short toShort(ByteBuffer buf
, int offset
) {
176 return Short
.reverseBytes(getAsShort(buf
, offset
));
178 return getAsShort(buf
, offset
);
182 * Reads a short value at the given Object's offset considering it was written in big-endian
186 * @return short value at offset
188 public static short toShort(Object ref
, long offset
) {
190 return Short
.reverseBytes(theUnsafe
.getShort(ref
, offset
));
192 return theUnsafe
.getShort(ref
, offset
);
196 * Reads bytes at the given offset as a short value.
199 * @return short value at offset
201 static short getAsShort(ByteBuffer buf
, int offset
) {
202 if (buf
.isDirect()) {
203 return theUnsafe
.getShort(((DirectBuffer
) buf
).address() + offset
);
205 return theUnsafe
.getShort(buf
.array(), BYTE_ARRAY_BASE_OFFSET
+ buf
.arrayOffset() + offset
);
209 * Reads an int value at the given buffer's offset considering it was written in big-endian
214 * @return int value at offset
216 public static int toInt(ByteBuffer buf
, int offset
) {
218 return Integer
.reverseBytes(getAsInt(buf
, offset
));
220 return getAsInt(buf
, offset
);
224 * Reads a int value at the given Object's offset considering it was written in big-endian
228 * @return int value at offset
230 public static int toInt(Object ref
, long offset
) {
232 return Integer
.reverseBytes(theUnsafe
.getInt(ref
, offset
));
234 return theUnsafe
.getInt(ref
, offset
);
238 * Reads bytes at the given offset as an int value.
241 * @return int value at offset
243 static int getAsInt(ByteBuffer buf
, int offset
) {
244 if (buf
.isDirect()) {
245 return theUnsafe
.getInt(((DirectBuffer
) buf
).address() + offset
);
247 return theUnsafe
.getInt(buf
.array(), BYTE_ARRAY_BASE_OFFSET
+ buf
.arrayOffset() + offset
);
251 * Reads a long value at the given buffer's offset considering it was written in big-endian
256 * @return long value at offset
258 public static long toLong(ByteBuffer buf
, int offset
) {
260 return Long
.reverseBytes(getAsLong(buf
, offset
));
262 return getAsLong(buf
, offset
);
266 * Reads a long value at the given Object's offset considering it was written in big-endian
270 * @return long value at offset
272 public static long toLong(Object ref
, long offset
) {
274 return Long
.reverseBytes(theUnsafe
.getLong(ref
, offset
));
276 return theUnsafe
.getLong(ref
, offset
);
280 * Reads bytes at the given offset as a long value.
283 * @return long value at offset
285 static long getAsLong(ByteBuffer buf
, int offset
) {
286 if (buf
.isDirect()) {
287 return theUnsafe
.getLong(((DirectBuffer
) buf
).address() + offset
);
289 return theUnsafe
.getLong(buf
.array(), BYTE_ARRAY_BASE_OFFSET
+ buf
.arrayOffset() + offset
);
293 * Put an int value out to the specified ByteBuffer offset in big-endian format.
294 * @param buf the ByteBuffer to write to
295 * @param offset offset in the ByteBuffer
296 * @param val int to write out
297 * @return incremented offset
299 public static int putInt(ByteBuffer buf
, int offset
, int val
) {
301 val
= Integer
.reverseBytes(val
);
303 if (buf
.isDirect()) {
304 theUnsafe
.putInt(((DirectBuffer
) buf
).address() + offset
, val
);
306 theUnsafe
.putInt(buf
.array(), offset
+ buf
.arrayOffset() + BYTE_ARRAY_BASE_OFFSET
, val
);
308 return offset
+ Bytes
.SIZEOF_INT
;
311 // APIs to copy data. This will be direct memory location copy and will be much faster
313 * Copies the bytes from given array's offset to length part into the given buffer.
320 public static void copy(byte[] src
, int srcOffset
, ByteBuffer dest
, int destOffset
, int length
) {
321 long destAddress
= destOffset
;
322 Object destBase
= null;
323 if (dest
.isDirect()) {
324 destAddress
= destAddress
+ ((DirectBuffer
) dest
).address();
326 destAddress
= destAddress
+ BYTE_ARRAY_BASE_OFFSET
+ dest
.arrayOffset();
327 destBase
= dest
.array();
329 long srcAddress
= srcOffset
+ BYTE_ARRAY_BASE_OFFSET
;
330 unsafeCopy(src
, srcAddress
, destBase
, destAddress
, length
);
333 private static void unsafeCopy(Object src
, long srcAddr
, Object dst
, long destAddr
, long len
) {
335 long size
= (len
> UNSAFE_COPY_THRESHOLD
) ? UNSAFE_COPY_THRESHOLD
: len
;
336 theUnsafe
.copyMemory(src
, srcAddr
, dst
, destAddr
, size
);
344 * Copies specified number of bytes from given offset of {@code src} ByteBuffer to the
345 * {@code dest} array.
353 public static void copy(ByteBuffer src
, int srcOffset
, byte[] dest
, int destOffset
,
355 long srcAddress
= srcOffset
;
356 Object srcBase
= null;
357 if (src
.isDirect()) {
358 srcAddress
= srcAddress
+ ((DirectBuffer
) src
).address();
360 srcAddress
= srcAddress
+ BYTE_ARRAY_BASE_OFFSET
+ src
.arrayOffset();
361 srcBase
= src
.array();
363 long destAddress
= destOffset
+ BYTE_ARRAY_BASE_OFFSET
;
364 unsafeCopy(srcBase
, srcAddress
, dest
, destAddress
, length
);
368 * Copies specified number of bytes from given offset of {@code src} buffer into the {@code dest}
377 public static void copy(ByteBuffer src
, int srcOffset
, ByteBuffer dest
, int destOffset
,
379 long srcAddress
, destAddress
;
380 Object srcBase
= null, destBase
= null;
381 if (src
.isDirect()) {
382 srcAddress
= srcOffset
+ ((DirectBuffer
) src
).address();
384 srcAddress
= (long) srcOffset
+ src
.arrayOffset() + BYTE_ARRAY_BASE_OFFSET
;
385 srcBase
= src
.array();
387 if (dest
.isDirect()) {
388 destAddress
= destOffset
+ ((DirectBuffer
) dest
).address();
390 destAddress
= destOffset
+ BYTE_ARRAY_BASE_OFFSET
+ dest
.arrayOffset();
391 destBase
= dest
.array();
393 unsafeCopy(srcBase
, srcAddress
, destBase
, destAddress
, length
);
396 // APIs to add primitives to BBs
398 * Put a short value out to the specified BB position in big-endian format.
399 * @param buf the byte buffer
400 * @param offset position in the buffer
401 * @param val short to write out
402 * @return incremented offset
404 public static int putShort(ByteBuffer buf
, int offset
, short val
) {
406 val
= Short
.reverseBytes(val
);
408 if (buf
.isDirect()) {
409 theUnsafe
.putShort(((DirectBuffer
) buf
).address() + offset
, val
);
411 theUnsafe
.putShort(buf
.array(), BYTE_ARRAY_BASE_OFFSET
+ buf
.arrayOffset() + offset
, val
);
413 return offset
+ Bytes
.SIZEOF_SHORT
;
417 * Put a long value out to the specified BB position in big-endian format.
418 * @param buf the byte buffer
419 * @param offset position in the buffer
420 * @param val long to write out
421 * @return incremented offset
423 public static int putLong(ByteBuffer buf
, int offset
, long val
) {
425 val
= Long
.reverseBytes(val
);
427 if (buf
.isDirect()) {
428 theUnsafe
.putLong(((DirectBuffer
) buf
).address() + offset
, val
);
430 theUnsafe
.putLong(buf
.array(), BYTE_ARRAY_BASE_OFFSET
+ buf
.arrayOffset() + offset
, val
);
432 return offset
+ Bytes
.SIZEOF_LONG
;
435 * Put a byte value out to the specified BB position in big-endian format.
436 * @param buf the byte buffer
437 * @param offset position in the buffer
438 * @param b byte to write out
439 * @return incremented offset
441 public static int putByte(ByteBuffer buf
, int offset
, byte b
) {
442 if (buf
.isDirect()) {
443 theUnsafe
.putByte(((DirectBuffer
) buf
).address() + offset
, b
);
445 theUnsafe
.putByte(buf
.array(),
446 BYTE_ARRAY_BASE_OFFSET
+ buf
.arrayOffset() + offset
, b
);
452 * Returns the byte at the given offset
453 * @param buf the buffer to read
454 * @param offset the offset at which the byte has to be read
455 * @return the byte at the given offset
457 public static byte toByte(ByteBuffer buf
, int offset
) {
458 if (buf
.isDirect()) {
459 return theUnsafe
.getByte(((DirectBuffer
) buf
).address() + offset
);
461 return theUnsafe
.getByte(buf
.array(), BYTE_ARRAY_BASE_OFFSET
+ buf
.arrayOffset() + offset
);
466 * Returns the byte at the given offset of the object
469 * @return the byte at the given offset
471 public static byte toByte(Object ref
, long offset
) {
472 return theUnsafe
.getByte(ref
, offset
);