mirror of
https://github.com/facebook/rocksdb.git
synced 2026-07-08 07:05:23 +08:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 51b540921d | |||
| e8b841eb47 | |||
| 6ee0acdbb4 | |||
| 6fc2818ef8 | |||
| 5881f4ac50 | |||
| 28aa6d4e76 | |||
| 9d7de9605a | |||
| f64f08e0bc |
+9
-3
@@ -1,5 +1,9 @@
|
||||
# Rocksdb Change Log
|
||||
## Unreleased
|
||||
## 6.22.1 (2021-06-25)
|
||||
### Bug Fixes
|
||||
* `GetLiveFilesMetaData()` now populates the `temperature`, `oldest_ancester_time`, and `file_creation_time` fields of its `LiveFileMetaData` results when the information is available. Previously these fields always contained zero indicating unknown.
|
||||
|
||||
## 6.22.0 (2021-06-18)
|
||||
### Behavior Changes
|
||||
* Added two additional tickers, MEMTABLE_PAYLOAD_BYTES_AT_FLUSH and MEMTABLE_GARBAGE_BYTES_AT_FLUSH. These stats can be used to estimate the ratio of "garbage" (outdated) bytes in the memtable that are discarded at flush time.
|
||||
* Added API comments clarifying safe usage of Disable/EnableManualCompaction and EventListener callbacks for compaction.
|
||||
@@ -7,11 +11,15 @@
|
||||
### Bug Fixes
|
||||
* fs_posix.cc GetFreeSpace() always report disk space available to root even when running as non-root. Linux defaults often have disk mounts with 5 to 10 percent of total space reserved only for root. Out of space could result for non-root users.
|
||||
* Subcompactions are now disabled when user-defined timestamps are used, since the subcompaction boundary picking logic is currently not timestamp-aware, which could lead to incorrect results when different subcompactions process keys that only differ by timestamp.
|
||||
* Fix an issue that `DeleteFilesInRange()` may cause ongoing compaction reports corruption exception, or ASSERT for debug build. There's no actual data loss or corruption that we find.
|
||||
* Fixed confusingly duplicated output in LOG for periodic stats ("DUMPING STATS"), including "Compaction Stats" and "File Read Latency Histogram By Level".
|
||||
* Fixed performance bugs in background gathering of block cache entry statistics, that could consume a lot of CPU when there are many column families with a shared block cache.
|
||||
|
||||
### New Features
|
||||
* Marked the Ribbon filter and optimize_filters_for_memory features as production-ready, each enabling memory savings for Bloom-like filters. Use `NewRibbonFilterPolicy` in place of `NewBloomFilterPolicy` to use Ribbon filters instead of Bloom, or `ribbonfilter` in place of `bloomfilter` in configuration string.
|
||||
* Allow `DBWithTTL` to use `DeleteRange` api just like other DBs. `DeleteRangeCF()` which executes `WriteBatchInternal::DeleteRange()` has been added to the handler in `DBWithTTLImpl::Write()` to implement it.
|
||||
* Add BlockBasedTableOptions.prepopulate_block_cache. If enabled, it prepopulate warm/hot data blocks which are already in memory into block cache at the time of flush. On a flush, the data block that is in memory (in memtables) get flushed to the device. If using Direct IO, additional IO is incurred to read this data back into memory again, which is avoided by enabling this option and it also helps with Distributed FileSystem. More details in include/rocksdb/table.h.
|
||||
* Added a `cancel` field to `CompactRangeOptions`, allowing individual in-process manual range compactions to be cancelled.
|
||||
|
||||
## 6.21.0 (2021-05-21)
|
||||
### Bug Fixes
|
||||
@@ -23,7 +31,6 @@
|
||||
* Handle return code by io_uring_submit_and_wait() and io_uring_wait_cqe().
|
||||
* In the IngestExternalFile() API, only try to sync the ingested file if the file is linked and the FileSystem/Env supports reopening a writable file.
|
||||
* Fixed a bug that `AdvancedColumnFamilyOptions.max_compaction_bytes` is under-calculated for manual compaction (`CompactRange()`). Manual compaction is split to multiple compactions if the compaction size exceed the `max_compaction_bytes`. The bug creates much larger compaction which size exceed the user setting. On the other hand, larger manual compaction size can increase the subcompaction parallelism, you can tune that by setting `max_compaction_bytes`.
|
||||
* Fixed confusingly duplicated output in LOG for periodic stats ("DUMPING STATS"), including "Compaction Stats" and "File Read Latency Histogram By Level".
|
||||
|
||||
### Behavior Changes
|
||||
* Due to the fix of false-postive alert of "SST file is ahead of WAL", all the CFs with no SST file (CF empty) will bypass the consistency check. We fixed a false-positive, but introduced a very rare true-negative which will be triggered in the following conditions: A CF with some delete operations in the last a few queries which will result in an empty CF (those are flushed to SST file and a compaction triggered which combines this file and all other SST files and generates an empty CF, or there is another reason to write a manifest entry for this CF after a flush that generates no SST file from an empty CF). The deletion entries are logged in a WAL and this WAL was corrupted, while the CF's log number points to the next WAL (due to the flush). Therefore, the DB can only recover to the point without these trailing deletions and cause the inconsistent DB status.
|
||||
@@ -36,7 +43,6 @@
|
||||
* Add an experimental Remote Compaction feature, which allows the user to run Compaction on a different host or process. The feature is still under development, currently only works on some basic use cases. The interface will be changed without backward/forward compatibility support.
|
||||
* RocksDB would validate total entries read in flush, and compare with counter inserted into it. If flush_verify_memtable_count = true (default), flush will fail. Otherwise, only log to info logs.
|
||||
* Add `TableProperties::num_filter_entries`, which can be used with `TableProperties::filter_size` to calculate the effective bits per filter entry (unique user key or prefix) for a table file.
|
||||
* Added a `cancel` field to `CompactRangeOptions`, allowing individual in-process manual range compactions to be cancelled.
|
||||
|
||||
### Performance Improvements
|
||||
* BlockPrefetcher is used by iterators to prefetch data if they anticipate more data to be used in future. It is enabled implicitly by rocksdb. Added change to take in account read pattern if reads are sequential. This would disable prefetching for random reads in MultiGet and iterators as readahead_size is increased exponential doing large prefetches.
|
||||
|
||||
@@ -516,8 +516,10 @@ endif
|
||||
ifdef ASSERT_STATUS_CHECKED
|
||||
# TODO: finish fixing all tests to pass this check
|
||||
TESTS_FAILING_ASC = \
|
||||
c_test \
|
||||
db_test \
|
||||
db_test2 \
|
||||
env_test \
|
||||
range_locking_test \
|
||||
testutil_test \
|
||||
|
||||
|
||||
Vendored
+2
-5
@@ -596,15 +596,12 @@ void LRUCacheShard::Erase(const Slice& key, uint32_t hash) {
|
||||
|
||||
bool LRUCacheShard::IsReady(Cache::Handle* handle) {
|
||||
LRUHandle* e = reinterpret_cast<LRUHandle*>(handle);
|
||||
MutexLock l(&mutex_);
|
||||
bool ready = true;
|
||||
if (e->IsPending()) {
|
||||
assert(secondary_cache_);
|
||||
assert(e->sec_handle);
|
||||
if (e->sec_handle->IsReady()) {
|
||||
Promote(e);
|
||||
} else {
|
||||
ready = false;
|
||||
}
|
||||
ready = e->sec_handle->IsReady();
|
||||
}
|
||||
return ready;
|
||||
}
|
||||
|
||||
@@ -3600,6 +3600,41 @@ TEST_F(DBCompactionTest, CompactFilesOverlapInL0Bug) {
|
||||
ASSERT_EQ("new_val", Get(Key(0)));
|
||||
}
|
||||
|
||||
TEST_F(DBCompactionTest, DeleteFilesInRangeConflictWithCompaction) {
|
||||
Options options = CurrentOptions();
|
||||
DestroyAndReopen(options);
|
||||
const Snapshot* snapshot = nullptr;
|
||||
const int kMaxKey = 10;
|
||||
|
||||
for (int i = 0; i < kMaxKey; i++) {
|
||||
ASSERT_OK(Put(Key(i), Key(i)));
|
||||
ASSERT_OK(Delete(Key(i)));
|
||||
if (!snapshot) {
|
||||
snapshot = db_->GetSnapshot();
|
||||
}
|
||||
}
|
||||
ASSERT_OK(Flush());
|
||||
MoveFilesToLevel(1);
|
||||
ASSERT_OK(Put(Key(kMaxKey), Key(kMaxKey)));
|
||||
ASSERT_OK(dbfull()->TEST_WaitForCompact());
|
||||
// test DeleteFilesInRange() deletes the files already picked for compaction
|
||||
SyncPoint::GetInstance()->LoadDependency(
|
||||
{{"VersionSet::LogAndApply:WriteManifestStart",
|
||||
"BackgroundCallCompaction:0"},
|
||||
{"DBImpl::BackgroundCompaction:Finish",
|
||||
"VersionSet::LogAndApply:WriteManifestDone"}});
|
||||
SyncPoint::GetInstance()->EnableProcessing();
|
||||
|
||||
// release snapshot which mark bottommost file for compaction
|
||||
db_->ReleaseSnapshot(snapshot);
|
||||
std::string begin_string = Key(0);
|
||||
std::string end_string = Key(kMaxKey + 1);
|
||||
Slice begin(begin_string);
|
||||
Slice end(end_string);
|
||||
ASSERT_OK(DeleteFilesInRange(db_, db_->DefaultColumnFamily(), &begin, &end));
|
||||
SyncPoint::GetInstance()->DisableProcessing();
|
||||
}
|
||||
|
||||
TEST_F(DBCompactionTest, CompactBottomLevelFilesWithDeletions) {
|
||||
// bottom-level files may contain deletions due to snapshots protecting the
|
||||
// deleted keys. Once the snapshot is released, we should see files with many
|
||||
|
||||
@@ -3709,6 +3709,8 @@ Status DBImpl::DeleteFilesInRanges(ColumnFamilyHandle* column_family,
|
||||
deleted_files.insert(level_file);
|
||||
level_file->being_compacted = true;
|
||||
}
|
||||
vstorage->ComputeCompactionScore(*cfd->ioptions(),
|
||||
*cfd->GetLatestMutableCFOptions());
|
||||
}
|
||||
}
|
||||
if (edit.GetDeletedFiles().empty()) {
|
||||
|
||||
+4
-1
@@ -4092,7 +4092,7 @@ Status VersionSet::ProcessManifestWrites(
|
||||
{
|
||||
FileOptions opt_file_opts = fs_->OptimizeForManifestWrite(file_options_);
|
||||
mu->Unlock();
|
||||
|
||||
TEST_SYNC_POINT("VersionSet::LogAndApply:WriteManifestStart");
|
||||
TEST_SYNC_POINT_CALLBACK("VersionSet::LogAndApply:WriteManifest", nullptr);
|
||||
if (!first_writer.edit_list.front()->IsColumnFamilyManipulation()) {
|
||||
for (int i = 0; i < static_cast<int>(versions.size()); ++i) {
|
||||
@@ -5590,6 +5590,9 @@ void VersionSet::GetLiveFilesMetaData(std::vector<LiveFileMetaData>* metadata) {
|
||||
filemetadata.oldest_blob_file_number = file->oldest_blob_file_number;
|
||||
filemetadata.file_checksum = file->file_checksum;
|
||||
filemetadata.file_checksum_func_name = file->file_checksum_func_name;
|
||||
filemetadata.temperature = file->temperature;
|
||||
filemetadata.oldest_ancester_time = file->TryGetOldestAncesterTime();
|
||||
filemetadata.file_creation_time = file->TryGetFileCreationTime();
|
||||
metadata->push_back(filemetadata);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "rocksdb/customizable.h"
|
||||
#include "rocksdb/rocksdb_namespace.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
@@ -21,7 +20,7 @@ class Slice;
|
||||
// used as keys in an sstable or a database. A Comparator implementation
|
||||
// must be thread-safe since rocksdb may invoke its methods concurrently
|
||||
// from multiple threads.
|
||||
class Comparator : public Customizable {
|
||||
class Comparator {
|
||||
public:
|
||||
Comparator() : timestamp_size_(0) {}
|
||||
|
||||
@@ -38,11 +37,7 @@ class Comparator : public Customizable {
|
||||
|
||||
virtual ~Comparator() {}
|
||||
|
||||
static Status CreateFromString(const ConfigOptions& opts,
|
||||
const std::string& id,
|
||||
const Comparator** comp);
|
||||
static const char* Type() { return "Comparator"; }
|
||||
|
||||
// Three-way comparison. Returns value:
|
||||
// < 0 iff "a" < "b",
|
||||
// == 0 iff "a" == "b",
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
@@ -270,7 +269,7 @@ class Configurable {
|
||||
protected:
|
||||
// True once the object is prepared. Once the object is prepared, only
|
||||
// mutable options can be configured.
|
||||
std::atomic<bool> prepared_;
|
||||
bool prepared_;
|
||||
|
||||
// Returns the raw pointer for the associated named option.
|
||||
// The name is typically the name of an option registered via the
|
||||
|
||||
@@ -35,6 +35,7 @@ enum class OptionType {
|
||||
kCompactionPri,
|
||||
kSliceTransform,
|
||||
kCompressionType,
|
||||
kComparator,
|
||||
kCompactionFilter,
|
||||
kCompactionFilterFactory,
|
||||
kCompactionStopStyle,
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
#include "rocksdb/rocksdb_namespace.h"
|
||||
|
||||
#define ROCKSDB_MAJOR 6
|
||||
#define ROCKSDB_MINOR 21
|
||||
#define ROCKSDB_PATCH 0
|
||||
#define ROCKSDB_MINOR 22
|
||||
#define ROCKSDB_PATCH 1
|
||||
|
||||
// Do not use these. We made the mistake of declaring macros starting with
|
||||
// double underscore. Now we have to live with our choice. We'll deprecate these
|
||||
|
||||
+16
-24
@@ -535,30 +535,22 @@ static std::unordered_map<std::string, OptionTypeInfo>
|
||||
OptionVerificationType::kNormal, OptionTypeFlags::kNone,
|
||||
{0, OptionType::kCompressionType})},
|
||||
{"comparator",
|
||||
OptionTypeInfo::AsCustomRawPtr<const Comparator>(
|
||||
offset_of(&ImmutableCFOptions::user_comparator),
|
||||
OptionVerificationType::kByName, OptionTypeFlags::kCompareLoose,
|
||||
// Serializes a Comparator
|
||||
[](const ConfigOptions& /*opts*/, const std::string&,
|
||||
const void* addr, std::string* value) {
|
||||
// it's a const pointer of const Comparator*
|
||||
const auto* ptr = static_cast<const Comparator* const*>(addr);
|
||||
|
||||
// Since the user-specified comparator will be wrapped by
|
||||
// InternalKeyComparator, we should persist the user-specified
|
||||
// one instead of InternalKeyComparator.
|
||||
if (*ptr == nullptr) {
|
||||
*value = kNullptrString;
|
||||
} else {
|
||||
const Comparator* root_comp = (*ptr)->GetRootComparator();
|
||||
if (root_comp == nullptr) {
|
||||
root_comp = (*ptr);
|
||||
}
|
||||
*value = root_comp->Name();
|
||||
}
|
||||
return Status::OK();
|
||||
},
|
||||
/* Use the default match function*/ nullptr)},
|
||||
{offset_of(&ImmutableCFOptions::user_comparator),
|
||||
OptionType::kComparator, OptionVerificationType::kByName,
|
||||
OptionTypeFlags::kCompareLoose,
|
||||
// Parses the string and sets the corresponding comparator
|
||||
[](const ConfigOptions& opts, const std::string& /*name*/,
|
||||
const std::string& value, void* addr) {
|
||||
auto old_comparator = static_cast<const Comparator**>(addr);
|
||||
const Comparator* new_comparator = *old_comparator;
|
||||
Status status =
|
||||
opts.registry->NewStaticObject(value, &new_comparator);
|
||||
if (status.ok()) {
|
||||
*old_comparator = new_comparator;
|
||||
return status;
|
||||
}
|
||||
return Status::OK();
|
||||
}}},
|
||||
{"memtable_insert_with_hint_prefix_extractor",
|
||||
{offset_of(
|
||||
&ImmutableCFOptions::memtable_insert_with_hint_prefix_extractor),
|
||||
|
||||
@@ -771,15 +771,6 @@ static int RegisterTestObjects(ObjectLibrary& library,
|
||||
guard->reset(new mock::MockTableFactory());
|
||||
return guard->get();
|
||||
});
|
||||
library.Register<const Comparator>(
|
||||
test::SimpleSuffixReverseComparator::kClassName(),
|
||||
[](const std::string& /*uri*/,
|
||||
std::unique_ptr<const Comparator>* /*guard*/,
|
||||
std::string* /* errmsg */) {
|
||||
static test::SimpleSuffixReverseComparator ssrc;
|
||||
return &ssrc;
|
||||
});
|
||||
|
||||
return static_cast<int>(library.GetFactoryCount(&num_types));
|
||||
}
|
||||
|
||||
@@ -789,7 +780,6 @@ static int RegisterLocalObjects(ObjectLibrary& library,
|
||||
// Load any locally defined objects here
|
||||
return static_cast<int>(library.GetFactoryCount(&num_types));
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
class LoadCustomizableTest : public testing::Test {
|
||||
public:
|
||||
@@ -829,31 +819,7 @@ TEST_F(LoadCustomizableTest, LoadTableFactoryTest) {
|
||||
ASSERT_STREQ(factory->Name(), "MockTable");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(LoadCustomizableTest, LoadComparatorTest) {
|
||||
const Comparator* bytewise = BytewiseComparator();
|
||||
const Comparator* reverse = ReverseBytewiseComparator();
|
||||
|
||||
const Comparator* result = nullptr;
|
||||
ASSERT_NOK(Comparator::CreateFromString(
|
||||
config_options_, test::SimpleSuffixReverseComparator::kClassName(),
|
||||
&result));
|
||||
ASSERT_OK(
|
||||
Comparator::CreateFromString(config_options_, bytewise->Name(), &result));
|
||||
ASSERT_EQ(result, bytewise);
|
||||
ASSERT_OK(
|
||||
Comparator::CreateFromString(config_options_, reverse->Name(), &result));
|
||||
ASSERT_EQ(result, reverse);
|
||||
|
||||
if (RegisterTests("Test")) {
|
||||
ASSERT_OK(Comparator::CreateFromString(
|
||||
config_options_, test::SimpleSuffixReverseComparator::kClassName(),
|
||||
&result));
|
||||
ASSERT_NE(result, nullptr);
|
||||
ASSERT_STREQ(result->Name(),
|
||||
test::SimpleSuffixReverseComparator::kClassName());
|
||||
}
|
||||
}
|
||||
#endif // !ROCKSDB_LITE
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
int main(int argc, char** argv) {
|
||||
|
||||
@@ -562,6 +562,23 @@ bool SerializeSingleOptionHelper(const void* opt_address,
|
||||
: kNullptrString;
|
||||
break;
|
||||
}
|
||||
case OptionType::kComparator: {
|
||||
// it's a const pointer of const Comparator*
|
||||
const auto* ptr = static_cast<const Comparator* const*>(opt_address);
|
||||
// Since the user-specified comparator will be wrapped by
|
||||
// InternalKeyComparator, we should persist the user-specified one
|
||||
// instead of InternalKeyComparator.
|
||||
if (*ptr == nullptr) {
|
||||
*value = kNullptrString;
|
||||
} else {
|
||||
const Comparator* root_comp = (*ptr)->GetRootComparator();
|
||||
if (root_comp == nullptr) {
|
||||
root_comp = (*ptr);
|
||||
}
|
||||
*value = root_comp->Name();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OptionType::kCompactionFilter: {
|
||||
// it's a const pointer of const CompactionFilter*
|
||||
const auto* ptr =
|
||||
|
||||
@@ -2564,24 +2564,21 @@ void BlockBasedTable::MultiGet(const ReadOptions& read_options,
|
||||
s = Status::OK();
|
||||
}
|
||||
if (s.ok() && !results.back().IsEmpty()) {
|
||||
if (results.back().IsReady()) {
|
||||
// Since we have a valid handle, check the value. If its nullptr,
|
||||
// it means the cache is waiting for the final result and we're
|
||||
// supposed to call WaitAll() to wait for the result.
|
||||
if (results.back().GetValue() != nullptr) {
|
||||
// Found it in the cache. Add NULL handle to indicate there is
|
||||
// nothing to read from disk.
|
||||
if (results.back().GetCacheHandle()) {
|
||||
results.back().UpdateCachedValue();
|
||||
// Its possible the cache lookup returned a non-null handle,
|
||||
// but the lookup actually failed to produce a valid value
|
||||
if (results.back().GetValue() == nullptr) {
|
||||
block_handles.emplace_back(handle);
|
||||
total_len += block_size(handle);
|
||||
}
|
||||
}
|
||||
if (results.back().GetValue() != nullptr) {
|
||||
block_handles.emplace_back(BlockHandle::NullBlockHandle());
|
||||
}
|
||||
block_handles.emplace_back(BlockHandle::NullBlockHandle());
|
||||
} else {
|
||||
// We have to wait for the asynchronous cache lookup to finish,
|
||||
// and then we may have to read the block from disk anyway
|
||||
// We have to wait for the cache lookup to finish in the
|
||||
// background, and then we may have to read the block from disk
|
||||
// anyway
|
||||
assert(results.back().GetCacheHandle());
|
||||
wait_for_cache_results = true;
|
||||
block_handles.emplace_back(handle);
|
||||
cache_handles.emplace_back(results.back().GetCacheHandle());
|
||||
|
||||
@@ -98,8 +98,10 @@ class PlainInternalKeyComparator : public InternalKeyComparator {
|
||||
class SimpleSuffixReverseComparator : public Comparator {
|
||||
public:
|
||||
SimpleSuffixReverseComparator() {}
|
||||
static const char* kClassName() { return "SimpleSuffixReverseComparator"; }
|
||||
virtual const char* Name() const override { return kClassName(); }
|
||||
|
||||
virtual const char* Name() const override {
|
||||
return "SimpleSuffixReverseComparator";
|
||||
}
|
||||
|
||||
virtual int Compare(const Slice& a, const Slice& b) const override {
|
||||
Slice prefix_a = Slice(a.data(), 8);
|
||||
|
||||
+3
-83
@@ -8,17 +8,11 @@
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
|
||||
#include "rocksdb/comparator.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include "options/configurable_helper.h"
|
||||
#include "port/port.h"
|
||||
#include "rocksdb/slice.h"
|
||||
#include "rocksdb/utilities/object_registry.h"
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
|
||||
@@ -26,8 +20,8 @@ namespace {
|
||||
class BytewiseComparatorImpl : public Comparator {
|
||||
public:
|
||||
BytewiseComparatorImpl() { }
|
||||
static const char* kClassName() { return "leveldb.BytewiseComparator"; }
|
||||
const char* Name() const override { return kClassName(); }
|
||||
|
||||
const char* Name() const override { return "leveldb.BytewiseComparator"; }
|
||||
|
||||
int Compare(const Slice& a, const Slice& b) const override {
|
||||
return a.compare(b);
|
||||
@@ -145,10 +139,9 @@ class ReverseBytewiseComparatorImpl : public BytewiseComparatorImpl {
|
||||
public:
|
||||
ReverseBytewiseComparatorImpl() { }
|
||||
|
||||
static const char* kClassName() {
|
||||
const char* Name() const override {
|
||||
return "rocksdb.ReverseBytewiseComparator";
|
||||
}
|
||||
const char* Name() const override { return kClassName(); }
|
||||
|
||||
int Compare(const Slice& a, const Slice& b) const override {
|
||||
return -a.compare(b);
|
||||
@@ -227,77 +220,4 @@ const Comparator* ReverseBytewiseComparator() {
|
||||
return &rbytewise;
|
||||
}
|
||||
|
||||
#ifndef ROCKSDB_LITE
|
||||
static int RegisterBuiltinComparators(ObjectLibrary& library,
|
||||
const std::string& /*arg*/) {
|
||||
library.Register<const Comparator>(
|
||||
BytewiseComparatorImpl::kClassName(),
|
||||
[](const std::string& /*uri*/,
|
||||
std::unique_ptr<const Comparator>* /*guard */,
|
||||
std::string* /* errmsg */) { return BytewiseComparator(); });
|
||||
library.Register<const Comparator>(
|
||||
ReverseBytewiseComparatorImpl::kClassName(),
|
||||
[](const std::string& /*uri*/,
|
||||
std::unique_ptr<const Comparator>* /*guard */,
|
||||
std::string* /* errmsg */) { return ReverseBytewiseComparator(); });
|
||||
return 2;
|
||||
}
|
||||
#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;
|
||||
Status status =
|
||||
ConfigurableHelper::GetOptionsMap(value, *result, &id, &opt_map);
|
||||
if (!status.ok()) { // GetOptionsMap failed
|
||||
return status;
|
||||
}
|
||||
std::string curr_opts;
|
||||
#ifndef ROCKSDB_LITE
|
||||
if (*result != nullptr && (*result)->GetId() == id) {
|
||||
// Try to get the existing options, ignoring any errors
|
||||
ConfigOptions embedded = config_options;
|
||||
embedded.delimiter = ";";
|
||||
(*result)->GetOptionString(embedded, &curr_opts).PermitUncheckedError();
|
||||
}
|
||||
#endif
|
||||
if (id == BytewiseComparatorImpl::kClassName()) {
|
||||
*result = BytewiseComparator();
|
||||
} else if (id == ReverseBytewiseComparatorImpl::kClassName()) {
|
||||
*result = ReverseBytewiseComparator();
|
||||
} 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;
|
||||
}
|
||||
} else if (!curr_opts.empty() || !opt_map.empty()) {
|
||||
Comparator* comparator = const_cast<Comparator*>(*result);
|
||||
status = ConfigurableHelper::ConfigureNewObject(
|
||||
config_options, comparator, id, curr_opts, opt_map);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
Reference in New Issue
Block a user