2016-02-10 00:12:00 +01:00
|
|
|
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
2017-07-16 01:03:42 +02:00
|
|
|
// This source code is licensed under both the GPLv2 (found in the
|
|
|
|
// COPYING file in the root directory) and Apache 2.0 License
|
|
|
|
// (found in the LICENSE.Apache file in the root directory).
|
2013-10-16 23:59:46 +02:00
|
|
|
//
|
2011-03-18 23:37:00 +01:00
|
|
|
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
|
|
|
|
2019-06-01 02:19:43 +02:00
|
|
|
#include "rocksdb/comparator.h"
|
2021-06-11 15:21:55 +02:00
|
|
|
|
2019-06-01 02:19:43 +02:00
|
|
|
#include <stdint.h>
|
2021-06-11 15:21:55 +02:00
|
|
|
|
2011-07-20 01:36:47 +02:00
|
|
|
#include <algorithm>
|
2015-08-06 00:45:21 +02:00
|
|
|
#include <memory>
|
2021-06-11 15:21:55 +02:00
|
|
|
#include <mutex>
|
2022-02-08 21:14:25 +01:00
|
|
|
#include <sstream>
|
2021-06-11 15:21:55 +02:00
|
|
|
|
2022-02-08 21:14:25 +01:00
|
|
|
#include "db/dbformat.h"
|
2022-05-17 18:39:22 +02:00
|
|
|
#include "port/lang.h"
|
2012-08-27 08:45:35 +02:00
|
|
|
#include "port/port.h"
|
2021-06-29 18:07:10 +02:00
|
|
|
#include "rocksdb/convenience.h"
|
2019-06-01 02:19:43 +02:00
|
|
|
#include "rocksdb/slice.h"
|
2021-06-29 18:07:10 +02:00
|
|
|
#include "rocksdb/utilities/customizable_util.h"
|
2021-06-11 15:21:55 +02:00
|
|
|
#include "rocksdb/utilities/object_registry.h"
|
2011-03-18 23:37:00 +01:00
|
|
|
|
2020-02-20 21:07:53 +01:00
|
|
|
namespace ROCKSDB_NAMESPACE {
|
2011-03-18 23:37:00 +01:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
class BytewiseComparatorImpl : public Comparator {
|
|
|
|
public:
|
|
|
|
BytewiseComparatorImpl() { }
|
2021-06-11 15:21:55 +02:00
|
|
|
static const char* kClassName() { return "leveldb.BytewiseComparator"; }
|
|
|
|
const char* Name() const override { return kClassName(); }
|
2011-03-18 23:37:00 +01:00
|
|
|
|
2019-02-14 22:52:47 +01:00
|
|
|
int Compare(const Slice& a, const Slice& b) const override {
|
2011-03-18 23:37:00 +01:00
|
|
|
return a.compare(b);
|
|
|
|
}
|
|
|
|
|
2019-02-14 22:52:47 +01:00
|
|
|
bool Equal(const Slice& a, const Slice& b) const override { return a == b; }
|
2015-09-09 00:30:49 +02:00
|
|
|
|
2019-02-14 22:52:47 +01:00
|
|
|
void FindShortestSeparator(std::string* start,
|
|
|
|
const Slice& limit) const override {
|
2011-03-18 23:37:00 +01:00
|
|
|
// Find length of common prefix
|
|
|
|
size_t min_length = std::min(start->size(), limit.size());
|
|
|
|
size_t diff_index = 0;
|
|
|
|
while ((diff_index < min_length) &&
|
|
|
|
((*start)[diff_index] == limit[diff_index])) {
|
|
|
|
diff_index++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (diff_index >= min_length) {
|
|
|
|
// Do not shorten if one string is a prefix of the other
|
|
|
|
} else {
|
2016-04-26 08:02:14 +02:00
|
|
|
uint8_t start_byte = static_cast<uint8_t>((*start)[diff_index]);
|
|
|
|
uint8_t limit_byte = static_cast<uint8_t>(limit[diff_index]);
|
2017-05-06 00:01:04 +02:00
|
|
|
if (start_byte >= limit_byte) {
|
2016-04-26 08:02:14 +02:00
|
|
|
// Cannot shorten since limit is smaller than start or start is
|
|
|
|
// already the shortest possible.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
assert(start_byte < limit_byte);
|
|
|
|
|
|
|
|
if (diff_index < limit.size() - 1 || start_byte + 1 < limit_byte) {
|
2011-03-18 23:37:00 +01:00
|
|
|
(*start)[diff_index]++;
|
|
|
|
start->resize(diff_index + 1);
|
2016-04-26 08:02:14 +02:00
|
|
|
} else {
|
|
|
|
// v
|
|
|
|
// A A 1 A A A
|
|
|
|
// A A 2
|
|
|
|
//
|
|
|
|
// Incrementing the current byte will make start bigger than limit, we
|
|
|
|
// will skip this byte, and find the first non 0xFF byte in start and
|
|
|
|
// increment it.
|
|
|
|
diff_index++;
|
|
|
|
|
|
|
|
while (diff_index < start->size()) {
|
|
|
|
// Keep moving until we find the first non 0xFF byte to
|
|
|
|
// increment it
|
|
|
|
if (static_cast<uint8_t>((*start)[diff_index]) <
|
|
|
|
static_cast<uint8_t>(0xff)) {
|
|
|
|
(*start)[diff_index]++;
|
|
|
|
start->resize(diff_index + 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
diff_index++;
|
|
|
|
}
|
2011-03-18 23:37:00 +01:00
|
|
|
}
|
2016-04-26 08:02:14 +02:00
|
|
|
assert(Compare(*start, limit) < 0);
|
2011-03-18 23:37:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-14 22:52:47 +01:00
|
|
|
void FindShortSuccessor(std::string* key) const override {
|
2011-03-18 23:37:00 +01:00
|
|
|
// Find first character that can be incremented
|
|
|
|
size_t n = key->size();
|
2011-04-21 00:48:11 +02:00
|
|
|
for (size_t i = 0; i < n; i++) {
|
2011-03-18 23:37:00 +01:00
|
|
|
const uint8_t byte = (*key)[i];
|
|
|
|
if (byte != static_cast<uint8_t>(0xff)) {
|
|
|
|
(*key)[i] = byte + 1;
|
|
|
|
key->resize(i+1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// *key is a run of 0xffs. Leave it alone.
|
|
|
|
}
|
2018-06-27 00:56:26 +02:00
|
|
|
|
2019-02-14 22:52:47 +01:00
|
|
|
bool IsSameLengthImmediateSuccessor(const Slice& s,
|
|
|
|
const Slice& t) const override {
|
2018-06-27 00:56:26 +02:00
|
|
|
if (s.size() != t.size() || s.size() == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
size_t diff_ind = s.difference_offset(t);
|
|
|
|
// same slice
|
|
|
|
if (diff_ind >= s.size()) return false;
|
|
|
|
uint8_t byte_s = static_cast<uint8_t>(s[diff_ind]);
|
|
|
|
uint8_t byte_t = static_cast<uint8_t>(t[diff_ind]);
|
|
|
|
// first different byte must be consecutive, and remaining bytes must be
|
|
|
|
// 0xff for s and 0x00 for t
|
|
|
|
if (byte_s != uint8_t{0xff} && byte_s + 1 == byte_t) {
|
|
|
|
for (size_t i = diff_ind + 1; i < s.size(); ++i) {
|
|
|
|
byte_s = static_cast<uint8_t>(s[i]);
|
|
|
|
byte_t = static_cast<uint8_t>(t[i]);
|
|
|
|
if (byte_s != uint8_t{0xff} || byte_t != uint8_t{0x00}) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2018-08-15 23:27:47 +02:00
|
|
|
|
2019-02-14 22:52:47 +01:00
|
|
|
bool CanKeysWithDifferentByteContentsBeEqual() const override {
|
2018-08-15 23:27:47 +02:00
|
|
|
return false;
|
|
|
|
}
|
2019-06-06 08:07:28 +02:00
|
|
|
|
2020-03-07 01:21:03 +01:00
|
|
|
using Comparator::CompareWithoutTimestamp;
|
|
|
|
int CompareWithoutTimestamp(const Slice& a, bool /*a_has_ts*/, const Slice& b,
|
|
|
|
bool /*b_has_ts*/) const override {
|
2019-06-06 08:07:28 +02:00
|
|
|
return a.compare(b);
|
|
|
|
}
|
2021-03-10 20:13:55 +01:00
|
|
|
|
|
|
|
bool EqualWithoutTimestamp(const Slice& a, const Slice& b) const override {
|
|
|
|
return a == b;
|
|
|
|
}
|
2011-03-18 23:37:00 +01:00
|
|
|
};
|
2014-09-26 10:35:12 +02:00
|
|
|
|
|
|
|
class ReverseBytewiseComparatorImpl : public BytewiseComparatorImpl {
|
|
|
|
public:
|
|
|
|
ReverseBytewiseComparatorImpl() { }
|
|
|
|
|
2021-06-11 15:21:55 +02:00
|
|
|
static const char* kClassName() {
|
2014-09-27 10:06:13 +02:00
|
|
|
return "rocksdb.ReverseBytewiseComparator";
|
2014-09-26 10:35:12 +02:00
|
|
|
}
|
2021-06-11 15:21:55 +02:00
|
|
|
const char* Name() const override { return kClassName(); }
|
2014-09-26 10:35:12 +02:00
|
|
|
|
2019-02-14 22:52:47 +01:00
|
|
|
int Compare(const Slice& a, const Slice& b) const override {
|
2014-09-26 10:35:12 +02:00
|
|
|
return -a.compare(b);
|
|
|
|
}
|
|
|
|
|
2018-05-18 03:24:20 +02:00
|
|
|
void FindShortestSeparator(std::string* start,
|
|
|
|
const Slice& limit) const override {
|
|
|
|
// Find length of common prefix
|
|
|
|
size_t min_length = std::min(start->size(), limit.size());
|
|
|
|
size_t diff_index = 0;
|
|
|
|
while ((diff_index < min_length) &&
|
|
|
|
((*start)[diff_index] == limit[diff_index])) {
|
|
|
|
diff_index++;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(diff_index <= min_length);
|
|
|
|
if (diff_index == min_length) {
|
|
|
|
// Do not shorten if one string is a prefix of the other
|
|
|
|
//
|
|
|
|
// We could handle cases like:
|
|
|
|
// V
|
|
|
|
// A A 2 X Y
|
|
|
|
// A A 2
|
|
|
|
// in a similar way as BytewiseComparator::FindShortestSeparator().
|
|
|
|
// We keep it simple by not implementing it. We can come back to it
|
|
|
|
// later when needed.
|
|
|
|
} else {
|
|
|
|
uint8_t start_byte = static_cast<uint8_t>((*start)[diff_index]);
|
|
|
|
uint8_t limit_byte = static_cast<uint8_t>(limit[diff_index]);
|
|
|
|
if (start_byte > limit_byte && diff_index < start->size() - 1) {
|
|
|
|
// Case like
|
|
|
|
// V
|
|
|
|
// A A 3 A A
|
|
|
|
// A A 1 B B
|
|
|
|
//
|
|
|
|
// or
|
|
|
|
// v
|
|
|
|
// A A 2 A A
|
|
|
|
// A A 1 B B
|
|
|
|
// In this case "AA2" will be good.
|
|
|
|
#ifndef NDEBUG
|
|
|
|
std::string old_start = *start;
|
|
|
|
#endif
|
|
|
|
start->resize(diff_index + 1);
|
|
|
|
#ifndef NDEBUG
|
|
|
|
assert(old_start >= *start);
|
|
|
|
#endif
|
|
|
|
assert(Slice(*start).compare(limit) > 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void FindShortSuccessor(std::string* /*key*/) const override {
|
|
|
|
// Don't do anything for simplicity.
|
|
|
|
}
|
2018-08-15 23:27:47 +02:00
|
|
|
|
2019-02-14 22:52:47 +01:00
|
|
|
bool CanKeysWithDifferentByteContentsBeEqual() const override {
|
2018-08-15 23:27:47 +02:00
|
|
|
return false;
|
|
|
|
}
|
2019-06-06 08:07:28 +02:00
|
|
|
|
2020-03-07 01:21:03 +01:00
|
|
|
using Comparator::CompareWithoutTimestamp;
|
|
|
|
int CompareWithoutTimestamp(const Slice& a, bool /*a_has_ts*/, const Slice& b,
|
|
|
|
bool /*b_has_ts*/) const override {
|
2019-06-06 08:07:28 +02:00
|
|
|
return -a.compare(b);
|
|
|
|
}
|
2018-05-18 03:24:20 +02:00
|
|
|
};
|
2022-02-08 21:14:25 +01:00
|
|
|
|
|
|
|
// EXPERIMENTAL
|
|
|
|
// Comparator with 64-bit integer timestamp.
|
|
|
|
// We did not performance test this yet.
|
|
|
|
template <typename TComparator>
|
|
|
|
class ComparatorWithU64TsImpl : public Comparator {
|
|
|
|
static_assert(std::is_base_of<Comparator, TComparator>::value,
|
|
|
|
"template type must be a inherited type of comparator");
|
|
|
|
|
|
|
|
public:
|
|
|
|
explicit ComparatorWithU64TsImpl() : Comparator(/*ts_sz=*/sizeof(uint64_t)) {
|
|
|
|
assert(cmp_without_ts_.timestamp_size() == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char* kClassName() {
|
|
|
|
static std::string class_name = kClassNameInternal();
|
|
|
|
return class_name.c_str();
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* Name() const override { return kClassName(); }
|
|
|
|
|
|
|
|
void FindShortSuccessor(std::string*) const override {}
|
|
|
|
void FindShortestSeparator(std::string*, const Slice&) const override {}
|
|
|
|
int Compare(const Slice& a, const Slice& b) const override {
|
|
|
|
int ret = CompareWithoutTimestamp(a, b);
|
|
|
|
size_t ts_sz = timestamp_size();
|
|
|
|
if (ret != 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
// Compare timestamp.
|
|
|
|
// For the same user key with different timestamps, larger (newer) timestamp
|
|
|
|
// comes first.
|
|
|
|
return -CompareTimestamp(ExtractTimestampFromUserKey(a, ts_sz),
|
|
|
|
ExtractTimestampFromUserKey(b, ts_sz));
|
|
|
|
}
|
|
|
|
using Comparator::CompareWithoutTimestamp;
|
|
|
|
int CompareWithoutTimestamp(const Slice& a, bool a_has_ts, const Slice& b,
|
|
|
|
bool b_has_ts) const override {
|
|
|
|
const size_t ts_sz = timestamp_size();
|
|
|
|
assert(!a_has_ts || a.size() >= ts_sz);
|
|
|
|
assert(!b_has_ts || b.size() >= ts_sz);
|
|
|
|
Slice lhs = a_has_ts ? StripTimestampFromUserKey(a, ts_sz) : a;
|
|
|
|
Slice rhs = b_has_ts ? StripTimestampFromUserKey(b, ts_sz) : b;
|
|
|
|
return cmp_without_ts_.Compare(lhs, rhs);
|
|
|
|
}
|
|
|
|
int CompareTimestamp(const Slice& ts1, const Slice& ts2) const override {
|
|
|
|
assert(ts1.size() == sizeof(uint64_t));
|
|
|
|
assert(ts2.size() == sizeof(uint64_t));
|
|
|
|
uint64_t lhs = DecodeFixed64(ts1.data());
|
|
|
|
uint64_t rhs = DecodeFixed64(ts2.data());
|
|
|
|
if (lhs < rhs) {
|
|
|
|
return -1;
|
|
|
|
} else if (lhs > rhs) {
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
static std::string kClassNameInternal() {
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << TComparator::kClassName() << ".u64ts";
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
TComparator cmp_without_ts_;
|
|
|
|
};
|
|
|
|
|
2014-09-26 10:35:12 +02:00
|
|
|
}// namespace
|
2011-11-14 18:06:16 +01:00
|
|
|
|
2011-03-18 23:37:00 +01:00
|
|
|
const Comparator* BytewiseComparator() {
|
2022-05-17 18:39:22 +02:00
|
|
|
STATIC_AVOID_DESTRUCTION(BytewiseComparatorImpl, bytewise);
|
2015-08-11 19:55:27 +02:00
|
|
|
return &bytewise;
|
2011-03-18 23:37:00 +01:00
|
|
|
}
|
|
|
|
|
2014-09-26 10:35:12 +02:00
|
|
|
const Comparator* ReverseBytewiseComparator() {
|
2022-05-17 18:39:22 +02:00
|
|
|
STATIC_AVOID_DESTRUCTION(ReverseBytewiseComparatorImpl, rbytewise);
|
2015-08-11 19:55:27 +02:00
|
|
|
return &rbytewise;
|
2014-09-26 10:35:12 +02:00
|
|
|
}
|
|
|
|
|
2022-02-08 21:14:25 +01:00
|
|
|
const Comparator* BytewiseComparatorWithU64Ts() {
|
2022-05-17 18:39:22 +02:00
|
|
|
STATIC_AVOID_DESTRUCTION(ComparatorWithU64TsImpl<BytewiseComparatorImpl>,
|
|
|
|
comp_with_u64_ts);
|
2022-02-08 21:14:25 +01:00
|
|
|
return &comp_with_u64_ts;
|
|
|
|
}
|
|
|
|
|
2021-06-11 15:21:55 +02:00
|
|
|
#ifndef ROCKSDB_LITE
|
|
|
|
static int RegisterBuiltinComparators(ObjectLibrary& library,
|
|
|
|
const std::string& /*arg*/) {
|
2022-01-11 15:32:42 +01:00
|
|
|
library.AddFactory<const Comparator>(
|
2021-06-11 15:21:55 +02:00
|
|
|
BytewiseComparatorImpl::kClassName(),
|
|
|
|
[](const std::string& /*uri*/,
|
|
|
|
std::unique_ptr<const Comparator>* /*guard */,
|
|
|
|
std::string* /* errmsg */) { return BytewiseComparator(); });
|
2022-01-11 15:32:42 +01:00
|
|
|
library.AddFactory<const Comparator>(
|
2021-06-11 15:21:55 +02:00
|
|
|
ReverseBytewiseComparatorImpl::kClassName(),
|
|
|
|
[](const std::string& /*uri*/,
|
|
|
|
std::unique_ptr<const Comparator>* /*guard */,
|
|
|
|
std::string* /* errmsg */) { return ReverseBytewiseComparator(); });
|
2022-02-08 21:14:25 +01:00
|
|
|
library.AddFactory<const Comparator>(
|
|
|
|
ComparatorWithU64TsImpl<BytewiseComparatorImpl>::kClassName(),
|
|
|
|
[](const std::string& /*uri*/,
|
|
|
|
std::unique_ptr<const Comparator>* /*guard */,
|
|
|
|
std::string* /* errmsg */) { return BytewiseComparatorWithU64Ts(); });
|
|
|
|
return 3;
|
2021-06-11 15:21:55 +02:00
|
|
|
}
|
|
|
|
#endif // ROCKSDB_LITE
|
|
|
|
|
|
|
|
Status Comparator::CreateFromString(const ConfigOptions& config_options,
|
|
|
|
const std::string& value,
|
|
|
|
const Comparator** result) {
|
|
|
|
#ifndef ROCKSDB_LITE
|
|
|
|
static std::once_flag once;
|
|
|
|
std::call_once(once, [&]() {
|
|
|
|
RegisterBuiltinComparators(*(ObjectLibrary::Default().get()), "");
|
|
|
|
});
|
|
|
|
#endif // ROCKSDB_LITE
|
|
|
|
std::string id;
|
|
|
|
std::unordered_map<std::string, std::string> opt_map;
|
2021-06-29 18:07:10 +02:00
|
|
|
Status status = Customizable::GetOptionsMap(config_options, *result, value,
|
|
|
|
&id, &opt_map);
|
2021-06-11 15:21:55 +02:00
|
|
|
if (!status.ok()) { // GetOptionsMap failed
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
if (id == BytewiseComparatorImpl::kClassName()) {
|
|
|
|
*result = BytewiseComparator();
|
|
|
|
} else if (id == ReverseBytewiseComparatorImpl::kClassName()) {
|
|
|
|
*result = ReverseBytewiseComparator();
|
2022-02-08 21:14:25 +01:00
|
|
|
} else if (id ==
|
|
|
|
ComparatorWithU64TsImpl<BytewiseComparatorImpl>::kClassName()) {
|
|
|
|
*result = BytewiseComparatorWithU64Ts();
|
2021-06-11 15:21:55 +02:00
|
|
|
} else if (value.empty()) {
|
|
|
|
// No Id and no options. Clear the object
|
|
|
|
*result = nullptr;
|
|
|
|
return Status::OK();
|
|
|
|
} else if (id.empty()) { // We have no Id but have options. Not good
|
|
|
|
return Status::NotSupported("Cannot reset object ", id);
|
|
|
|
} else {
|
|
|
|
#ifndef ROCKSDB_LITE
|
|
|
|
status = config_options.registry->NewStaticObject(id, result);
|
|
|
|
#else
|
|
|
|
status = Status::NotSupported("Cannot load object in LITE mode ", id);
|
|
|
|
#endif // ROCKSDB_LITE
|
|
|
|
if (!status.ok()) {
|
|
|
|
if (config_options.ignore_unsupported_options &&
|
|
|
|
status.IsNotSupported()) {
|
|
|
|
return Status::OK();
|
|
|
|
} else {
|
|
|
|
return status;
|
|
|
|
}
|
2022-02-11 14:10:10 +01:00
|
|
|
} else {
|
2021-06-11 15:21:55 +02:00
|
|
|
Comparator* comparator = const_cast<Comparator*>(*result);
|
2022-02-11 14:10:10 +01:00
|
|
|
status =
|
|
|
|
Customizable::ConfigureNewObject(config_options, comparator, opt_map);
|
2021-06-11 15:21:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
2020-02-20 21:07:53 +01:00
|
|
|
} // namespace ROCKSDB_NAMESPACE
|