1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.hadoop.hbase.util;
18
19 import java.io.ByteArrayOutputStream;
20 import java.io.DataInputStream;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.OutputStream;
24 import java.nio.ByteBuffer;
25
26 import org.apache.hadoop.hbase.classification.InterfaceAudience;
27 import org.apache.hadoop.hbase.classification.InterfaceStability;
28 import org.apache.hadoop.io.IOUtils;
29 import org.apache.hadoop.io.WritableUtils;
30
31
32
33
34
35 @SuppressWarnings("restriction")
36 @InterfaceAudience.Public
37 @InterfaceStability.Evolving
38 public final class ByteBufferUtils {
39
40
41 private final static int VALUE_MASK = 0x7f;
42 private final static int NEXT_BIT_SHIFT = 7;
43 private final static int NEXT_BIT_MASK = 1 << 7;
44
45 private ByteBufferUtils() {
46 }
47
48
49
50
51
52 public static void writeVLong(ByteBuffer out, long i) {
53 if (i >= -112 && i <= 127) {
54 out.put((byte) i);
55 return;
56 }
57
58 int len = -112;
59 if (i < 0) {
60 i ^= -1L;
61 len = -120;
62 }
63
64 long tmp = i;
65 while (tmp != 0) {
66 tmp = tmp >> 8;
67 len--;
68 }
69
70 out.put((byte) len);
71
72 len = (len < -120) ? -(len + 120) : -(len + 112);
73
74 for (int idx = len; idx != 0; idx--) {
75 int shiftbits = (idx - 1) * 8;
76 long mask = 0xFFL << shiftbits;
77 out.put((byte) ((i & mask) >> shiftbits));
78 }
79 }
80
81
82
83
84
85 public static long readVLong(ByteBuffer in) {
86 byte firstByte = in.get();
87 int len = WritableUtils.decodeVIntSize(firstByte);
88 if (len == 1) {
89 return firstByte;
90 }
91 long i = 0;
92 for (int idx = 0; idx < len-1; idx++) {
93 byte b = in.get();
94 i = i << 8;
95 i = i | (b & 0xFF);
96 }
97 return (WritableUtils.isNegativeVInt(firstByte) ? (i ^ -1L) : i);
98 }
99
100
101
102
103
104
105
106
107
108
109
110 public static int putCompressedInt(OutputStream out, final int value)
111 throws IOException {
112 int i = 0;
113 int tmpvalue = value;
114 do {
115 byte b = (byte) (tmpvalue & VALUE_MASK);
116 tmpvalue >>>= NEXT_BIT_SHIFT;
117 if (tmpvalue != 0) {
118 b |= (byte) NEXT_BIT_MASK;
119 }
120 out.write(b);
121 i++;
122 } while (tmpvalue != 0);
123 return i;
124 }
125
126
127
128
129
130
131
132 public static void putInt(OutputStream out, final int value)
133 throws IOException {
134 for (int i = Bytes.SIZEOF_INT - 1; i >= 0; --i) {
135 out.write((byte) (value >>> (i * 8)));
136 }
137 }
138
139
140
141
142
143
144
145 public static void moveBufferToStream(OutputStream out, ByteBuffer in,
146 int length) throws IOException {
147 copyBufferToStream(out, in, in.position(), length);
148 skip(in, length);
149 }
150
151
152
153
154
155
156
157
158
159
160 public static void copyBufferToStream(OutputStream out, ByteBuffer in,
161 int offset, int length) throws IOException {
162 if (in.hasArray()) {
163 out.write(in.array(), in.arrayOffset() + offset,
164 length);
165 } else {
166 for (int i = 0; i < length; ++i) {
167 out.write(in.get(offset + i));
168 }
169 }
170 }
171
172 public static int putLong(OutputStream out, final long value,
173 final int fitInBytes) throws IOException {
174 long tmpValue = value;
175 for (int i = 0; i < fitInBytes; ++i) {
176 out.write((byte) (tmpValue & 0xff));
177 tmpValue >>>= 8;
178 }
179 return fitInBytes;
180 }
181
182
183
184
185
186
187 public static int longFitsIn(final long value) {
188 if (value < 0) {
189 return 8;
190 }
191
192 if (value < (1l << 4 * 8)) {
193
194 if (value < (1l << 2 * 8)) {
195 if (value < (1l << 1 * 8)) {
196 return 1;
197 }
198 return 2;
199 }
200 if (value < (1l << 3 * 8)) {
201 return 3;
202 }
203 return 4;
204 }
205
206 if (value < (1l << 6 * 8)) {
207 if (value < (1l << 5 * 8)) {
208 return 5;
209 }
210 return 6;
211 }
212 if (value < (1l << 7 * 8)) {
213 return 7;
214 }
215 return 8;
216 }
217
218
219
220
221
222
223 public static int intFitsIn(final int value) {
224 if (value < 0) {
225 return 4;
226 }
227
228 if (value < (1 << 2 * 8)) {
229 if (value < (1 << 1 * 8)) {
230 return 1;
231 }
232 return 2;
233 }
234 if (value <= (1 << 3 * 8)) {
235 return 3;
236 }
237 return 4;
238 }
239
240
241
242
243
244
245 public static int readCompressedInt(InputStream input)
246 throws IOException {
247 int result = 0;
248 int i = 0;
249 byte b;
250 do {
251 b = (byte) input.read();
252 result += (b & VALUE_MASK) << (NEXT_BIT_SHIFT * i);
253 i++;
254 if (i > Bytes.SIZEOF_INT + 1) {
255 throw new IllegalStateException(
256 "Corrupted compressed int (too long: " + (i + 1) + " bytes)");
257 }
258 } while (0 != (b & NEXT_BIT_MASK));
259 return result;
260 }
261
262
263
264
265
266 public static int readCompressedInt(ByteBuffer buffer) {
267 byte b = buffer.get();
268 if ((b & NEXT_BIT_MASK) != 0) {
269 return (b & VALUE_MASK) + (readCompressedInt(buffer) << NEXT_BIT_SHIFT);
270 }
271 return b & VALUE_MASK;
272 }
273
274
275
276
277
278
279
280 public static long readLong(InputStream in, final int fitInBytes)
281 throws IOException {
282 long tmpLong = 0;
283 for (int i = 0; i < fitInBytes; ++i) {
284 tmpLong |= (in.read() & 0xffl) << (8 * i);
285 }
286 return tmpLong;
287 }
288
289
290
291
292
293
294 public static long readLong(ByteBuffer in, final int fitInBytes) {
295 long tmpLength = 0;
296 for (int i = 0; i < fitInBytes; ++i) {
297 tmpLength |= (in.get() & 0xffl) << (8l * i);
298 }
299 return tmpLength;
300 }
301
302
303
304
305
306
307
308
309 public static void copyFromStreamToBuffer(ByteBuffer out,
310 DataInputStream in, int length) throws IOException {
311 if (out.hasArray()) {
312 in.readFully(out.array(), out.position() + out.arrayOffset(),
313 length);
314 skip(out, length);
315 } else {
316 for (int i = 0; i < length; ++i) {
317 out.put(in.readByte());
318 }
319 }
320 }
321
322
323
324
325 public static ByteBuffer drainInputStreamToBuffer(InputStream is) throws IOException {
326 ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
327 IOUtils.copyBytes(is, baos, 4096, true);
328 ByteBuffer buffer = ByteBuffer.wrap(baos.toByteArray());
329 buffer.rewind();
330 return buffer;
331 }
332
333
334
335
336
337
338
339
340
341
342
343 public static void copyFromBufferToBuffer(ByteBuffer out,
344 ByteBuffer in, int sourceOffset, int length) {
345 if (in.hasArray() && out.hasArray()) {
346 System.arraycopy(in.array(), sourceOffset + in.arrayOffset(),
347 out.array(), out.position() +
348 out.arrayOffset(), length);
349 skip(out, length);
350 } else {
351 for (int i = 0; i < length; ++i) {
352 out.put(in.get(sourceOffset + i));
353 }
354 }
355 }
356
357
358
359
360
361
362
363
364
365
366 public static void copyFromBufferToBuffer(ByteBuffer out, ByteBuffer in, int sourceOffset,
367 int destinationOffset, int length) {
368 if (in.hasArray() && out.hasArray()) {
369 System.arraycopy(in.array(), sourceOffset + in.arrayOffset(), out.array(), out.arrayOffset()
370 + destinationOffset, length);
371 } else {
372 for (int i = 0; i < length; ++i) {
373 out.put((destinationOffset + i), in.get(sourceOffset + i));
374 }
375 }
376 }
377
378
379
380
381
382
383
384
385
386 public static int findCommonPrefix(ByteBuffer buffer, int offsetLeft,
387 int offsetRight, int limit) {
388 int prefix = 0;
389
390 for (; prefix < limit; ++prefix) {
391 if (buffer.get(offsetLeft + prefix) != buffer.get(offsetRight + prefix)) {
392 break;
393 }
394 }
395
396 return prefix;
397 }
398
399
400
401
402
403
404
405
406
407
408 public static int findCommonPrefix(
409 byte[] left, int leftOffset, int leftLength,
410 byte[] right, int rightOffset, int rightLength) {
411 int length = Math.min(leftLength, rightLength);
412 int result = 0;
413
414 while (result < length &&
415 left[leftOffset + result] == right[rightOffset + result]) {
416 result++;
417 }
418
419 return result;
420 }
421
422
423
424
425
426
427
428
429
430
431 public static boolean arePartsEqual(ByteBuffer buffer,
432 int offsetLeft, int lengthLeft,
433 int offsetRight, int lengthRight) {
434 if (lengthLeft != lengthRight) {
435 return false;
436 }
437
438 if (buffer.hasArray()) {
439 return 0 == Bytes.compareTo(
440 buffer.array(), buffer.arrayOffset() + offsetLeft, lengthLeft,
441 buffer.array(), buffer.arrayOffset() + offsetRight, lengthRight);
442 }
443
444 for (int i = 0; i < lengthRight; ++i) {
445 if (buffer.get(offsetLeft + i) != buffer.get(offsetRight + i)) {
446 return false;
447 }
448 }
449 return true;
450 }
451
452
453
454
455
456
457 public static void skip(ByteBuffer buffer, int length) {
458 buffer.position(buffer.position() + length);
459 }
460
461 public static void extendLimit(ByteBuffer buffer, int numBytes) {
462 buffer.limit(buffer.limit() + numBytes);
463 }
464
465
466
467
468
469
470
471
472 public static byte[] toBytes(ByteBuffer buffer, int startPosition) {
473 int originalPosition = buffer.position();
474 byte[] output = new byte[buffer.limit() - startPosition];
475 buffer.position(startPosition);
476 buffer.get(output);
477 buffer.position(originalPosition);
478 return output;
479 }
480
481
482
483
484
485
486
487
488 public static byte[] toBytes(ByteBuffer buffer, int offset, int length) {
489 byte[] output = new byte[length];
490 for (int i = 0; i < length; i++) {
491 output[i] = buffer.get(offset + i);
492 }
493 return output;
494 }
495
496 public static int compareTo(ByteBuffer buf1, int o1, int len1, ByteBuffer buf2, int o2, int len2) {
497 if (buf1.hasArray() && buf2.hasArray()) {
498 return Bytes.compareTo(buf1.array(), buf1.arrayOffset() + o1, len1, buf2.array(),
499 buf2.arrayOffset() + o2, len2);
500 }
501 int end1 = o1 + len1;
502 int end2 = o2 + len2;
503 for (int i = o1, j = o2; i < end1 && j < end2; i++, j++) {
504 int a = buf1.get(i) & 0xFF;
505 int b = buf2.get(j) & 0xFF;
506 if (a != b) {
507 return a - b;
508 }
509 }
510 return len1 - len2;
511 }
512 }