github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/c-deps/libroach/comparator.cc (about) 1 // Copyright 2018 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 #include "comparator.h" 12 #include "encoding.h" 13 14 namespace cockroach { 15 16 int DBComparator::Compare(const rocksdb::Slice& a, const rocksdb::Slice& b) const { 17 rocksdb::Slice key_a, key_b; 18 rocksdb::Slice ts_a, ts_b; 19 if (!SplitKey(a, &key_a, &ts_a) || !SplitKey(b, &key_b, &ts_b)) { 20 // This should never happen unless there is some sort of corruption of 21 // the keys. 22 return a.compare(b); 23 } 24 25 const int c = key_a.compare(key_b); 26 if (c != 0) { 27 return c; 28 } 29 if (ts_a.empty()) { 30 if (ts_b.empty()) { 31 return 0; 32 } 33 return -1; 34 } else if (ts_b.empty()) { 35 return +1; 36 } 37 return ts_b.compare(ts_a); 38 } 39 40 bool DBComparator::Equal(const rocksdb::Slice& a, const rocksdb::Slice& b) const { return a == b; } 41 42 namespace { 43 44 void ShrinkSlice(rocksdb::Slice* a, size_t size) { a->remove_suffix(a->size() - size); } 45 46 int SharedPrefixLen(const rocksdb::Slice& a, const rocksdb::Slice& b) { 47 auto n = std::min(a.size(), b.size()); 48 int i = 0; 49 for (; i < n && a[i] == b[i]; ++i) { 50 } 51 return i; 52 } 53 54 bool FindSeparator(rocksdb::Slice* a, std::string* a_backing, const rocksdb::Slice& b) { 55 auto prefix = SharedPrefixLen(*a, b); 56 auto n = std::min(a->size(), b.size()); 57 if (prefix >= n) { 58 // The > case is not actually possible. 59 assert(prefix == n); 60 // One slice is a prefix of another. 61 return false; 62 } 63 // prefix < n. So can look at the characters at prefix, where they differed. 64 if (static_cast<unsigned char>((*a)[prefix]) >= static_cast<unsigned char>(b[prefix])) { 65 // == is not possible since they differed. 66 assert((*a)[prefix] != b[prefix]); 67 // So b is smaller than a. 68 return false; 69 } 70 if ((prefix < b.size() - 1) || 71 static_cast<unsigned char>((*a)[prefix]) + 1 < static_cast<unsigned char>(b[prefix])) { 72 // a and b do not have consecutive characters at prefix. 73 (*a_backing)[prefix]++; 74 ShrinkSlice(a, prefix + 1); 75 return true; 76 } 77 // They two slices have consecutive characters at prefix, so we leave the 78 // character at prefix unchanged for a. Now we are free to increment any 79 // subsequent character in a, to make the new a bigger than the old a. 80 ++prefix; 81 for (int i = prefix; i < a->size() - 1; ++i) { 82 if (static_cast<unsigned char>((*a)[i]) != 0xff) { 83 (*a_backing)[i]++; 84 ShrinkSlice(a, i + 1); 85 return true; 86 } 87 } 88 return false; 89 } 90 91 } // namespace 92 93 void DBComparator::FindShortestSeparator(std::string* start, const rocksdb::Slice& limit) const { 94 rocksdb::Slice key_s, key_l; 95 rocksdb::Slice ts_s, ts_l; 96 if (!SplitKey(*start, &key_s, &ts_s) || !SplitKey(limit, &key_l, &ts_l)) { 97 return; 98 } 99 auto found = FindSeparator(&key_s, start, key_l); 100 if (!found) 101 return; 102 start->resize(key_s.size() + 1); 103 (*start)[key_s.size()] = 0x00; 104 } 105 106 void DBComparator::FindShortSuccessor(std::string* key) const { 107 rocksdb::Slice k, ts; 108 if (!SplitKey(*key, &k, &ts)) { 109 return; 110 } 111 for (int i = 0; i < k.size(); ++i) { 112 if (static_cast<unsigned char>(k[i]) != 0xff) { 113 (*key)[i]++; 114 key->resize(i + 2); 115 (*key)[i + 1] = 0; 116 return; 117 } 118 } 119 } 120 121 } // namespace cockroach