@@ -80,6 +80,14 @@ static abstract class Converter {
8080 abstract int putLong (ByteBuffer buffer , int index , long val );
8181 }
8282
83+ static abstract class CommonPrefixer {
84+ abstract int findCommonPrefix (ByteBuffer left , int leftOffset , int leftLength , byte [] right ,
85+ int rightOffset , int rightLength );
86+
87+ abstract int findCommonPrefix (ByteBuffer left , int leftOffset , int leftLength , ByteBuffer right ,
88+ int rightOffset , int rightLength );
89+ }
90+
8391 static class ComparerHolder {
8492 static final String UNSAFE_COMPARER_NAME = ComparerHolder .class .getName () + "$UnsafeComparer" ;
8593
@@ -322,6 +330,111 @@ int putLong(ByteBuffer buffer, int index, long val) {
322330 }
323331 }
324332
333+ static class CommonPrefixerHolder {
334+ static final String UNSAFE_COMMON_PREFIXER_NAME =
335+ CommonPrefixerHolder .class .getName () + "$UnsafeCommonPrefixer" ;
336+
337+ static final CommonPrefixer BEST_COMMON_PREFIXER = getBestCommonPrefixer ();
338+
339+ static CommonPrefixer getBestCommonPrefixer () {
340+ try {
341+ Class <? extends CommonPrefixer > theClass =
342+ Class .forName (UNSAFE_COMMON_PREFIXER_NAME ).asSubclass (CommonPrefixer .class );
343+
344+ return theClass .getConstructor ().newInstance ();
345+ } catch (Throwable t ) { // ensure we really catch *everything*
346+ return PureJavaCommonPrefixer .INSTANCE ;
347+ }
348+ }
349+
350+ static final class PureJavaCommonPrefixer extends CommonPrefixer {
351+ static final PureJavaCommonPrefixer INSTANCE = new PureJavaCommonPrefixer ();
352+
353+ private PureJavaCommonPrefixer () {
354+ }
355+
356+ @ Override
357+ public int findCommonPrefix (ByteBuffer left , int leftOffset , int leftLength , byte [] right ,
358+ int rightOffset , int rightLength ) {
359+ int length = Math .min (leftLength , rightLength );
360+ int result = 0 ;
361+
362+ while (
363+ result < length
364+ && ByteBufferUtils .toByte (left , leftOffset + result ) == right [rightOffset + result ]
365+ ) {
366+ result ++;
367+ }
368+
369+ return result ;
370+ }
371+
372+ @ Override
373+ int findCommonPrefix (ByteBuffer left , int leftOffset , int leftLength , ByteBuffer right ,
374+ int rightOffset , int rightLength ) {
375+ int length = Math .min (leftLength , rightLength );
376+ int result = 0 ;
377+
378+ while (
379+ result < length && ByteBufferUtils .toByte (left , leftOffset + result )
380+ == ByteBufferUtils .toByte (right , rightOffset + result )
381+ ) {
382+ result ++;
383+ }
384+
385+ return result ;
386+ }
387+ }
388+
389+ static final class UnsafeCommonPrefixer extends CommonPrefixer {
390+
391+ static {
392+ if (!UNSAFE_UNALIGNED ) {
393+ throw new Error ();
394+ }
395+ }
396+
397+ public UnsafeCommonPrefixer () {
398+ }
399+
400+ @ Override
401+ public int findCommonPrefix (ByteBuffer left , int leftOffset , int leftLength , byte [] right ,
402+ int rightOffset , int rightLength ) {
403+ long offset1Adj ;
404+ Object refObj1 = null ;
405+ if (left .isDirect ()) {
406+ offset1Adj = leftOffset + UnsafeAccess .directBufferAddress (left );
407+ } else {
408+ offset1Adj = leftOffset + left .arrayOffset () + UnsafeAccess .BYTE_ARRAY_BASE_OFFSET ;
409+ refObj1 = left .array ();
410+ }
411+ return findCommonPrefixUnsafe (refObj1 , offset1Adj , leftLength , right ,
412+ rightOffset + UnsafeAccess .BYTE_ARRAY_BASE_OFFSET , rightLength );
413+ }
414+
415+ @ Override
416+ public int findCommonPrefix (ByteBuffer left , int leftOffset , int leftLength , ByteBuffer right ,
417+ int rightOffset , int rightLength ) {
418+ long offset1Adj , offset2Adj ;
419+ Object refObj1 = null , refObj2 = null ;
420+ if (left .isDirect ()) {
421+ offset1Adj = leftOffset + UnsafeAccess .directBufferAddress (left );
422+ } else {
423+ offset1Adj = leftOffset + left .arrayOffset () + UnsafeAccess .BYTE_ARRAY_BASE_OFFSET ;
424+ refObj1 = left .array ();
425+ }
426+ if (right .isDirect ()) {
427+ offset2Adj = rightOffset + UnsafeAccess .directBufferAddress (right );
428+ } else {
429+ offset2Adj = rightOffset + right .arrayOffset () + UnsafeAccess .BYTE_ARRAY_BASE_OFFSET ;
430+ refObj2 = right .array ();
431+ }
432+ return findCommonPrefixUnsafe (refObj1 , offset1Adj , leftLength , refObj2 , offset2Adj ,
433+ rightLength );
434+ }
435+ }
436+ }
437+
325438 /**
326439 * Similar to {@link WritableUtils#writeVLong(java.io.DataOutput, long)}, but writes to a
327440 * {@link ByteBuffer}.
@@ -744,14 +857,7 @@ public static void copyFromBufferToBuffer(ByteBuffer in, ByteBuffer out, int sou
744857 */
745858 public static int findCommonPrefix (byte [] left , int leftOffset , int leftLength , byte [] right ,
746859 int rightOffset , int rightLength ) {
747- int length = Math .min (leftLength , rightLength );
748- int result = 0 ;
749-
750- while (result < length && left [leftOffset + result ] == right [rightOffset + result ]) {
751- result ++;
752- }
753-
754- return result ;
860+ return Bytes .findCommonPrefix (left , right , leftLength , rightLength , leftOffset , rightOffset );
755861 }
756862
757863 /**
@@ -765,17 +871,8 @@ public static int findCommonPrefix(byte[] left, int leftOffset, int leftLength,
765871 */
766872 public static int findCommonPrefix (ByteBuffer left , int leftOffset , int leftLength ,
767873 ByteBuffer right , int rightOffset , int rightLength ) {
768- int length = Math .min (leftLength , rightLength );
769- int result = 0 ;
770-
771- while (
772- result < length && ByteBufferUtils .toByte (left , leftOffset + result )
773- == ByteBufferUtils .toByte (right , rightOffset + result )
774- ) {
775- result ++;
776- }
777-
778- return result ;
874+ return CommonPrefixerHolder .BEST_COMMON_PREFIXER .findCommonPrefix (left , leftOffset , leftLength ,
875+ right , rightOffset , rightLength );
779876 }
780877
781878 /**
@@ -789,17 +886,8 @@ public static int findCommonPrefix(ByteBuffer left, int leftOffset, int leftLeng
789886 */
790887 public static int findCommonPrefix (ByteBuffer left , int leftOffset , int leftLength , byte [] right ,
791888 int rightOffset , int rightLength ) {
792- int length = Math .min (leftLength , rightLength );
793- int result = 0 ;
794-
795- while (
796- result < length
797- && ByteBufferUtils .toByte (left , leftOffset + result ) == right [rightOffset + result ]
798- ) {
799- result ++;
800- }
801-
802- return result ;
889+ return CommonPrefixerHolder .BEST_COMMON_PREFIXER .findCommonPrefix (left , leftOffset , leftLength ,
890+ right , rightOffset , rightLength );
803891 }
804892
805893 /**
@@ -972,6 +1060,43 @@ static int compareToUnsafe(Object obj1, long o1, int l1, Object obj2, long o2, i
9721060 return l1 - l2 ;
9731061 }
9741062
1063+ static int findCommonPrefixUnsafe (Object left , long leftOffset , int leftLength , Object right ,
1064+ long rightOffset , int rightLength ) {
1065+ final int stride = 8 ;
1066+ final int minLength = Math .min (leftLength , rightLength );
1067+ int strideLimit = minLength & ~(stride - 1 );
1068+ int result = 0 ;
1069+ int i ;
1070+
1071+ for (i = 0 ; i < strideLimit ; i += stride ) {
1072+ long lw = HBasePlatformDependent .getLong (left , leftOffset + (long ) i );
1073+ long rw = HBasePlatformDependent .getLong (right , rightOffset + (long ) i );
1074+
1075+ if (lw != rw ) {
1076+ if (!UnsafeAccess .LITTLE_ENDIAN ) {
1077+ return result + (Long .numberOfLeadingZeros (lw ^ rw ) / Bytes .SIZEOF_LONG );
1078+ } else {
1079+ return result + (Long .numberOfTrailingZeros (lw ^ rw ) / Bytes .SIZEOF_LONG );
1080+ }
1081+ } else {
1082+ result += Bytes .SIZEOF_LONG ;
1083+ }
1084+ }
1085+
1086+ // The epilogue to cover the last (minLength % stride) elements.
1087+ for (; i < minLength ; i ++) {
1088+ byte il = HBasePlatformDependent .getByte (left , leftOffset + i );
1089+ byte ir = HBasePlatformDependent .getByte (right , rightOffset + i );
1090+ if (il != ir ) {
1091+ return result ;
1092+ } else {
1093+ result ++;
1094+ }
1095+ }
1096+
1097+ return result ;
1098+ }
1099+
9751100 /**
9761101 * Reads a short value at the given buffer's offset.
9771102 * @param buffer input byte buffer to read
0 commit comments