View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with this
4    * work for additional information regarding copyright ownership. The ASF
5    * licenses this file to you under the Apache License, Version 2.0 (the
6    * "License"); you may not use this file except in compliance with the License.
7    * You may obtain a copy of the License at
8    *
9    * http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14   * License for the specific language governing permissions and limitations
15   * under the License.
16   */
17  package org.apache.hadoop.hbase.util;
18  
19  import java.io.ByteArrayOutputStream;
20  import java.io.DataInput;
21  import java.io.DataInputStream;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.OutputStream;
25  import java.nio.ByteBuffer;
26  
27  import org.apache.hadoop.hbase.classification.InterfaceAudience;
28  import org.apache.hadoop.hbase.classification.InterfaceStability;
29  import org.apache.hadoop.io.IOUtils;
30  import org.apache.hadoop.io.WritableUtils;
31  
32  import sun.nio.ch.DirectBuffer;
33  
34  /**
35   * Utility functions for working with byte buffers, such as reading/writing
36   * variable-length long numbers.
37   * @deprecated This class will become IA.Private in HBase 3.0. Downstream folks shouldn't use it.
38   */
39  @SuppressWarnings("restriction")
40  @Deprecated
41  @InterfaceAudience.Public
42  @InterfaceStability.Evolving
43  public final class ByteBufferUtils {
44    // "Compressed integer" serialization helper constants.
45    public final static int VALUE_MASK = 0x7f;
46    public final static int NEXT_BIT_SHIFT = 7;
47    public final static int NEXT_BIT_MASK = 1 << 7;
48    @InterfaceAudience.Private
49    static final boolean UNSAFE_AVAIL = UnsafeAvailChecker.isAvailable();
50    public static final boolean UNSAFE_UNALIGNED = UnsafeAvailChecker.unaligned();
51  
52    private ByteBufferUtils() {
53    }
54  
55    static abstract class Comparer {
56      abstract int compareTo(byte [] buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2);
57      abstract int compareTo(ByteBuffer buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2);
58    }
59  
60    static abstract class Converter {
61      abstract short toShort(ByteBuffer buffer, int offset);
62      abstract int toInt(ByteBuffer buffer);
63      abstract int toInt(ByteBuffer buffer, int offset);
64      abstract long toLong(ByteBuffer buffer, int offset);
65      abstract void putInt(ByteBuffer buffer, int val);
66      abstract int putInt(ByteBuffer buffer, int index, int val);
67      abstract void putShort(ByteBuffer buffer, short val);
68      abstract int putShort(ByteBuffer buffer, int index, short val);
69      abstract void putLong(ByteBuffer buffer, long val);
70      abstract int putLong(ByteBuffer buffer, int index, long val);
71    }
72  
73    static class ComparerHolder {
74      static final String UNSAFE_COMPARER_NAME = ComparerHolder.class.getName() + "$UnsafeComparer";
75  
76      static final Comparer BEST_COMPARER = getBestComparer();
77  
78      static Comparer getBestComparer() {
79        try {
80          Class<?> theClass = Class.forName(UNSAFE_COMPARER_NAME);
81  
82          @SuppressWarnings("unchecked")
83          Comparer comparer = (Comparer) theClass.getConstructor().newInstance();
84          return comparer;
85        } catch (Throwable t) { // ensure we really catch *everything*
86          return PureJavaComparer.INSTANCE;
87        }
88      }
89  
90      static final class PureJavaComparer extends Comparer {
91        static final PureJavaComparer INSTANCE = new PureJavaComparer();
92  
93        private PureJavaComparer() {}
94  
95        @Override
96        public int compareTo(byte [] buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) {
97          int end1 = o1 + l1;
98          int end2 = o2 + l2;
99          for (int i = o1, j = o2; i < end1 && j < end2; i++, j++) {
100           int a = buf1[i] & 0xFF;
101           int b = buf2.get(j) & 0xFF;
102           if (a != b) {
103             return a - b;
104           }
105         }
106         return l1 - l2;
107       }
108 
109       @Override
110       public int compareTo(ByteBuffer buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) {
111         int end1 = o1 + l1;
112         int end2 = o2 + l2;
113         for (int i = o1, j = o2; i < end1 && j < end2; i++, j++) {
114           int a = buf1.get(i) & 0xFF;
115           int b = buf2.get(j) & 0xFF;
116           if (a != b) {
117             return a - b;
118           }
119         }
120         return l1 - l2;
121       }
122     }
123 
124     static final class UnsafeComparer extends Comparer {
125 
126       public UnsafeComparer() {}
127 
128       static {
129         if(!UNSAFE_UNALIGNED) {
130           throw new Error();
131         }
132       }
133 
134       @Override
135       public int compareTo(byte[] buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) {
136         long offset2Adj;
137         Object refObj2 = null;
138         if (buf2.isDirect()) {
139           offset2Adj = o2 + ((DirectBuffer)buf2).address();
140         } else {
141           offset2Adj = o2 + buf2.arrayOffset() + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
142           refObj2 = buf2.array();
143         }
144         return compareToUnsafe(buf1, o1 + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET, l1,
145                 refObj2, offset2Adj, l2);
146       }
147 
148       @Override
149       public int compareTo(ByteBuffer buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) {
150         long offset1Adj, offset2Adj;
151         Object refObj1 = null, refObj2 = null;
152         if (buf1.isDirect()) {
153           offset1Adj = o1 + ((DirectBuffer) buf1).address();
154         } else {
155           offset1Adj = o1 + buf1.arrayOffset() + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
156           refObj1 = buf1.array();
157         }
158         if (buf2.isDirect()) {
159           offset2Adj = o2 + ((DirectBuffer) buf2).address();
160         } else {
161           offset2Adj = o2 + buf2.arrayOffset() + UnsafeAccess.BYTE_ARRAY_BASE_OFFSET;
162           refObj2 = buf2.array();
163         }
164         return compareToUnsafe(refObj1, offset1Adj, l1, refObj2, offset2Adj, l2);
165       }
166     }
167   }
168 
169 
170   static class ConverterHolder {
171     static final String UNSAFE_CONVERTER_NAME =
172             ConverterHolder.class.getName() + "$UnsafeConverter";
173     static final Converter BEST_CONVERTER = getBestConverter();
174 
175     static Converter getBestConverter() {
176       try {
177         Class<?> theClass = Class.forName(UNSAFE_CONVERTER_NAME);
178 
179         // yes, UnsafeComparer does implement Comparer<byte[]>
180         @SuppressWarnings("unchecked")
181         Converter converter = (Converter) theClass.getConstructor().newInstance();
182         return converter;
183       } catch (Throwable t) { // ensure we really catch *everything*
184         return PureJavaConverter.INSTANCE;
185       }
186     }
187 
188     static final class PureJavaConverter extends Converter {
189       static final PureJavaConverter INSTANCE = new PureJavaConverter();
190 
191       private PureJavaConverter() {}
192 
193       @Override
194       short toShort(ByteBuffer buffer, int offset) {
195         return buffer.getShort(offset);
196       }
197 
198       @Override
199       int toInt(ByteBuffer buffer) {
200         return buffer.getInt();
201       }
202 
203       @Override
204       int toInt(ByteBuffer buffer, int offset) {
205         return buffer.getInt(offset);
206       }
207 
208       @Override
209       long toLong(ByteBuffer buffer, int offset) {
210         return buffer.getLong(offset);
211       }
212 
213       @Override
214       void putInt(ByteBuffer buffer, int val) {
215         buffer.putInt(val);
216       }
217 
218       @Override
219       int putInt(ByteBuffer buffer, int index, int val) {
220         buffer.putInt(index, val);
221         return index + Bytes.SIZEOF_INT;
222       }
223 
224       @Override
225       void putShort(ByteBuffer buffer, short val) {
226         buffer.putShort(val);
227       }
228 
229       @Override
230       int putShort(ByteBuffer buffer, int index, short val) {
231         buffer.putShort(index, val);
232         return index + Bytes.SIZEOF_SHORT;
233       }
234 
235       @Override
236       void putLong(ByteBuffer buffer, long val) {
237         buffer.putLong(val);
238       }
239 
240       @Override
241       int putLong(ByteBuffer buffer, int index, long val) {
242         buffer.putLong(index, val);
243         return index + Bytes.SIZEOF_LONG;
244       }
245     }
246 
247     static final class UnsafeConverter extends Converter {
248 
249       public UnsafeConverter() {}
250 
251       static {
252         if(!UNSAFE_UNALIGNED) {
253           throw new Error();
254         }
255       }
256 
257       @Override
258       short toShort(ByteBuffer buffer, int offset) {
259         return UnsafeAccess.toShort(buffer, offset);
260       }
261 
262       @Override
263       int toInt(ByteBuffer buffer) {
264         int i = UnsafeAccess.toInt(buffer, buffer.position());
265         buffer.position(buffer.position() + Bytes.SIZEOF_INT);
266         return i;
267       }
268 
269       @Override
270       int toInt(ByteBuffer buffer, int offset) {
271         return UnsafeAccess.toInt(buffer, offset);
272       }
273 
274       @Override
275       long toLong(ByteBuffer buffer, int offset) {
276         return UnsafeAccess.toLong(buffer, offset);
277       }
278 
279       @Override
280       void putInt(ByteBuffer buffer, int val) {
281         int newPos = UnsafeAccess.putInt(buffer, buffer.position(), val);
282         buffer.position(newPos);
283       }
284 
285       @Override
286       int putInt(ByteBuffer buffer, int index, int val) {
287         return UnsafeAccess.putInt(buffer, index, val);
288       }
289 
290       @Override
291       void putShort(ByteBuffer buffer, short val) {
292         int newPos = UnsafeAccess.putShort(buffer, buffer.position(), val);
293         buffer.position(newPos);
294       }
295 
296       @Override
297       int putShort(ByteBuffer buffer, int index, short val) {
298         return UnsafeAccess.putShort(buffer, index, val);
299       }
300 
301       @Override
302       void putLong(ByteBuffer buffer, long val) {
303         int newPos = UnsafeAccess.putLong(buffer, buffer.position(), val);
304         buffer.position(newPos);
305       }
306 
307       @Override
308       int putLong(ByteBuffer buffer, int index, long val) {
309         return UnsafeAccess.putLong(buffer, index, val);
310       }
311     }
312   }
313 
314     /**
315    * Similar to {@link WritableUtils#writeVLong(java.io.DataOutput, long)},
316    * but writes to a {@link ByteBuffer}.
317    */
318   public static void writeVLong(ByteBuffer out, long i) {
319     if (i >= -112 && i <= 127) {
320       out.put((byte) i);
321       return;
322     }
323 
324     int len = -112;
325     if (i < 0) {
326       i ^= -1L; // take one's complement
327       len = -120;
328     }
329 
330     long tmp = i;
331     while (tmp != 0) {
332       tmp = tmp >> 8;
333       len--;
334     }
335 
336     out.put((byte) len);
337 
338     len = (len < -120) ? -(len + 120) : -(len + 112);
339 
340     for (int idx = len; idx != 0; idx--) {
341       int shiftbits = (idx - 1) * 8;
342       long mask = 0xFFL << shiftbits;
343       out.put((byte) ((i & mask) >> shiftbits));
344     }
345   }
346 
347   /**
348    * Similar to {@link WritableUtils#readVLong(DataInput)} but reads from a
349    * {@link ByteBuffer}.
350    */
351   public static long readVLong(ByteBuffer in) {
352     byte firstByte = in.get();
353     int len = WritableUtils.decodeVIntSize(firstByte);
354     if (len == 1) {
355       return firstByte;
356     }
357     long i = 0;
358     for (int idx = 0; idx < len-1; idx++) {
359       byte b = in.get();
360       i = i << 8;
361       i = i | (b & 0xFF);
362     }
363     return (WritableUtils.isNegativeVInt(firstByte) ? (i ^ -1L) : i);
364   }
365 
366 
367   /**
368    * Put in buffer integer using 7 bit encoding. For each written byte:
369    * 7 bits are used to store value
370    * 1 bit is used to indicate whether there is next bit.
371    * @param value Int to be compressed.
372    * @param out Where to put compressed data
373    * @return Number of bytes written.
374    * @throws IOException on stream error
375    */
376    public static int putCompressedInt(OutputStream out, final int value)
377       throws IOException {
378     int i = 0;
379     int tmpvalue = value;
380     do {
381       byte b = (byte) (tmpvalue & VALUE_MASK);
382       tmpvalue >>>= NEXT_BIT_SHIFT;
383       if (tmpvalue != 0) {
384         b |= (byte) NEXT_BIT_MASK;
385       }
386       out.write(b);
387       i++;
388     } while (tmpvalue != 0);
389     return i;
390   }
391 
392    /**
393     * Put in output stream 32 bit integer (Big Endian byte order).
394     * @param out Where to put integer.
395     * @param value Value of integer.
396     * @throws IOException On stream error.
397     */
398    public static void putInt(OutputStream out, final int value)
399        throws IOException {
400      for (int i = Bytes.SIZEOF_INT - 1; i >= 0; --i) {
401        out.write((byte) (value >>> (i * 8)));
402      }
403    }
404 
405    public static byte toByte(ByteBuffer buffer, int offset) {
406      if (UNSAFE_AVAIL) {
407        return UnsafeAccess.toByte(buffer, offset);
408      } else {
409        return buffer.get(offset);
410      }
411    }
412 
413   /**
414    * Copy the data to the output stream and update position in buffer.
415    * @param out the stream to write bytes to
416    * @param in the buffer to read bytes from
417    * @param length the number of bytes to copy
418    */
419   public static void moveBufferToStream(OutputStream out, ByteBuffer in,
420       int length) throws IOException {
421     copyBufferToStream(out, in, in.position(), length);
422     skip(in, length);
423   }
424 
425   /**
426    * Copy data from a buffer to an output stream. Does not update the position
427    * in the buffer.
428    * @param out the stream to write bytes to
429    * @param in the buffer to read bytes from
430    * @param offset the offset in the buffer (from the buffer's array offset)
431    *      to start copying bytes from
432    * @param length the number of bytes to copy
433    */
434   public static void copyBufferToStream(OutputStream out, ByteBuffer in,
435       int offset, int length) throws IOException {
436     if (in.hasArray()) {
437       out.write(in.array(), in.arrayOffset() + offset, length);
438     } else {
439       for (int i = 0; i < length; ++i) {
440         out.write(toByte(in, offset + i));
441       }
442     }
443   }
444 
445   public static int putLong(OutputStream out, final long value,
446       final int fitInBytes) throws IOException {
447     long tmpValue = value;
448     for (int i = 0; i < fitInBytes; ++i) {
449       out.write((byte) (tmpValue & 0xff));
450       tmpValue >>>= 8;
451     }
452     return fitInBytes;
453   }
454 
455   /**
456    * Check how many bytes are required to store value.
457    * @param value Value which size will be tested.
458    * @return How many bytes are required to store value.
459    */
460   public static int longFitsIn(final long value) {
461     if (value < 0) {
462       return 8;
463     }
464 
465     if (value < (1L << (4 * 8))) {
466       // no more than 4 bytes
467       if (value < (1L << (2 * 8))) {
468         if (value < (1L << (1 * 8))) {
469           return 1;
470         }
471         return 2;
472       }
473       if (value < (1L << (3 * 8))) {
474         return 3;
475       }
476       return 4;
477     }
478     // more than 4 bytes
479     if (value < (1L << (6 * 8))) {
480       if (value < (1L << (5 * 8))) {
481         return 5;
482       }
483       return 6;
484     }
485     if (value < (1L << (7 * 8))) {
486       return 7;
487     }
488     return 8;
489   }
490 
491   /**
492    * Check how many bytes is required to store value.
493    * @param value Value which size will be tested.
494    * @return How many bytes are required to store value.
495    */
496   public static int intFitsIn(final int value) {
497     if (value < 0) {
498       return 4;
499     }
500 
501     if (value < (1 << (2 * 8))) {
502       if (value < (1 << (1 * 8))) {
503         return 1;
504       }
505       return 2;
506     }
507     if (value <= (1 << (3 * 8))) {
508       return 3;
509     }
510     return 4;
511   }
512 
513   /**
514    * Read integer from stream coded in 7 bits and increment position.
515    * @return the integer that has been read
516    * @throws IOException
517    */
518   public static int readCompressedInt(InputStream input)
519       throws IOException {
520     int result = 0;
521     int i = 0;
522     byte b;
523     do {
524       b = (byte) input.read();
525       result += (b & VALUE_MASK) << (NEXT_BIT_SHIFT * i);
526       i++;
527       if (i > Bytes.SIZEOF_INT + 1) {
528         throw new IllegalStateException(
529             "Corrupted compressed int (too long: " + (i + 1) + " bytes)");
530       }
531     } while (0 != (b & NEXT_BIT_MASK));
532     return result;
533   }
534 
535   /**
536    * Read integer from buffer coded in 7 bits and increment position.
537    * @return Read integer.
538    */
539   public static int readCompressedInt(ByteBuffer buffer) {
540     byte b = buffer.get();
541     if ((b & NEXT_BIT_MASK) != 0) {
542       return (b & VALUE_MASK) + (readCompressedInt(buffer) << NEXT_BIT_SHIFT);
543     }
544     return b & VALUE_MASK;
545   }
546 
547   /**
548    * Read long which was written to fitInBytes bytes and increment position.
549    * @param fitInBytes In how many bytes given long is stored.
550    * @return The value of parsed long.
551    * @throws IOException
552    */
553   public static long readLong(InputStream in, final int fitInBytes)
554       throws IOException {
555     long tmpLong = 0;
556     for (int i = 0; i < fitInBytes; ++i) {
557       tmpLong |= (in.read() & 0xffL) << (8 * i);
558     }
559     return tmpLong;
560   }
561 
562   /**
563    * Read long which was written to fitInBytes bytes and increment position.
564    * @param fitInBytes In how many bytes given long is stored.
565    * @return The value of parsed long.
566    */
567   public static long readLong(ByteBuffer in, final int fitInBytes) {
568     long tmpLength = 0;
569     for (int i = 0; i < fitInBytes; ++i) {
570       tmpLength |= (in.get() & 0xffL) << (8L * i);
571     }
572     return tmpLength;
573   }
574 
575   /**
576    * Copy the given number of bytes from the given stream and put it at the
577    * current position of the given buffer, updating the position in the buffer.
578    * @param out the buffer to write data to
579    * @param in the stream to read data from
580    * @param length the number of bytes to read/write
581    */
582   public static void copyFromStreamToBuffer(ByteBuffer out,
583       DataInputStream in, int length) throws IOException {
584     if (out.hasArray()) {
585       in.readFully(out.array(), out.position() + out.arrayOffset(),
586           length);
587       skip(out, length);
588     } else {
589       for (int i = 0; i < length; ++i) {
590         out.put(in.readByte());
591       }
592     }
593   }
594 
595   /**
596    * Copy from the InputStream to a new heap ByteBuffer until the InputStream is exhausted.
597    */
598   public static ByteBuffer drainInputStreamToBuffer(InputStream is) throws IOException {
599     ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
600     IOUtils.copyBytes(is, baos, 4096, true);
601     ByteBuffer buffer = ByteBuffer.wrap(baos.toByteArray());
602     buffer.rewind();
603     return buffer;
604   }
605 
606   /**
607    * Copy from one buffer to another from given offset.
608    * <p>
609    * Note : This will advance the position marker of {@code out} but not change the position maker
610    * for {@code in}
611    * @param out destination buffer
612    * @param in source buffer
613    * @param sourceOffset offset in the source buffer
614    * @param length how many bytes to copy
615    */
616   public static void copyFromBufferToBuffer(ByteBuffer out,
617       ByteBuffer in, int sourceOffset, int length) {
618     if (in.hasArray() && out.hasArray()) {
619       System.arraycopy(in.array(), sourceOffset + in.arrayOffset(),
620           out.array(), out.position() +
621           out.arrayOffset(), length);
622       skip(out, length);
623     } else {
624       for (int i = 0; i < length; ++i) {
625         out.put(in.get(sourceOffset + i));
626       }
627     }
628   }
629 
630   /**
631    * Copy from one buffer to another from given offset. This will be absolute positional copying and
632    * won't affect the position of any of the buffers.
633    * @param in
634    * @param out
635    * @param sourceOffset
636    * @param destinationOffset
637    * @param length
638    */
639   public static void copyFromBufferToBuffer(ByteBuffer out, ByteBuffer in, int sourceOffset,
640       int destinationOffset, int length) {
641     if (in.hasArray() && out.hasArray()) {
642       System.arraycopy(in.array(), sourceOffset + in.arrayOffset(), out.array(), out.arrayOffset()
643           + destinationOffset, length);
644     } else if (UNSAFE_AVAIL) {
645       UnsafeAccess.copy(in, sourceOffset, out, destinationOffset, length);
646     } else {
647       for (int i = 0; i < length; ++i) {
648         out.put((destinationOffset + i), in.get(sourceOffset + i));
649       }
650     }
651   }
652 
653   /**
654    * Find length of common prefix of two parts in the buffer
655    * @param buffer Where parts are located.
656    * @param offsetLeft Offset of the first part.
657    * @param offsetRight Offset of the second part.
658    * @param limit Maximal length of common prefix.
659    * @return Length of prefix.
660    */
661   public static int findCommonPrefix(ByteBuffer buffer, int offsetLeft,
662       int offsetRight, int limit) {
663     int prefix = 0;
664 
665     for (; prefix < limit; ++prefix) {
666       if (buffer.get(offsetLeft + prefix) != buffer.get(offsetRight + prefix)) {
667         break;
668       }
669     }
670 
671     return prefix;
672   }
673 
674 
675   /**
676    * Find length of common prefix in two arrays.
677    * @param left Array to be compared.
678    * @param leftOffset Offset in left array.
679    * @param leftLength Length of left array.
680    * @param right Array to be compared.
681    * @param rightOffset Offset in right array.
682    * @param rightLength Length of right array.
683    */
684   public static int findCommonPrefix(
685       byte[] left, int leftOffset, int leftLength,
686       byte[] right, int rightOffset, int rightLength) {
687     int length = Math.min(leftLength, rightLength);
688     int result = 0;
689 
690     while (result < length &&
691         left[leftOffset + result] == right[rightOffset + result]) {
692       result++;
693     }
694 
695     return result;
696   }
697 
698   /**
699    * Find length of common prefix in two arrays.
700    * @param left ByteBuffer to be compared.
701    * @param leftOffset Offset in left ByteBuffer.
702    * @param leftLength Length of left ByteBuffer.
703    * @param right ByteBuffer to be compared.
704    * @param rightOffset Offset in right ByteBuffer.
705    * @param rightLength Length of right ByteBuffer.
706    */
707   public static int findCommonPrefix(ByteBuffer left, int leftOffset, int leftLength,
708       ByteBuffer right, int rightOffset, int rightLength) {
709     int length = Math.min(leftLength, rightLength);
710     int result = 0;
711 
712     while (result < length && ByteBufferUtils.toByte(left, leftOffset + result) == ByteBufferUtils
713         .toByte(right, rightOffset + result)) {
714       result++;
715     }
716 
717     return result;
718   }
719 
720   /**
721    * Check whether two parts in the same buffer are equal.
722    * @param buffer In which buffer there are parts
723    * @param offsetLeft Beginning of first part.
724    * @param lengthLeft Length of the first part.
725    * @param offsetRight Beginning of the second part.
726    * @param lengthRight Length of the second part.
727    * @return True if equal
728    */
729   public static boolean arePartsEqual(ByteBuffer buffer,
730       int offsetLeft, int lengthLeft,
731       int offsetRight, int lengthRight) {
732     if (lengthLeft != lengthRight) {
733       return false;
734     }
735 
736     if (buffer.hasArray()) {
737       return 0 == Bytes.compareTo(
738           buffer.array(), buffer.arrayOffset() + offsetLeft, lengthLeft,
739           buffer.array(), buffer.arrayOffset() + offsetRight, lengthRight);
740     }
741 
742     for (int i = 0; i < lengthRight; ++i) {
743       if (buffer.get(offsetLeft + i) != buffer.get(offsetRight + i)) {
744         return false;
745       }
746     }
747     return true;
748   }
749 
750   /**
751    * Increment position in buffer.
752    * @param buffer In this buffer.
753    * @param length By that many bytes.
754    */
755   public static void skip(ByteBuffer buffer, int length) {
756     buffer.position(buffer.position() + length);
757   }
758 
759   public static void extendLimit(ByteBuffer buffer, int numBytes) {
760     buffer.limit(buffer.limit() + numBytes);
761   }
762 
763   /**
764    * Copy the bytes from position to limit into a new byte[] of the exact length and sets the
765    * position and limit back to their original values (though not thread safe).
766    * @param buffer copy from here
767    * @param startPosition put buffer.get(startPosition) into byte[0]
768    * @return a new byte[] containing the bytes in the specified range
769    */
770   public static byte[] toBytes(ByteBuffer buffer, int startPosition) {
771     int originalPosition = buffer.position();
772     byte[] output = new byte[buffer.limit() - startPosition];
773     buffer.position(startPosition);
774     buffer.get(output);
775     buffer.position(originalPosition);
776     return output;
777   }
778 
779   /**
780    * Copy the given number of bytes from specified offset into a new byte[]
781    * @param buffer
782    * @param offset
783    * @param length
784    * @return a new byte[] containing the bytes in the specified range
785    */
786   public static byte[] toBytes(ByteBuffer buffer, int offset, int length) {
787     byte[] output = new byte[length];
788     for (int i = 0; i < length; i++) {
789       output[i] = buffer.get(offset + i);
790     }
791     return output;
792   }
793 
794   public static int compareTo(ByteBuffer buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) {
795     return ComparerHolder.BEST_COMPARER.compareTo(buf1, o1, l1, buf2, o2, l2);
796   }
797 
798   public static boolean equals(ByteBuffer buf1, int o1, int l1, byte[] buf2, int o2, int l2) {
799     if ((l1 == 0) || (l2 == 0)) {
800       // both 0 length, return true, or else false
801       return l1 == l2;
802     }
803     // Since we're often comparing adjacent sorted data,
804     // it's usual to have equal arrays except for the very last byte
805     // so check that first
806     if (toByte(buf1, o1 + l1 - 1) != buf2[o2 + l2 - 1]) return false;
807     return compareTo(buf1, o1, l1, buf2, o2, l2) == 0;
808   }
809 
810   // The below two methods show up in lots of places. Versions of them in commons util and in
811   // Cassandra. In guava too? They are copied from ByteBufferUtils. They are here as static
812   // privates. Seems to make code smaller and make Hotspot happier (comes of compares and study
813   // of compiled code via  jitwatch).
814 
815   public static int compareTo(byte [] buf1, int o1, int l1, ByteBuffer buf2, int o2, int l2) {
816     return ComparerHolder.BEST_COMPARER.compareTo(buf1, o1, l1, buf2, o2, l2);
817   }
818 
819   public static int compareTo(ByteBuffer buf1, int o1, int l1, byte[] buf2, int o2, int l2) {
820     return compareTo(buf2, o2, l2, buf1, o1, l1)*-1;
821   }
822 
823   static int compareToUnsafe(Object obj1, long o1, int l1, Object obj2, long o2, int l2) {
824     final int stride = 8;
825     final int minLength = Math.min(l1, l2);
826     int strideLimit = minLength & ~(stride - 1);
827     int i;
828 
829     /*
830      * Compare 8 bytes at a time. Benchmarking shows comparing 8 bytes at a time is no slower than
831      * comparing 4 bytes at a time even on 32-bit. On the other hand, it is substantially faster on
832      * 64-bit.
833      */
834     for (i = 0; i < strideLimit; i += stride) {
835       long lw = UnsafeAccess.theUnsafe.getLong(obj1, o1 + (long) i);
836       long rw = UnsafeAccess.theUnsafe.getLong(obj2, o2 + (long) i);
837       if (lw != rw) {
838         if (!UnsafeAccess.LITTLE_ENDIAN) {
839           return ((lw + Long.MIN_VALUE) < (rw + Long.MIN_VALUE)) ? -1 : 1;
840         }
841 
842         /*
843          * We want to compare only the first index where left[index] != right[index]. This
844          * corresponds to the least significant nonzero byte in lw ^ rw, since lw and rw are
845          * little-endian. Long.numberOfTrailingZeros(diff) tells us the least significant
846          * nonzero bit, and zeroing out the first three bits of L.nTZ gives us the shift to get
847          * that least significant nonzero byte. This comparison logic is based on UnsignedBytes
848          * from guava v21
849          */
850         int n = Long.numberOfTrailingZeros(lw ^ rw) & ~0x7;
851         return ((int) ((lw >>> n) & 0xFF)) - ((int) ((rw >>> n) & 0xFF));
852       }
853     }
854 
855     // The epilogue to cover the last (minLength % stride) elements.
856     for (; i < minLength; i++) {
857       int il = (UnsafeAccess.theUnsafe.getByte(obj1, o1 + i) & 0xFF);
858       int ir = (UnsafeAccess.theUnsafe.getByte(obj2, o2 + i) & 0xFF);
859       if (il != ir) {
860         return il - ir;
861       }
862     }
863     return l1 - l2;
864   }
865 
866   /**
867    * Reads a short value at the given buffer's offset.
868    * @param buffer
869    * @param offset
870    * @return short value at offset
871    */
872   public static short toShort(ByteBuffer buffer, int offset) {
873     return ConverterHolder.BEST_CONVERTER.toShort(buffer, offset);
874   }
875 
876   /**
877    * Reads an int value at the given buffer's current position. Also advances the buffer's position
878    */
879   public static int toInt(ByteBuffer buffer) {
880     return ConverterHolder.BEST_CONVERTER.toInt(buffer);
881   }
882 
883   /**
884    * Reads an int value at the given buffer's offset.
885    * @param buffer
886    * @param offset
887    * @return int value at offset
888    */
889   public static int toInt(ByteBuffer buffer, int offset) {
890     return ConverterHolder.BEST_CONVERTER.toInt(buffer, offset);
891   }
892 
893   /**
894    * Reads a long value at the given buffer's offset.
895    * @param buffer
896    * @param offset
897    * @return long value at offset
898    */
899   public static long toLong(ByteBuffer buffer, int offset) {
900     return ConverterHolder.BEST_CONVERTER.toLong(buffer, offset);
901   }
902 
903   /**
904    * Put an int value out to the given ByteBuffer's current position in big-endian format.
905    * This also advances the position in buffer by int size.
906    * @param buffer the ByteBuffer to write to
907    * @param val int to write out
908    */
909   public static void putInt(ByteBuffer buffer, int val) {
910     ConverterHolder.BEST_CONVERTER.putInt(buffer, val);
911   }
912 
913   public static int putInt(ByteBuffer buffer, int index, int val) {
914     return ConverterHolder.BEST_CONVERTER.putInt(buffer, index, val);
915   }
916 
917   /**
918    * Put a short value out to the given ByteBuffer's current position in big-endian format.
919    * This also advances the position in buffer by short size.
920    * @param buffer the ByteBuffer to write to
921    * @param val short to write out
922    */
923   public static void putShort(ByteBuffer buffer, short val) {
924     ConverterHolder.BEST_CONVERTER.putShort(buffer, val);
925   }
926 
927   public static int putShort(ByteBuffer buffer, int index, short val) {
928     return ConverterHolder.BEST_CONVERTER.putShort(buffer, index, val);
929   }
930 
931   /**
932    * Put a long value out to the given ByteBuffer's current position in big-endian format.
933    * This also advances the position in buffer by long size.
934    * @param buffer the ByteBuffer to write to
935    * @param val long to write out
936    */
937   public static void putLong(ByteBuffer buffer, long val) {
938     ConverterHolder.BEST_CONVERTER.putLong(buffer, val);
939   }
940 
941   public static int putLong(ByteBuffer buffer, int index, long val) {
942     return ConverterHolder.BEST_CONVERTER.putLong(buffer, index, val);
943   }
944 
945   /**
946    * Copies bytes from given array's offset to length part into the given buffer. Puts the bytes
947    * to buffer's given position. This doesn't affact the position of buffer.
948    * @param out
949    * @param in
950    * @param inOffset
951    * @param length
952    */
953   public static void copyFromArrayToBuffer(ByteBuffer out, int outOffset, byte[] in, int inOffset,
954       int length) {
955     if (out.hasArray()) {
956       System.arraycopy(in, inOffset, out.array(), out.arrayOffset() + outOffset, length);
957     } else if (UNSAFE_AVAIL) {
958       UnsafeAccess.copy(in, inOffset, out, outOffset, length);
959     } else {
960       ByteBuffer outDup = out.duplicate();
961       outDup.position(outOffset);
962       outDup.put(in, inOffset, length);
963     }
964   }
965 
966   /**
967    * Copies specified number of bytes from given offset of 'in' ByteBuffer to
968    * the array. This doesn't affact the position of buffer.
969    * @param out
970    * @param in
971    * @param sourceOffset
972    * @param destinationOffset
973    * @param length
974    */
975   public static void copyFromBufferToArray(byte[] out, ByteBuffer in, int sourceOffset,
976       int destinationOffset, int length) {
977     if (in.hasArray()) {
978       System.arraycopy(in.array(), sourceOffset + in.arrayOffset(), out, destinationOffset, length);
979     } else if (UNSAFE_AVAIL) {
980       UnsafeAccess.copy(in, sourceOffset, out, destinationOffset, length);
981     } else {
982       ByteBuffer inDup = in.duplicate();
983       inDup.position(sourceOffset);
984       inDup.get(out, destinationOffset, length);
985     }
986   }
987 }