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