1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.hadoop.hbase.util;
19
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;
25
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28 import org.apache.hadoop.hbase.classification.InterfaceAudience;
29 import org.apache.hadoop.hbase.classification.InterfaceStability;
30
31 import sun.misc.Unsafe;
32 import sun.nio.ch.DirectBuffer;
33
34 @InterfaceAudience.Private
35 @InterfaceStability.Evolving
36 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="REC_CATCH_EXCEPTION",
37 justification="If exception, presume unaligned")
38 public final class UnsafeAccess {
39
40 private static final Log LOG = LogFactory.getLog(UnsafeAccess.class);
41
42 public static final Unsafe theUnsafe;
43
44
45 public static final long BYTE_ARRAY_BASE_OFFSET;
46
47 public static final boolean LITTLE_ENDIAN =
48 ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN);
49
50
51
52
53 static final long UNSAFE_COPY_THRESHOLD = 1024L * 1024L;
54 static {
55 theUnsafe = (Unsafe) AccessController.doPrivileged(new PrivilegedAction<Object>() {
56 @Override
57 public Object run() {
58 try {
59 Field f = Unsafe.class.getDeclaredField("theUnsafe");
60 f.setAccessible(true);
61 return f.get(null);
62 } catch (Throwable e) {
63 LOG.warn("sun.misc.Unsafe is not accessible", e);
64 }
65 return null;
66 }
67 });
68
69 if(theUnsafe != null){
70 BYTE_ARRAY_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class);
71 } else{
72 BYTE_ARRAY_BASE_OFFSET = -1;
73 }
74 }
75
76 private UnsafeAccess(){}
77
78
79
80
81
82
83
84
85
86
87 public static void copy(byte[] src, int srcOffset, ByteBuffer dest, int destOffset, int length) {
88 long destAddress = destOffset;
89 Object destBase = null;
90 if (dest.isDirect()) {
91 destAddress = destAddress + ((DirectBuffer) dest).address();
92 } else {
93 destAddress = destAddress + BYTE_ARRAY_BASE_OFFSET + dest.arrayOffset();
94 destBase = dest.array();
95 }
96 long srcAddress = (long) srcOffset + BYTE_ARRAY_BASE_OFFSET;
97 unsafeCopy(src, srcAddress, destBase, destAddress, length);
98 }
99
100 private static void unsafeCopy(Object src, long srcAddr, Object dst, long destAddr, long len) {
101 while (len > 0) {
102 long size = (len > UNSAFE_COPY_THRESHOLD) ? UNSAFE_COPY_THRESHOLD : len;
103 theUnsafe.copyMemory(src, srcAddr, dst, destAddr, size);
104 len -= size;
105 srcAddr += size;
106 destAddr += size;
107 }
108 }
109
110
111
112
113
114
115
116
117
118
119
120 public static void copy(ByteBuffer src, int srcOffset, byte[] dest, int destOffset,
121 int length) {
122 long srcAddress = srcOffset;
123 Object srcBase = null;
124 if (src.isDirect()) {
125 srcAddress = srcAddress + ((DirectBuffer) src).address();
126 } else {
127 srcAddress = srcAddress + BYTE_ARRAY_BASE_OFFSET + src.arrayOffset();
128 srcBase = src.array();
129 }
130 long destAddress = (long) destOffset + BYTE_ARRAY_BASE_OFFSET;
131 unsafeCopy(srcBase, srcAddress, dest, destAddress, length);
132 }
133
134
135
136
137
138
139
140
141
142
143
144 public static void copy(ByteBuffer src, int srcOffset, ByteBuffer dest, int destOffset,
145 int length) {
146 long srcAddress, destAddress;
147 Object srcBase = null, destBase = null;
148 if (src.isDirect()) {
149 srcAddress = srcOffset + ((DirectBuffer) src).address();
150 } else {
151 srcAddress = (long) srcOffset + src.arrayOffset() + BYTE_ARRAY_BASE_OFFSET;
152 srcBase = src.array();
153 }
154 if (dest.isDirect()) {
155 destAddress = destOffset + ((DirectBuffer) dest).address();
156 } else {
157 destAddress = (long) destOffset + BYTE_ARRAY_BASE_OFFSET + dest.arrayOffset();
158 destBase = dest.array();
159 }
160 unsafeCopy(srcBase, srcAddress, destBase, destAddress, length);
161 }
162
163
164
165
166
167
168
169
170 public static short toShort(byte[] bytes, int offset) {
171 if (LITTLE_ENDIAN) {
172 return Short.reverseBytes(theUnsafe.getShort(bytes, offset + BYTE_ARRAY_BASE_OFFSET));
173 } else {
174 return theUnsafe.getShort(bytes, offset + BYTE_ARRAY_BASE_OFFSET);
175 }
176 }
177
178
179
180
181
182
183
184 public static int toInt(byte[] bytes, int offset) {
185 if (LITTLE_ENDIAN) {
186 return Integer.reverseBytes(theUnsafe.getInt(bytes, offset + BYTE_ARRAY_BASE_OFFSET));
187 } else {
188 return theUnsafe.getInt(bytes, offset + BYTE_ARRAY_BASE_OFFSET);
189 }
190 }
191
192
193
194
195
196
197
198 public static long toLong(byte[] bytes, int offset) {
199 if (LITTLE_ENDIAN) {
200 return Long.reverseBytes(theUnsafe.getLong(bytes, offset + BYTE_ARRAY_BASE_OFFSET));
201 } else {
202 return theUnsafe.getLong(bytes, offset + BYTE_ARRAY_BASE_OFFSET);
203 }
204 }
205
206
207
208
209
210
211
212
213
214 public static int putShort(byte[] bytes, int offset, short val) {
215 if (LITTLE_ENDIAN) {
216 val = Short.reverseBytes(val);
217 }
218 theUnsafe.putShort(bytes, offset + BYTE_ARRAY_BASE_OFFSET, val);
219 return offset + Bytes.SIZEOF_SHORT;
220 }
221
222
223
224
225
226
227
228
229 public static int putInt(byte[] bytes, int offset, int val) {
230 if (LITTLE_ENDIAN) {
231 val = Integer.reverseBytes(val);
232 }
233 theUnsafe.putInt(bytes, offset + BYTE_ARRAY_BASE_OFFSET, val);
234 return offset + Bytes.SIZEOF_INT;
235 }
236
237
238
239
240
241
242
243
244 public static int putLong(byte[] bytes, int offset, long val) {
245 if (LITTLE_ENDIAN) {
246 val = Long.reverseBytes(val);
247 }
248 theUnsafe.putLong(bytes, offset + BYTE_ARRAY_BASE_OFFSET, val);
249 return offset + Bytes.SIZEOF_LONG;
250 }
251
252
253
254
255
256
257
258
259
260
261 public static short toShort(ByteBuffer buf, int offset) {
262 if (LITTLE_ENDIAN) {
263 return Short.reverseBytes(getAsShort(buf, offset));
264 }
265 return getAsShort(buf, offset);
266 }
267
268
269
270
271
272
273
274 static short getAsShort(ByteBuffer buf, int offset) {
275 if (buf.isDirect()) {
276 return theUnsafe.getShort(((DirectBuffer) buf).address() + offset);
277 }
278 return theUnsafe.getShort(buf.array(), BYTE_ARRAY_BASE_OFFSET + buf.arrayOffset() + offset);
279 }
280
281
282
283
284
285
286
287
288
289 public static int toInt(ByteBuffer buf, int offset) {
290 if (LITTLE_ENDIAN) {
291 return Integer.reverseBytes(getAsInt(buf, offset));
292 }
293 return getAsInt(buf, offset);
294 }
295
296
297
298
299
300
301
302 static int getAsInt(ByteBuffer buf, int offset) {
303 if (buf.isDirect()) {
304 return theUnsafe.getInt(((DirectBuffer) buf).address() + offset);
305 }
306 return theUnsafe.getInt(buf.array(), BYTE_ARRAY_BASE_OFFSET + buf.arrayOffset() + offset);
307 }
308
309
310
311
312
313
314
315
316
317 public static long toLong(ByteBuffer buf, int offset) {
318 if (LITTLE_ENDIAN) {
319 return Long.reverseBytes(getAsLong(buf, offset));
320 }
321 return getAsLong(buf, offset);
322 }
323
324
325
326
327
328
329
330 static long getAsLong(ByteBuffer buf, int offset) {
331 if (buf.isDirect()) {
332 return theUnsafe.getLong(((DirectBuffer) buf).address() + offset);
333 }
334 return theUnsafe.getLong(buf.array(), BYTE_ARRAY_BASE_OFFSET + buf.arrayOffset() + offset);
335 }
336
337
338
339
340
341
342
343
344 public static int putInt(ByteBuffer buf, int offset, int val) {
345 if (LITTLE_ENDIAN) {
346 val = Integer.reverseBytes(val);
347 }
348 if (buf.isDirect()) {
349 theUnsafe.putInt(((DirectBuffer) buf).address() + offset, val);
350 } else {
351 theUnsafe.putInt(buf.array(), offset + buf.arrayOffset() + BYTE_ARRAY_BASE_OFFSET, val);
352 }
353 return offset + Bytes.SIZEOF_INT;
354 }
355
356
357
358
359
360
361
362
363
364 public static int putShort(ByteBuffer buf, int offset, short val) {
365 if (LITTLE_ENDIAN) {
366 val = Short.reverseBytes(val);
367 }
368 if (buf.isDirect()) {
369 theUnsafe.putShort(((DirectBuffer) buf).address() + offset, val);
370 } else {
371 theUnsafe.putShort(buf.array(), BYTE_ARRAY_BASE_OFFSET + buf.arrayOffset() + offset, val);
372 }
373 return offset + Bytes.SIZEOF_SHORT;
374 }
375
376
377
378
379
380
381
382
383 public static int putLong(ByteBuffer buf, int offset, long val) {
384 if (LITTLE_ENDIAN) {
385 val = Long.reverseBytes(val);
386 }
387 if (buf.isDirect()) {
388 theUnsafe.putLong(((DirectBuffer) buf).address() + offset, val);
389 } else {
390 theUnsafe.putLong(buf.array(), BYTE_ARRAY_BASE_OFFSET + buf.arrayOffset() + offset, val);
391 }
392 return offset + Bytes.SIZEOF_LONG;
393 }
394
395
396
397
398
399
400
401
402 public static int putByte(ByteBuffer buf, int offset, byte b) {
403 if (buf.isDirect()) {
404 theUnsafe.putByte(((DirectBuffer) buf).address() + offset, b);
405 } else {
406 theUnsafe.putByte(buf.array(),
407 BYTE_ARRAY_BASE_OFFSET + buf.arrayOffset() + offset, b);
408 }
409 return offset + 1;
410 }
411
412
413
414
415
416
417
418 public static byte toByte(ByteBuffer buf, int offset) {
419 if (buf.isDirect()) {
420 return theUnsafe.getByte(((DirectBuffer) buf).address() + offset);
421 } else {
422 return theUnsafe.getByte(buf.array(), BYTE_ARRAY_BASE_OFFSET + buf.arrayOffset() + offset);
423 }
424 }
425 }