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
.commons
.logging
.Log
;
27 import org
.apache
.commons
.logging
.LogFactory
;
28 import org
.apache
.yetus
.audience
.InterfaceAudience
;
29 import org
.apache
.yetus
.audience
.InterfaceStability
;
30 import sun
.misc
.Unsafe
;
31 import sun
.nio
.ch
.DirectBuffer
;
33 @InterfaceAudience.Private
34 @InterfaceStability.Evolving
35 public final class UnsafeAccess
{
37 private static final Log LOG
= LogFactory
.getLog(UnsafeAccess
.class);
39 static final Unsafe theUnsafe
;
41 /** The offset to the first element in a byte array. */
42 public static final long BYTE_ARRAY_BASE_OFFSET
;
44 static final boolean littleEndian
= ByteOrder
.nativeOrder()
45 .equals(ByteOrder
.LITTLE_ENDIAN
);
47 // This number limits the number of bytes to copy per call to Unsafe's
48 // copyMemory method. A limit is imposed to allow for safepoint polling
49 // during a large copy
50 static final long UNSAFE_COPY_THRESHOLD
= 1024L * 1024L;
52 theUnsafe
= (Unsafe
) AccessController
.doPrivileged(new PrivilegedAction
<Object
>() {
56 Field f
= Unsafe
.class.getDeclaredField("theUnsafe");
57 f
.setAccessible(true);
59 } catch (Throwable e
) {
60 LOG
.warn("sun.misc.Unsafe is not accessible", e
);
66 if (theUnsafe
!= null) {
67 BYTE_ARRAY_BASE_OFFSET
= theUnsafe
.arrayBaseOffset(byte[].class);
69 BYTE_ARRAY_BASE_OFFSET
= -1;
73 private UnsafeAccess(){}
75 // APIs to read primitive data from a byte[] using Unsafe way
77 * Converts a byte array to a short value considering it was written in big-endian format.
78 * @param bytes byte array
79 * @param offset offset into array
80 * @return the short value
82 public static short toShort(byte[] bytes
, int offset
) {
84 return Short
.reverseBytes(theUnsafe
.getShort(bytes
, offset
+ BYTE_ARRAY_BASE_OFFSET
));
86 return theUnsafe
.getShort(bytes
, offset
+ BYTE_ARRAY_BASE_OFFSET
);
91 * Converts a byte array to an int value considering it was written in big-endian format.
92 * @param bytes byte array
93 * @param offset offset into array
94 * @return the int value
96 public static int toInt(byte[] bytes
, int offset
) {
98 return Integer
.reverseBytes(theUnsafe
.getInt(bytes
, offset
+ BYTE_ARRAY_BASE_OFFSET
));
100 return theUnsafe
.getInt(bytes
, offset
+ BYTE_ARRAY_BASE_OFFSET
);
105 * Converts a byte array to a long value considering it was written in big-endian format.
106 * @param bytes byte array
107 * @param offset offset into array
108 * @return the long value
110 public static long toLong(byte[] bytes
, int offset
) {
112 return Long
.reverseBytes(theUnsafe
.getLong(bytes
, offset
+ BYTE_ARRAY_BASE_OFFSET
));
114 return theUnsafe
.getLong(bytes
, offset
+ BYTE_ARRAY_BASE_OFFSET
);
118 // APIs to write primitive data to a byte[] using Unsafe way
120 * Put a short value out to the specified byte array position in big-endian format.
121 * @param bytes the byte array
122 * @param offset position in the array
123 * @param val short to write out
124 * @return incremented offset
126 public static int putShort(byte[] bytes
, int offset
, short val
) {
128 val
= Short
.reverseBytes(val
);
130 theUnsafe
.putShort(bytes
, offset
+ BYTE_ARRAY_BASE_OFFSET
, val
);
131 return offset
+ Bytes
.SIZEOF_SHORT
;
135 * Put an int value out to the specified byte array position in big-endian format.
136 * @param bytes the byte array
137 * @param offset position in the array
138 * @param val int to write out
139 * @return incremented offset
141 public static int putInt(byte[] bytes
, int offset
, int val
) {
143 val
= Integer
.reverseBytes(val
);
145 theUnsafe
.putInt(bytes
, offset
+ BYTE_ARRAY_BASE_OFFSET
, val
);
146 return offset
+ Bytes
.SIZEOF_INT
;
150 * Put a long value out to the specified byte array position in big-endian format.
151 * @param bytes the byte array
152 * @param offset position in the array
153 * @param val long to write out
154 * @return incremented offset
156 public static int putLong(byte[] bytes
, int offset
, long val
) {
158 val
= Long
.reverseBytes(val
);
160 theUnsafe
.putLong(bytes
, offset
+ BYTE_ARRAY_BASE_OFFSET
, val
);
161 return offset
+ Bytes
.SIZEOF_LONG
;
164 // APIs to read primitive data from a ByteBuffer using Unsafe way
166 * Reads a short value at the given buffer's offset considering it was written in big-endian
171 * @return short value at offset
173 public static short toShort(ByteBuffer buf
, int offset
) {
175 return Short
.reverseBytes(getAsShort(buf
, offset
));
177 return getAsShort(buf
, offset
);
181 * Reads a short value at the given Object's offset considering it was written in big-endian
185 * @return short value at offset
187 public static short toShort(Object ref
, long offset
) {
189 return Short
.reverseBytes(theUnsafe
.getShort(ref
, offset
));
191 return theUnsafe
.getShort(ref
, offset
);
195 * Reads bytes at the given offset as a short value.
198 * @return short value at offset
200 static short getAsShort(ByteBuffer buf
, int offset
) {
201 if (buf
.isDirect()) {
202 return theUnsafe
.getShort(((DirectBuffer
) buf
).address() + offset
);
204 return theUnsafe
.getShort(buf
.array(), BYTE_ARRAY_BASE_OFFSET
+ buf
.arrayOffset() + offset
);
208 * Reads an int value at the given buffer's offset considering it was written in big-endian
213 * @return int value at offset
215 public static int toInt(ByteBuffer buf
, int offset
) {
217 return Integer
.reverseBytes(getAsInt(buf
, offset
));
219 return getAsInt(buf
, offset
);
223 * Reads a int value at the given Object's offset considering it was written in big-endian
227 * @return int value at offset
229 public static int toInt(Object ref
, long offset
) {
231 return Integer
.reverseBytes(theUnsafe
.getInt(ref
, offset
));
233 return theUnsafe
.getInt(ref
, offset
);
237 * Reads bytes at the given offset as an int value.
240 * @return int value at offset
242 static int getAsInt(ByteBuffer buf
, int offset
) {
243 if (buf
.isDirect()) {
244 return theUnsafe
.getInt(((DirectBuffer
) buf
).address() + offset
);
246 return theUnsafe
.getInt(buf
.array(), BYTE_ARRAY_BASE_OFFSET
+ buf
.arrayOffset() + offset
);
250 * Reads a long value at the given buffer's offset considering it was written in big-endian
255 * @return long value at offset
257 public static long toLong(ByteBuffer buf
, int offset
) {
259 return Long
.reverseBytes(getAsLong(buf
, offset
));
261 return getAsLong(buf
, offset
);
265 * Reads a long value at the given Object's offset considering it was written in big-endian
269 * @return long value at offset
271 public static long toLong(Object ref
, long offset
) {
273 return Long
.reverseBytes(theUnsafe
.getLong(ref
, offset
));
275 return theUnsafe
.getLong(ref
, offset
);
279 * Reads bytes at the given offset as a long value.
282 * @return long value at offset
284 static long getAsLong(ByteBuffer buf
, int offset
) {
285 if (buf
.isDirect()) {
286 return theUnsafe
.getLong(((DirectBuffer
) buf
).address() + offset
);
288 return theUnsafe
.getLong(buf
.array(), BYTE_ARRAY_BASE_OFFSET
+ buf
.arrayOffset() + offset
);
292 * Put an int value out to the specified ByteBuffer offset in big-endian format.
293 * @param buf the ByteBuffer to write to
294 * @param offset offset in the ByteBuffer
295 * @param val int to write out
296 * @return incremented offset
298 public static int putInt(ByteBuffer buf
, int offset
, int val
) {
300 val
= Integer
.reverseBytes(val
);
302 if (buf
.isDirect()) {
303 theUnsafe
.putInt(((DirectBuffer
) buf
).address() + offset
, val
);
305 theUnsafe
.putInt(buf
.array(), offset
+ buf
.arrayOffset() + BYTE_ARRAY_BASE_OFFSET
, val
);
307 return offset
+ Bytes
.SIZEOF_INT
;
310 // APIs to copy data. This will be direct memory location copy and will be much faster
312 * Copies the bytes from given array's offset to length part into the given buffer.
319 public static void copy(byte[] src
, int srcOffset
, ByteBuffer dest
, int destOffset
, int length
) {
320 long destAddress
= destOffset
;
321 Object destBase
= null;
322 if (dest
.isDirect()) {
323 destAddress
= destAddress
+ ((DirectBuffer
) dest
).address();
325 destAddress
= destAddress
+ BYTE_ARRAY_BASE_OFFSET
+ dest
.arrayOffset();
326 destBase
= dest
.array();
328 long srcAddress
= (long) srcOffset
+ BYTE_ARRAY_BASE_OFFSET
;
329 unsafeCopy(src
, srcAddress
, destBase
, destAddress
, length
);
332 private static void unsafeCopy(Object src
, long srcAddr
, Object dst
, long destAddr
, long len
) {
334 long size
= (len
> UNSAFE_COPY_THRESHOLD
) ? UNSAFE_COPY_THRESHOLD
: len
;
335 theUnsafe
.copyMemory(src
, srcAddr
, dst
, destAddr
, len
);
343 * Copies specified number of bytes from given offset of {@code src} ByteBuffer to the
344 * {@code dest} array.
352 public static void copy(ByteBuffer src
, int srcOffset
, byte[] dest
, int destOffset
,
354 long srcAddress
= srcOffset
;
355 Object srcBase
= null;
356 if (src
.isDirect()) {
357 srcAddress
= srcAddress
+ ((DirectBuffer
) src
).address();
359 srcAddress
= srcAddress
+ BYTE_ARRAY_BASE_OFFSET
+ src
.arrayOffset();
360 srcBase
= src
.array();
362 long destAddress
= (long) destOffset
+ BYTE_ARRAY_BASE_OFFSET
;
363 unsafeCopy(srcBase
, srcAddress
, dest
, destAddress
, length
);
367 * Copies specified number of bytes from given offset of {@code src} buffer into the {@code dest}
376 public static void copy(ByteBuffer src
, int srcOffset
, ByteBuffer dest
, int destOffset
,
378 long srcAddress
, destAddress
;
379 Object srcBase
= null, destBase
= null;
380 if (src
.isDirect()) {
381 srcAddress
= srcOffset
+ ((DirectBuffer
) src
).address();
383 srcAddress
= (long) srcOffset
+ src
.arrayOffset() + BYTE_ARRAY_BASE_OFFSET
;
384 srcBase
= src
.array();
386 if (dest
.isDirect()) {
387 destAddress
= destOffset
+ ((DirectBuffer
) dest
).address();
389 destAddress
= (long) destOffset
+ BYTE_ARRAY_BASE_OFFSET
+ dest
.arrayOffset();
390 destBase
= dest
.array();
392 unsafeCopy(srcBase
, srcAddress
, destBase
, destAddress
, length
);
395 // APIs to add primitives to BBs
397 * Put a short value out to the specified BB position in big-endian format.
398 * @param buf the byte buffer
399 * @param offset position in the buffer
400 * @param val short to write out
401 * @return incremented offset
403 public static int putShort(ByteBuffer buf
, int offset
, short val
) {
405 val
= Short
.reverseBytes(val
);
407 if (buf
.isDirect()) {
408 theUnsafe
.putShort(((DirectBuffer
) buf
).address() + offset
, val
);
410 theUnsafe
.putShort(buf
.array(), BYTE_ARRAY_BASE_OFFSET
+ buf
.arrayOffset() + offset
, val
);
412 return offset
+ Bytes
.SIZEOF_SHORT
;
416 * Put a long value out to the specified BB position in big-endian format.
417 * @param buf the byte buffer
418 * @param offset position in the buffer
419 * @param val long to write out
420 * @return incremented offset
422 public static int putLong(ByteBuffer buf
, int offset
, long val
) {
424 val
= Long
.reverseBytes(val
);
426 if (buf
.isDirect()) {
427 theUnsafe
.putLong(((DirectBuffer
) buf
).address() + offset
, val
);
429 theUnsafe
.putLong(buf
.array(), BYTE_ARRAY_BASE_OFFSET
+ buf
.arrayOffset() + offset
, val
);
431 return offset
+ Bytes
.SIZEOF_LONG
;
434 * Put a byte value out to the specified BB position in big-endian format.
435 * @param buf the byte buffer
436 * @param offset position in the buffer
437 * @param b byte to write out
438 * @return incremented offset
440 public static int putByte(ByteBuffer buf
, int offset
, byte b
) {
441 if (buf
.isDirect()) {
442 theUnsafe
.putByte(((DirectBuffer
) buf
).address() + offset
, b
);
444 theUnsafe
.putByte(buf
.array(),
445 BYTE_ARRAY_BASE_OFFSET
+ buf
.arrayOffset() + offset
, b
);
451 * Returns the byte at the given offset
452 * @param buf the buffer to read
453 * @param offset the offset at which the byte has to be read
454 * @return the byte at the given offset
456 public static byte toByte(ByteBuffer buf
, int offset
) {
457 if (buf
.isDirect()) {
458 return theUnsafe
.getByte(((DirectBuffer
) buf
).address() + offset
);
460 return theUnsafe
.getByte(buf
.array(), BYTE_ARRAY_BASE_OFFSET
+ buf
.arrayOffset() + offset
);
465 * Returns the byte at the given offset of the object
468 * @return the byte at the given offset
470 public static byte toByte(Object ref
, long offset
) {
471 return theUnsafe
.getByte(ref
, offset
);