HBASE-19497 Fix findbugs and error-prone warnings in hbase-common (branch-2)
[hbase.git] / hbase-common / src / main / java / org / apache / hadoop / hbase / util / UnsafeAccess.java
blob50fef6d823e0bd9ba78089beda7f92972b47044f
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
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;
51 static {
52 theUnsafe = (Unsafe) AccessController.doPrivileged(new PrivilegedAction<Object>() {
53 @Override
54 public Object run() {
55 try {
56 Field f = Unsafe.class.getDeclaredField("theUnsafe");
57 f.setAccessible(true);
58 return f.get(null);
59 } catch (Throwable e) {
60 LOG.warn("sun.misc.Unsafe is not accessible", e);
62 return null;
64 });
66 if (theUnsafe != null) {
67 BYTE_ARRAY_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class);
68 } else{
69 BYTE_ARRAY_BASE_OFFSET = -1;
73 private UnsafeAccess(){}
75 // APIs to read primitive data from a byte[] using Unsafe way
76 /**
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) {
83 if (littleEndian) {
84 return Short.reverseBytes(theUnsafe.getShort(bytes, offset + BYTE_ARRAY_BASE_OFFSET));
85 } else {
86 return theUnsafe.getShort(bytes, offset + BYTE_ARRAY_BASE_OFFSET);
90 /**
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) {
97 if (littleEndian) {
98 return Integer.reverseBytes(theUnsafe.getInt(bytes, offset + BYTE_ARRAY_BASE_OFFSET));
99 } else {
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) {
111 if (littleEndian) {
112 return Long.reverseBytes(theUnsafe.getLong(bytes, offset + BYTE_ARRAY_BASE_OFFSET));
113 } else {
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) {
127 if (littleEndian) {
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) {
142 if (littleEndian) {
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) {
157 if (littleEndian) {
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
167 * format.
169 * @param buf
170 * @param offset
171 * @return short value at offset
173 public static short toShort(ByteBuffer buf, int offset) {
174 if (littleEndian) {
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
182 * format.
183 * @param ref
184 * @param offset
185 * @return short value at offset
187 public static short toShort(Object ref, long offset) {
188 if (littleEndian) {
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.
196 * @param buf
197 * @param offset
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
209 * format.
211 * @param buf
212 * @param offset
213 * @return int value at offset
215 public static int toInt(ByteBuffer buf, int offset) {
216 if (littleEndian) {
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
224 * format.
225 * @param ref
226 * @param offset
227 * @return int value at offset
229 public static int toInt(Object ref, long offset) {
230 if (littleEndian) {
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.
238 * @param buf
239 * @param offset
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
251 * format.
253 * @param buf
254 * @param offset
255 * @return long value at offset
257 public static long toLong(ByteBuffer buf, int offset) {
258 if (littleEndian) {
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
266 * format.
267 * @param ref
268 * @param offset
269 * @return long value at offset
271 public static long toLong(Object ref, long offset) {
272 if (littleEndian) {
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.
280 * @param buf
281 * @param offset
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) {
299 if (littleEndian) {
300 val = Integer.reverseBytes(val);
302 if (buf.isDirect()) {
303 theUnsafe.putInt(((DirectBuffer) buf).address() + offset, val);
304 } else {
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.
313 * @param src
314 * @param srcOffset
315 * @param dest
316 * @param destOffset
317 * @param length
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();
324 } else {
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) {
333 while (len > 0) {
334 long size = (len > UNSAFE_COPY_THRESHOLD) ? UNSAFE_COPY_THRESHOLD : len;
335 theUnsafe.copyMemory(src, srcAddr, dst, destAddr, len);
336 len -= size;
337 srcAddr += size;
338 destAddr += size;
343 * Copies specified number of bytes from given offset of {@code src} ByteBuffer to the
344 * {@code dest} array.
346 * @param src
347 * @param srcOffset
348 * @param dest
349 * @param destOffset
350 * @param length
352 public static void copy(ByteBuffer src, int srcOffset, byte[] dest, int destOffset,
353 int length) {
354 long srcAddress = srcOffset;
355 Object srcBase = null;
356 if (src.isDirect()) {
357 srcAddress = srcAddress + ((DirectBuffer) src).address();
358 } else {
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}
368 * buffer.
370 * @param src
371 * @param srcOffset
372 * @param dest
373 * @param destOffset
374 * @param length
376 public static void copy(ByteBuffer src, int srcOffset, ByteBuffer dest, int destOffset,
377 int length) {
378 long srcAddress, destAddress;
379 Object srcBase = null, destBase = null;
380 if (src.isDirect()) {
381 srcAddress = srcOffset + ((DirectBuffer) src).address();
382 } else {
383 srcAddress = (long) srcOffset + src.arrayOffset() + BYTE_ARRAY_BASE_OFFSET;
384 srcBase = src.array();
386 if (dest.isDirect()) {
387 destAddress = destOffset + ((DirectBuffer) dest).address();
388 } else {
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) {
404 if (littleEndian) {
405 val = Short.reverseBytes(val);
407 if (buf.isDirect()) {
408 theUnsafe.putShort(((DirectBuffer) buf).address() + offset, val);
409 } else {
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) {
423 if (littleEndian) {
424 val = Long.reverseBytes(val);
426 if (buf.isDirect()) {
427 theUnsafe.putLong(((DirectBuffer) buf).address() + offset, val);
428 } else {
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);
443 } else {
444 theUnsafe.putByte(buf.array(),
445 BYTE_ARRAY_BASE_OFFSET + buf.arrayOffset() + offset, b);
447 return offset + 1;
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);
459 } else {
460 return theUnsafe.getByte(buf.array(), BYTE_ARRAY_BASE_OFFSET + buf.arrayOffset() + offset);
465 * Returns the byte at the given offset of the object
466 * @param ref
467 * @param offset
468 * @return the byte at the given offset
470 public static byte toByte(Object ref, long offset) {
471 return theUnsafe.getByte(ref, offset);