1 // Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2 //  This source code is licensed under both the GPLv2 (found in the
3 //  COPYING file in the root directory) and Apache 2.0 License
4 //  (found in the LICENSE.Apache file in the root directory).
5 
6 package org.rocksdb.util;
7 
8 import org.rocksdb.AbstractComparator;
9 import org.rocksdb.BuiltinComparator;
10 import org.rocksdb.ComparatorOptions;
11 import org.rocksdb.Slice;
12 
13 import java.nio.ByteBuffer;
14 
15 /**
16  * This is a Java Native implementation of the C++
17  * equivalent ReverseBytewiseComparatorImpl using {@link Slice}
18  *
19  * The performance of Comparators implemented in Java is always
20  * less than their C++ counterparts due to the bridging overhead,
21  * as such you likely don't want to use this apart from benchmarking
22  * and you most likely instead wanted
23  * {@link BuiltinComparator#REVERSE_BYTEWISE_COMPARATOR}
24  */
25 public final class ReverseBytewiseComparator extends AbstractComparator {
26 
ReverseBytewiseComparator(final ComparatorOptions copt)27   public ReverseBytewiseComparator(final ComparatorOptions copt) {
28     super(copt);
29   }
30 
31   @Override
name()32   public String name() {
33     return "rocksdb.java.ReverseBytewiseComparator";
34   }
35 
36   @Override
compare(final ByteBuffer a, final ByteBuffer b)37   public int compare(final ByteBuffer a, final ByteBuffer b) {
38     return -BytewiseComparator._compare(a, b);
39   }
40 
41   @Override
findShortestSeparator(final ByteBuffer start, final ByteBuffer limit)42   public void findShortestSeparator(final ByteBuffer start,
43       final ByteBuffer limit) {
44     // Find length of common prefix
45     final int minLength = Math.min(start.remaining(), limit.remaining());
46     int diffIndex = 0;
47     while (diffIndex < minLength &&
48         start.get(diffIndex) == limit.get(diffIndex)) {
49       diffIndex++;
50     }
51 
52     assert(diffIndex <= minLength);
53     if (diffIndex == minLength) {
54       // Do not shorten if one string is a prefix of the other
55       //
56       // We could handle cases like:
57       //     V
58       // A A 2 X Y
59       // A A 2
60       // in a similar way as BytewiseComparator::FindShortestSeparator().
61       // We keep it simple by not implementing it. We can come back to it
62       // later when needed.
63     } else {
64       final int startByte = start.get(diffIndex) & 0xff;
65       final int limitByte = limit.get(diffIndex) & 0xff;
66       if (startByte > limitByte && diffIndex < start.remaining() - 1) {
67         // Case like
68         //     V
69         // A A 3 A A
70         // A A 1 B B
71         //
72         // or
73         //     v
74         // A A 2 A A
75         // A A 1 B B
76         // In this case "AA2" will be good.
77 //#ifndef NDEBUG
78 //        std::string old_start = *start;
79 //#endif
80         start.limit(diffIndex + 1);
81 //#ifndef NDEBUG
82 //        assert(old_start >= *start);
83 //#endif
84         assert(BytewiseComparator._compare(start.duplicate(), limit.duplicate()) > 0);
85       }
86     }
87   }
88 }
89