Remove FactoryFunc from LoadXXXObject (#11203)

Summary:
The primary purpose of the FactoryFunc was to support LITE mode where the ObjectRegistry was not available.  With the removal of LITE mode, the function was no longer required.

Note that the MergeOperator had some private classes defined in header files.  To gain access to their constructors (and name methods), the class definitions were moved into header files.

Pull Request resolved: https://github.com/facebook/rocksdb/pull/11203

Reviewed By: cbi42

Differential Revision: D43160255

Pulled By: pdillinger

fbshipit-source-id: f3a465fd5d1a7049b73ecf31e4b8c3762f6dae6c
This commit is contained in:
mrambacher 2023-02-17 12:54:07 -08:00 committed by Facebook GitHub Bot
parent 25e1365227
commit b6640c3117
23 changed files with 330 additions and 370 deletions

View File

@ -21,6 +21,7 @@
* Remove deprecated Env::LoadEnv(). Use Env::CreateFromString() instead.
* Remove deprecated FileSystem::Load(). Use FileSystem::CreateFromString() instead.
* Removed the deprecated version of these utility functions and the corresponding Java bindings: `LoadOptionsFromFile`, `LoadLatestOptions`, `CheckOptionsCompatibility`.
* Remove the FactoryFunc from the LoadObject method from the Customizable helper methods.
### Public API Changes
* Moved rarely-needed Cache class definition to new advanced_cache.h, and added a CacheWrapper class to advanced_cache.h. Minor changes to SimCache API definitions.

3
cache/cache.cc vendored
View File

@ -87,8 +87,7 @@ Status SecondaryCache::CreateFromString(
}
return status;
} else {
return LoadSharedObject<SecondaryCache>(config_options, value, nullptr,
result);
return LoadSharedObject<SecondaryCache>(config_options, value, result);
}
}

View File

@ -78,7 +78,6 @@ Status SstPartitionerFactory::CreateFromString(
std::call_once(once, [&]() {
RegisterSstPartitionerFactories(*(ObjectLibrary::Default().get()), "");
});
return LoadSharedObject<SstPartitionerFactory>(options, value, nullptr,
result);
return LoadSharedObject<SstPartitionerFactory>(options, value, result);
}
} // namespace ROCKSDB_NAMESPACE

View File

@ -13,7 +13,7 @@ namespace ROCKSDB_NAMESPACE {
Status EventListener::CreateFromString(const ConfigOptions& config_options,
const std::string& id,
std::shared_ptr<EventListener>* result) {
return LoadSharedObject<EventListener>(config_options, id, nullptr, result);
return LoadSharedObject<EventListener>(config_options, id, result);
}
namespace {

5
env/env.cc vendored
View File

@ -641,7 +641,7 @@ Status Env::CreateFromString(const ConfigOptions& config_options,
} else {
RegisterSystemEnvs();
Env* env = *result;
Status s = LoadStaticObject<Env>(config_options, value, nullptr, &env);
Status s = LoadStaticObject<Env>(config_options, value, &env);
if (s.ok()) {
*result = env;
}
@ -1227,8 +1227,7 @@ Status SystemClock::CreateFromString(const ConfigOptions& config_options,
std::call_once(once, [&]() {
RegisterBuiltinSystemClocks(*(ObjectLibrary::Default().get()), "");
});
return LoadSharedObject<SystemClock>(config_options, value, nullptr,
result);
return LoadSharedObject<SystemClock>(config_options, value, result);
}
}
} // namespace ROCKSDB_NAMESPACE

View File

@ -1332,15 +1332,14 @@ Status BlockCipher::CreateFromString(const ConfigOptions& config_options,
const std::string& value,
std::shared_ptr<BlockCipher>* result) {
RegisterEncryptionBuiltins();
return LoadSharedObject<BlockCipher>(config_options, value, nullptr, result);
return LoadSharedObject<BlockCipher>(config_options, value, result);
}
Status EncryptionProvider::CreateFromString(
const ConfigOptions& config_options, const std::string& value,
std::shared_ptr<EncryptionProvider>* result) {
RegisterEncryptionBuiltins();
return LoadSharedObject<EncryptionProvider>(config_options, value, nullptr,
result);
return LoadSharedObject<EncryptionProvider>(config_options, value, result);
}

2
env/file_system.cc vendored
View File

@ -91,7 +91,7 @@ Status FileSystem::CreateFromString(const ConfigOptions& config_options,
std::call_once(once, [&]() {
RegisterBuiltinFileSystems(*(ObjectLibrary::Default().get()), "");
});
return LoadSharedObject<FileSystem>(config_options, value, nullptr, result);
return LoadSharedObject<FileSystem>(config_options, value, result);
}
}

View File

@ -13,7 +13,6 @@
// for more information on how to develop and use customizable objects
#pragma once
#include <functional>
#include <memory>
#include <unordered_map>
@ -24,24 +23,6 @@
#include "rocksdb/utilities/object_registry.h"
namespace ROCKSDB_NAMESPACE {
// The FactoryFunc functions are used to create a new customizable object
// without going through the ObjectRegistry. This methodology is especially
// useful in LITE mode, where there is no ObjectRegistry. The methods take
// in an ID of the object to create and a pointer to store the created object.
// If the factory successfully recognized the input ID, the method should return
// success; otherwise false should be returned. On success, the object
// parameter contains the new object.
template <typename T>
using SharedFactoryFunc =
std::function<bool(const std::string&, std::shared_ptr<T>*)>;
template <typename T>
using UniqueFactoryFunc =
std::function<bool(const std::string&, std::unique_ptr<T>*)>;
template <typename T>
using StaticFactoryFunc = std::function<bool(const std::string&, T**)>;
// Creates a new shared customizable instance object based on the
// input parameters using the object registry.
//
@ -156,12 +137,10 @@ static Status NewManagedObject(
// handled
// @param value Either the simple name of the instance to create, or a set of
// name-value pairs to create and initailize the object
// @param func Optional function to call to attempt to create an instance
// @param result The newly created instance.
template <typename T>
static Status LoadSharedObject(const ConfigOptions& config_options,
const std::string& value,
const SharedFactoryFunc<T>& func,
std::shared_ptr<T>* result) {
std::string id;
std::unordered_map<std::string, std::string> opt_map;
@ -170,12 +149,8 @@ static Status LoadSharedObject(const ConfigOptions& config_options,
value, &id, &opt_map);
if (!status.ok()) { // GetOptionsMap failed
return status;
} else if (func == nullptr ||
!func(id, result)) { // No factory, or it failed
return NewSharedObject(config_options, id, opt_map, result);
} else {
return Customizable::ConfigureNewObject(config_options, result->get(),
opt_map);
return NewSharedObject(config_options, id, opt_map, result);
}
}
@ -204,7 +179,6 @@ static Status LoadSharedObject(const ConfigOptions& config_options,
// handled
// @param value Either the simple name of the instance to create, or a set of
// name-value pairs to create and initailize the object
// @param func Optional function to call to attempt to create an instance
// @param result The newly created instance.
template <typename T>
static Status LoadManagedObject(const ConfigOptions& config_options,
@ -270,12 +244,10 @@ static Status NewUniqueObject(
// handled
// @param value Either the simple name of the instance to create, or a set of
// name-value pairs to create and initailize the object
// @param func Optional function to call to attempt to create an instance
// @param result The newly created instance.
template <typename T>
static Status LoadUniqueObject(const ConfigOptions& config_options,
const std::string& value,
const UniqueFactoryFunc<T>& func,
std::unique_ptr<T>* result) {
std::string id;
std::unordered_map<std::string, std::string> opt_map;
@ -283,12 +255,8 @@ static Status LoadUniqueObject(const ConfigOptions& config_options,
value, &id, &opt_map);
if (!status.ok()) { // GetOptionsMap failed
return status;
} else if (func == nullptr ||
!func(id, result)) { // No factory, or it failed
return NewUniqueObject(config_options, id, opt_map, result);
} else {
return Customizable::ConfigureNewObject(config_options, result->get(),
opt_map);
return NewUniqueObject(config_options, id, opt_map, result);
}
}
@ -337,23 +305,18 @@ static Status NewStaticObject(
// handled
// @param value Either the simple name of the instance to create, or a set of
// name-value pairs to create and initailize the object
// @param func Optional function to call to attempt to create an instance
// @param result The newly created instance.
template <typename T>
static Status LoadStaticObject(const ConfigOptions& config_options,
const std::string& value,
const StaticFactoryFunc<T>& func, T** result) {
const std::string& value, T** result) {
std::string id;
std::unordered_map<std::string, std::string> opt_map;
Status status = Customizable::GetOptionsMap(config_options, *result, value,
&id, &opt_map);
if (!status.ok()) { // GetOptionsMap failed
return status;
} else if (func == nullptr ||
!func(id, result)) { // No factory, or it failed
return NewStaticObject(config_options, id, opt_map, result);
} else {
return Customizable::ConfigureNewObject(config_options, *result, opt_map);
return NewStaticObject(config_options, id, opt_map, result);
}
}
} // namespace ROCKSDB_NAMESPACE

View File

@ -300,7 +300,7 @@ Status Statistics::CreateFromString(const ConfigOptions& config_options,
} else if (id == kNullptrString) {
result->reset();
} else {
s = LoadSharedObject<Statistics>(config_options, id, nullptr, result);
s = LoadSharedObject<Statistics>(config_options, id, result);
}
return s;
}

View File

@ -160,19 +160,6 @@ class BCustomizable : public TestCustomizable {
BOptions opts_;
};
static bool LoadSharedB(const std::string& id,
std::shared_ptr<TestCustomizable>* result) {
if (id == "B") {
result->reset(new BCustomizable(id));
return true;
} else if (id.empty()) {
result->reset();
return true;
} else {
return false;
}
}
static int A_count = 0;
static int RegisterCustomTestObjects(ObjectLibrary& library,
const std::string& /*arg*/) {
@ -184,6 +171,12 @@ static int RegisterCustomTestObjects(ObjectLibrary& library,
A_count++;
return guard->get();
});
library.AddFactory<TestCustomizable>(
"B", [](const std::string& name, std::unique_ptr<TestCustomizable>* guard,
std::string* /* msg */) {
guard->reset(new BCustomizable(name));
return guard->get();
});
library.AddFactory<TestCustomizable>(
"S", [](const std::string& name,
@ -252,46 +245,19 @@ static void GetMapFromProperties(
Status TestCustomizable::CreateFromString(
const ConfigOptions& config_options, const std::string& value,
std::shared_ptr<TestCustomizable>* result) {
return LoadSharedObject<TestCustomizable>(config_options, value, LoadSharedB,
result);
return LoadSharedObject<TestCustomizable>(config_options, value, result);
}
Status TestCustomizable::CreateFromString(
const ConfigOptions& config_options, const std::string& value,
std::unique_ptr<TestCustomizable>* result) {
return LoadUniqueObject<TestCustomizable>(
config_options, value,
[](const std::string& id, std::unique_ptr<TestCustomizable>* u) {
if (id == "B") {
u->reset(new BCustomizable(id));
return true;
} else if (id.empty()) {
u->reset();
return true;
} else {
return false;
}
},
result);
return LoadUniqueObject<TestCustomizable>(config_options, value, result);
}
Status TestCustomizable::CreateFromString(const ConfigOptions& config_options,
const std::string& value,
TestCustomizable** result) {
return LoadStaticObject<TestCustomizable>(
config_options, value,
[](const std::string& id, TestCustomizable** ptr) {
if (id == "B") {
*ptr = new BCustomizable(id);
return true;
} else if (id.empty()) {
*ptr = nullptr;
return true;
} else {
return false;
}
},
result);
return LoadStaticObject<TestCustomizable>(config_options, value, result);
}
class CustomizableTest : public testing::Test {
@ -980,72 +946,36 @@ TEST_F(CustomizableTest, IgnoreUnknownObjects) {
std::unique_ptr<TestCustomizable> unique;
TestCustomizable* pointer = nullptr;
ignore.ignore_unsupported_options = false;
ASSERT_NOK(
LoadSharedObject<TestCustomizable>(ignore, "Unknown", nullptr, &shared));
ASSERT_NOK(
LoadUniqueObject<TestCustomizable>(ignore, "Unknown", nullptr, &unique));
ASSERT_NOK(
LoadStaticObject<TestCustomizable>(ignore, "Unknown", nullptr, &pointer));
ASSERT_NOK(LoadSharedObject<TestCustomizable>(ignore, "Unknown", &shared));
ASSERT_NOK(LoadUniqueObject<TestCustomizable>(ignore, "Unknown", &unique));
ASSERT_NOK(LoadStaticObject<TestCustomizable>(ignore, "Unknown", &pointer));
ASSERT_EQ(shared.get(), nullptr);
ASSERT_EQ(unique.get(), nullptr);
ASSERT_EQ(pointer, nullptr);
ignore.ignore_unsupported_options = true;
ASSERT_OK(
LoadSharedObject<TestCustomizable>(ignore, "Unknown", nullptr, &shared));
ASSERT_OK(
LoadUniqueObject<TestCustomizable>(ignore, "Unknown", nullptr, &unique));
ASSERT_OK(
LoadStaticObject<TestCustomizable>(ignore, "Unknown", nullptr, &pointer));
ASSERT_OK(LoadSharedObject<TestCustomizable>(ignore, "Unknown", &shared));
ASSERT_OK(LoadUniqueObject<TestCustomizable>(ignore, "Unknown", &unique));
ASSERT_OK(LoadStaticObject<TestCustomizable>(ignore, "Unknown", &pointer));
ASSERT_EQ(shared.get(), nullptr);
ASSERT_EQ(unique.get(), nullptr);
ASSERT_EQ(pointer, nullptr);
ASSERT_OK(LoadSharedObject<TestCustomizable>(ignore, "id=Unknown", nullptr,
&shared));
ASSERT_OK(LoadUniqueObject<TestCustomizable>(ignore, "id=Unknown", nullptr,
&unique));
ASSERT_OK(LoadStaticObject<TestCustomizable>(ignore, "id=Unknown", nullptr,
&pointer));
ASSERT_OK(LoadSharedObject<TestCustomizable>(ignore, "id=Unknown", &shared));
ASSERT_OK(LoadUniqueObject<TestCustomizable>(ignore, "id=Unknown", &unique));
ASSERT_OK(LoadStaticObject<TestCustomizable>(ignore, "id=Unknown", &pointer));
ASSERT_EQ(shared.get(), nullptr);
ASSERT_EQ(unique.get(), nullptr);
ASSERT_EQ(pointer, nullptr);
ASSERT_OK(LoadSharedObject<TestCustomizable>(ignore, "id=Unknown;option=bad",
nullptr, &shared));
&shared));
ASSERT_OK(LoadUniqueObject<TestCustomizable>(ignore, "id=Unknown;option=bad",
nullptr, &unique));
&unique));
ASSERT_OK(LoadStaticObject<TestCustomizable>(ignore, "id=Unknown;option=bad",
nullptr, &pointer));
&pointer));
ASSERT_EQ(shared.get(), nullptr);
ASSERT_EQ(unique.get(), nullptr);
ASSERT_EQ(pointer, nullptr);
}
TEST_F(CustomizableTest, FactoryFunctionTest) {
std::shared_ptr<TestCustomizable> shared;
std::unique_ptr<TestCustomizable> unique;
TestCustomizable* pointer = nullptr;
ConfigOptions ignore = config_options_;
ignore.ignore_unsupported_options = false;
ASSERT_OK(TestCustomizable::CreateFromString(ignore, "B", &shared));
ASSERT_OK(TestCustomizable::CreateFromString(ignore, "B", &unique));
ASSERT_OK(TestCustomizable::CreateFromString(ignore, "B", &pointer));
ASSERT_NE(shared.get(), nullptr);
ASSERT_NE(unique.get(), nullptr);
ASSERT_NE(pointer, nullptr);
delete pointer;
pointer = nullptr;
ASSERT_OK(TestCustomizable::CreateFromString(ignore, "id=", &shared));
ASSERT_OK(TestCustomizable::CreateFromString(ignore, "id=", &unique));
ASSERT_OK(TestCustomizable::CreateFromString(ignore, "id=", &pointer));
ASSERT_EQ(shared.get(), nullptr);
ASSERT_EQ(unique.get(), nullptr);
ASSERT_EQ(pointer, nullptr);
ASSERT_NOK(TestCustomizable::CreateFromString(ignore, "option=bad", &shared));
ASSERT_NOK(TestCustomizable::CreateFromString(ignore, "option=bad", &unique));
ASSERT_NOK(
TestCustomizable::CreateFromString(ignore, "option=bad", &pointer));
ASSERT_EQ(pointer, nullptr);
}
TEST_F(CustomizableTest, URLFactoryTest) {
std::unique_ptr<TestCustomizable> unique;
config_options_.registry->AddLibrary("URL")->AddFactory<TestCustomizable>(

View File

@ -110,16 +110,6 @@ static int RegisterFlushBlockPolicyFactories(ObjectLibrary& library,
return 2;
}
static bool LoadFlushPolicyFactory(
const std::string& id, std::shared_ptr<FlushBlockPolicyFactory>* result) {
if (id.empty()) {
result->reset(new FlushBlockBySizePolicyFactory());
} else {
return false;
}
return true;
}
FlushBlockBySizePolicyFactory::FlushBlockBySizePolicyFactory()
: FlushBlockPolicyFactory() {}
@ -130,7 +120,13 @@ Status FlushBlockPolicyFactory::CreateFromString(
std::call_once(once, [&]() {
RegisterFlushBlockPolicyFactories(*(ObjectLibrary::Default().get()), "");
});
return LoadSharedObject<FlushBlockPolicyFactory>(
config_options, value, LoadFlushPolicyFactory, factory);
if (value.empty()) {
factory->reset(new FlushBlockBySizePolicyFactory());
return Status::OK();
} else {
return LoadSharedObject<FlushBlockPolicyFactory>(config_options, value,
factory);
}
}
} // namespace ROCKSDB_NAMESPACE

View File

@ -43,21 +43,10 @@ static void RegisterTableFactories(const std::string& /*arg*/) {
});
}
static bool LoadFactory(const std::string& name,
std::shared_ptr<TableFactory>* factory) {
if (name == TableFactory::kBlockBasedTableName()) {
factory->reset(new BlockBasedTableFactory());
return true;
} else {
return false;
}
}
Status TableFactory::CreateFromString(const ConfigOptions& config_options,
const std::string& value,
std::shared_ptr<TableFactory>* factory) {
RegisterTableFactories("");
return LoadSharedObject<TableFactory>(config_options, value, LoadFactory,
factory);
return LoadSharedObject<TableFactory>(config_options, value, factory);
}
} // namespace ROCKSDB_NAMESPACE

View File

@ -160,8 +160,7 @@ Status FileChecksumGenFactory::CreateFromString(
*result = GetFileChecksumGenCrc32cFactory();
return Status::OK();
} else {
Status s = LoadSharedObject<FileChecksumGenFactory>(options, value, nullptr,
result);
Status s = LoadSharedObject<FileChecksumGenFactory>(options, value, result);
return s;
}
}

View File

@ -32,8 +32,8 @@ Status CompactionFilter::CreateFromString(const ConfigOptions& config_options,
RegisterBuiltinCompactionFilters(*(ObjectLibrary::Default().get()), "");
});
CompactionFilter* filter = const_cast<CompactionFilter*>(*result);
Status status = LoadStaticObject<CompactionFilter>(config_options, value,
nullptr, &filter);
Status status =
LoadStaticObject<CompactionFilter>(config_options, value, &filter);
if (status.ok()) {
*result = const_cast<CompactionFilter*>(filter);
}
@ -45,8 +45,8 @@ Status CompactionFilterFactory::CreateFromString(
std::shared_ptr<CompactionFilterFactory>* result) {
// Currently there are no builtin CompactionFilterFactories.
// If any are introduced, they need to be registered here.
Status status = LoadSharedObject<CompactionFilterFactory>(
config_options, value, nullptr, result);
Status status =
LoadSharedObject<CompactionFilterFactory>(config_options, value, result);
return status;
}
} // namespace ROCKSDB_NAMESPACE

View File

@ -12,30 +12,14 @@
#include "rocksdb/utilities/customizable_util.h"
#include "rocksdb/utilities/object_registry.h"
#include "utilities/merge_operators/bytesxor.h"
#include "utilities/merge_operators/max_operator.h"
#include "utilities/merge_operators/put_operator.h"
#include "utilities/merge_operators/sortlist.h"
#include "utilities/merge_operators/string_append/stringappend.h"
#include "utilities/merge_operators/string_append/stringappend2.h"
#include "utilities/merge_operators/uint64add.h"
namespace ROCKSDB_NAMESPACE {
static bool LoadMergeOperator(const std::string& id,
std::shared_ptr<MergeOperator>* result) {
bool success = true;
// TODO: Hook the "name" up to the actual Name() of the MergeOperators?
// Requires these classes be moved into a header file...
if (id == "put" || id == "PutOperator") {
*result = MergeOperators::CreatePutOperator();
} else if (id == "put_v1") {
*result = MergeOperators::CreateDeprecatedPutOperator();
} else if (id == "uint64add" || id == "UInt64AddOperator") {
*result = MergeOperators::CreateUInt64AddOperator();
} else if (id == "max" || id == "MaxOperator") {
*result = MergeOperators::CreateMaxOperator();
} else {
success = false;
}
return success;
}
static int RegisterBuiltinMergeOperators(ObjectLibrary& library,
const std::string& /*arg*/) {
size_t num_types;
@ -71,6 +55,37 @@ static int RegisterBuiltinMergeOperators(ObjectLibrary& library,
guard->reset(new BytesXOROperator());
return guard->get();
});
library.AddFactory<MergeOperator>(
ObjectLibrary::PatternEntry(UInt64AddOperator::kClassName())
.AnotherName(UInt64AddOperator::kNickName()),
[](const std::string& /*uri*/, std::unique_ptr<MergeOperator>* guard,
std::string* /*errmsg*/) {
guard->reset(new UInt64AddOperator());
return guard->get();
});
library.AddFactory<MergeOperator>(
ObjectLibrary::PatternEntry(MaxOperator::kClassName())
.AnotherName(MaxOperator::kNickName()),
[](const std::string& /*uri*/, std::unique_ptr<MergeOperator>* guard,
std::string* /*errmsg*/) {
guard->reset(new MaxOperator());
return guard->get();
});
library.AddFactory<MergeOperator>(
ObjectLibrary::PatternEntry(PutOperatorV2::kClassName())
.AnotherName(PutOperatorV2::kNickName()),
[](const std::string& /*uri*/, std::unique_ptr<MergeOperator>* guard,
std::string* /*errmsg*/) {
guard->reset(new PutOperatorV2());
return guard->get();
});
library.AddFactory<MergeOperator>(
ObjectLibrary::PatternEntry(PutOperator::kNickName()),
[](const std::string& /*uri*/, std::unique_ptr<MergeOperator>* guard,
std::string* /*errmsg*/) {
guard->reset(new PutOperator());
return guard->get();
});
return static_cast<int>(library.GetFactoryCount(&num_types));
}
@ -82,8 +97,7 @@ Status MergeOperator::CreateFromString(const ConfigOptions& config_options,
std::call_once(once, [&]() {
RegisterBuiltinMergeOperators(*(ObjectLibrary::Default().get()), "");
});
return LoadSharedObject<MergeOperator>(config_options, value,
LoadMergeOperator, result);
return LoadSharedObject<MergeOperator>(config_options, value, result);
}
std::shared_ptr<MergeOperator> MergeOperators::CreateFromStringId(

View File

@ -8,72 +8,56 @@
#include "rocksdb/merge_operator.h"
#include "rocksdb/slice.h"
#include "utilities/merge_operators.h"
using ROCKSDB_NAMESPACE::Logger;
using ROCKSDB_NAMESPACE::MergeOperator;
using ROCKSDB_NAMESPACE::Slice;
namespace { // anonymous namespace
// Merge operator that picks the maximum operand, Comparison is based on
// Slice::compare
class MaxOperator : public MergeOperator {
public:
bool FullMergeV2(const MergeOperationInput& merge_in,
MergeOperationOutput* merge_out) const override {
Slice& max = merge_out->existing_operand;
if (merge_in.existing_value) {
max = Slice(merge_in.existing_value->data(),
merge_in.existing_value->size());
} else if (max.data() == nullptr) {
max = Slice();
}
for (const auto& op : merge_in.operand_list) {
if (max.compare(op) < 0) {
max = op;
}
}
return true;
}
bool PartialMerge(const Slice& /*key*/, const Slice& left_operand,
const Slice& right_operand, std::string* new_value,
Logger* /*logger*/) const override {
if (left_operand.compare(right_operand) >= 0) {
new_value->assign(left_operand.data(), left_operand.size());
} else {
new_value->assign(right_operand.data(), right_operand.size());
}
return true;
}
bool PartialMergeMulti(const Slice& /*key*/,
const std::deque<Slice>& operand_list,
std::string* new_value,
Logger* /*logger*/) const override {
Slice max;
for (const auto& operand : operand_list) {
if (max.compare(operand) < 0) {
max = operand;
}
}
new_value->assign(max.data(), max.size());
return true;
}
static const char* kClassName() { return "MaxOperator"; }
static const char* kNickName() { return "max"; }
const char* Name() const override { return kClassName(); }
const char* NickName() const override { return kNickName(); }
};
} // end of anonymous namespace
#include "utilities/merge_operators/max_operator.h"
namespace ROCKSDB_NAMESPACE {
bool MaxOperator::FullMergeV2(const MergeOperationInput& merge_in,
MergeOperationOutput* merge_out) const {
Slice& max = merge_out->existing_operand;
if (merge_in.existing_value) {
max =
Slice(merge_in.existing_value->data(), merge_in.existing_value->size());
} else if (max.data() == nullptr) {
max = Slice();
}
for (const auto& op : merge_in.operand_list) {
if (max.compare(op) < 0) {
max = op;
}
}
return true;
}
bool MaxOperator::PartialMerge(const Slice& /*key*/, const Slice& left_operand,
const Slice& right_operand,
std::string* new_value,
Logger* /*logger*/) const {
if (left_operand.compare(right_operand) >= 0) {
new_value->assign(left_operand.data(), left_operand.size());
} else {
new_value->assign(right_operand.data(), right_operand.size());
}
return true;
}
bool MaxOperator::PartialMergeMulti(const Slice& /*key*/,
const std::deque<Slice>& operand_list,
std::string* new_value,
Logger* /*logger*/) const {
Slice max;
for (const auto& operand : operand_list) {
if (max.compare(operand) < 0) {
max = operand;
}
}
new_value->assign(max.data(), max.size());
return true;
}
std::shared_ptr<MergeOperator> MergeOperators::CreateMaxOperator() {
return std::make_shared<MaxOperator>();
}

View File

@ -0,0 +1,35 @@
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
// 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).
//
// Merge operator that picks the maximum operand, Comparison is based on
// Slice::compare
#pragma once
#include "rocksdb/merge_operator.h"
namespace ROCKSDB_NAMESPACE {
class Logger;
class Slice;
class MaxOperator : public MergeOperator {
public:
static const char* kClassName() { return "MaxOperator"; }
static const char* kNickName() { return "max"; }
const char* Name() const override { return kClassName(); }
const char* NickName() const override { return kNickName(); }
bool FullMergeV2(const MergeOperationInput& merge_in,
MergeOperationOutput* merge_out) const override;
bool PartialMerge(const Slice& /*key*/, const Slice& left_operand,
const Slice& right_operand, std::string* new_value,
Logger* /*logger*/) const override;
bool PartialMergeMulti(const Slice& /*key*/,
const std::deque<Slice>& operand_list,
std::string* new_value,
Logger* /*logger*/) const override;
};
} // namespace ROCKSDB_NAMESPACE

View File

@ -8,12 +8,9 @@
#include "rocksdb/merge_operator.h"
#include "rocksdb/slice.h"
#include "utilities/merge_operators.h"
#include "utilities/merge_operators/put_operator.h"
namespace { // anonymous namespace
using ROCKSDB_NAMESPACE::Logger;
using ROCKSDB_NAMESPACE::MergeOperator;
using ROCKSDB_NAMESPACE::Slice;
namespace ROCKSDB_NAMESPACE {
// A merge operator that mimics Put semantics
// Since this merge-operator will not be used in production,
@ -23,64 +20,49 @@ using ROCKSDB_NAMESPACE::Slice;
// which would be simpler in this case).
//
// From the client-perspective, semantics are the same.
class PutOperator : public MergeOperator {
public:
bool FullMerge(const Slice& /*key*/, const Slice* /*existing_value*/,
const std::deque<std::string>& operand_sequence,
std::string* new_value, Logger* /*logger*/) const override {
// Put basically only looks at the current/latest value
assert(!operand_sequence.empty());
assert(new_value != nullptr);
new_value->assign(operand_sequence.back());
return true;
}
bool PutOperator::FullMerge(const Slice& /*key*/,
const Slice* /*existing_value*/,
const std::deque<std::string>& operand_sequence,
std::string* new_value, Logger* /*logger*/) const {
// Put basically only looks at the current/latest value
assert(!operand_sequence.empty());
assert(new_value != nullptr);
new_value->assign(operand_sequence.back());
return true;
}
bool PartialMerge(const Slice& /*key*/, const Slice& /*left_operand*/,
const Slice& right_operand, std::string* new_value,
Logger* /*logger*/) const override {
new_value->assign(right_operand.data(), right_operand.size());
return true;
}
bool PutOperator::PartialMerge(const Slice& /*key*/,
const Slice& /*left_operand*/,
const Slice& right_operand,
std::string* new_value,
Logger* /*logger*/) const {
new_value->assign(right_operand.data(), right_operand.size());
return true;
}
using MergeOperator::PartialMergeMulti;
bool PartialMergeMulti(const Slice& /*key*/,
const std::deque<Slice>& operand_list,
std::string* new_value,
Logger* /*logger*/) const override {
new_value->assign(operand_list.back().data(), operand_list.back().size());
return true;
}
bool PutOperator::PartialMergeMulti(const Slice& /*key*/,
const std::deque<Slice>& operand_list,
std::string* new_value,
Logger* /*logger*/) const {
new_value->assign(operand_list.back().data(), operand_list.back().size());
return true;
}
static const char* kClassName() { return "PutOperator"; }
static const char* kNickName() { return "put_v1"; }
const char* Name() const override { return kClassName(); }
const char* NickName() const override { return kNickName(); }
};
bool PutOperatorV2::FullMerge(
const Slice& /*key*/, const Slice* /*existing_value*/,
const std::deque<std::string>& /*operand_sequence*/,
std::string* /*new_value*/, Logger* /*logger*/) const {
assert(false);
return false;
}
class PutOperatorV2 : public PutOperator {
bool FullMerge(const Slice& /*key*/, const Slice* /*existing_value*/,
const std::deque<std::string>& /*operand_sequence*/,
std::string* /*new_value*/,
Logger* /*logger*/) const override {
assert(false);
return false;
}
bool FullMergeV2(const MergeOperationInput& merge_in,
MergeOperationOutput* merge_out) const override {
// Put basically only looks at the current/latest value
assert(!merge_in.operand_list.empty());
merge_out->existing_operand = merge_in.operand_list.back();
return true;
}
static const char* kNickName() { return "put"; }
const char* NickName() const override { return kNickName(); }
};
} // end of anonymous namespace
namespace ROCKSDB_NAMESPACE {
bool PutOperatorV2::FullMergeV2(const MergeOperationInput& merge_in,
MergeOperationOutput* merge_out) const {
// Put basically only looks at the current/latest value
assert(!merge_in.operand_list.empty());
merge_out->existing_operand = merge_in.operand_list.back();
return true;
}
std::shared_ptr<MergeOperator> MergeOperators::CreateDeprecatedPutOperator() {
return std::make_shared<PutOperator>();

View File

@ -0,0 +1,56 @@
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
// 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).
//
// A merge operator that mimics Put semantics
// Since this merge-operator will not be used in production,
// it is implemented as a non-associative merge operator to illustrate the
// new interface and for testing purposes. (That is, we inherit from
// the MergeOperator class rather than the AssociativeMergeOperator
// which would be simpler in this case).
//
// From the client-perspective, semantics are the same.
#pragma once
#include "rocksdb/merge_operator.h"
namespace ROCKSDB_NAMESPACE {
class Logger;
class Slice;
class PutOperator : public MergeOperator {
public:
static const char* kClassName() { return "PutOperator"; }
static const char* kNickName() { return "put_v1"; }
const char* Name() const override { return kClassName(); }
const char* NickName() const override { return kNickName(); }
bool FullMerge(const Slice& /*key*/, const Slice* /*existing_value*/,
const std::deque<std::string>& operand_sequence,
std::string* new_value, Logger* /*logger*/) const override;
bool PartialMerge(const Slice& /*key*/, const Slice& left_operand,
const Slice& right_operand, std::string* new_value,
Logger* /*logger*/) const override;
using MergeOperator::PartialMergeMulti;
bool PartialMergeMulti(const Slice& /*key*/,
const std::deque<Slice>& operand_list,
std::string* new_value,
Logger* /*logger*/) const override;
};
class PutOperatorV2 : public PutOperator {
public:
static const char* kNickName() { return "put"; }
const char* NickName() const override { return kNickName(); }
bool FullMerge(const Slice& /*key*/, const Slice* /*existing_value*/,
const std::deque<std::string>& /*operand_sequence*/,
std::string* /*new_value*/, Logger* /*logger*/) const override;
bool FullMergeV2(const MergeOperationInput& merge_in,
MergeOperationOutput* merge_out) const override;
};
} // namespace ROCKSDB_NAMESPACE

View File

@ -3,6 +3,8 @@
// COPYING file in the root directory) and Apache 2.0 License
// (found in the LICENSE.Apache file in the root directory).
#include "utilities/merge_operators/uint64add.h"
#include <memory>
#include "logging/logging.h"
@ -12,61 +14,40 @@
#include "util/coding.h"
#include "utilities/merge_operators.h"
namespace { // anonymous namespace
namespace ROCKSDB_NAMESPACE { // anonymous namespace
using ROCKSDB_NAMESPACE::AssociativeMergeOperator;
using ROCKSDB_NAMESPACE::InfoLogLevel;
using ROCKSDB_NAMESPACE::Logger;
using ROCKSDB_NAMESPACE::Slice;
bool UInt64AddOperator::Merge(const Slice& /*key*/, const Slice* existing_value,
const Slice& value, std::string* new_value,
Logger* logger) const {
uint64_t orig_value = 0;
if (existing_value) {
orig_value = DecodeInteger(*existing_value, logger);
}
uint64_t operand = DecodeInteger(value, logger);
// A 'model' merge operator with uint64 addition semantics
// Implemented as an AssociativeMergeOperator for simplicity and example.
class UInt64AddOperator : public AssociativeMergeOperator {
public:
bool Merge(const Slice& /*key*/, const Slice* existing_value,
const Slice& value, std::string* new_value,
Logger* logger) const override {
uint64_t orig_value = 0;
if (existing_value) {
orig_value = DecodeInteger(*existing_value, logger);
}
uint64_t operand = DecodeInteger(value, logger);
assert(new_value);
new_value->clear();
PutFixed64(new_value, orig_value + operand);
assert(new_value);
new_value->clear();
ROCKSDB_NAMESPACE::PutFixed64(new_value, orig_value + operand);
return true; // Return true always since corruption will be treated as 0
}
return true; // Return true always since corruption will be treated as 0
uint64_t UInt64AddOperator::DecodeInteger(const Slice& value,
Logger* logger) const {
uint64_t result = 0;
if (value.size() == sizeof(uint64_t)) {
result = DecodeFixed64(value.data());
} else if (logger != nullptr) {
// If value is corrupted, treat it as 0
ROCKS_LOG_ERROR(logger,
"uint64 value corruption, size: %" ROCKSDB_PRIszt
" > %" ROCKSDB_PRIszt,
value.size(), sizeof(uint64_t));
}
static const char* kClassName() { return "UInt64AddOperator"; }
static const char* kNickName() { return "uint64add"; }
const char* Name() const override { return kClassName(); }
const char* NickName() const override { return kNickName(); }
private:
// Takes the string and decodes it into a uint64_t
// On error, prints a message and returns 0
uint64_t DecodeInteger(const Slice& value, Logger* logger) const {
uint64_t result = 0;
if (value.size() == sizeof(uint64_t)) {
result = ROCKSDB_NAMESPACE::DecodeFixed64(value.data());
} else if (logger != nullptr) {
// If value is corrupted, treat it as 0
ROCKS_LOG_ERROR(logger,
"uint64 value corruption, size: %" ROCKSDB_PRIszt
" > %" ROCKSDB_PRIszt,
value.size(), sizeof(uint64_t));
}
return result;
}
};
} // anonymous namespace
namespace ROCKSDB_NAMESPACE {
return result;
}
std::shared_ptr<MergeOperator> MergeOperators::CreateUInt64AddOperator() {
return std::make_shared<UInt64AddOperator>();

View File

@ -0,0 +1,35 @@
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
// 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).
//
// A 'model' merge operator with uint64 addition semantics
// Implemented as an AssociativeMergeOperator for simplicity and example.
#pragma once
#include "rocksdb/merge_operator.h"
#include "utilities/merge_operators.h"
namespace ROCKSDB_NAMESPACE {
class Logger;
class Slice;
class UInt64AddOperator : public AssociativeMergeOperator {
public:
static const char* kClassName() { return "UInt64AddOperator"; }
static const char* kNickName() { return "uint64add"; }
const char* Name() const override { return kClassName(); }
const char* NickName() const override { return kNickName(); }
bool Merge(const Slice& /*key*/, const Slice* existing_value,
const Slice& value, std::string* new_value,
Logger* logger) const override;
private:
// Takes the string and decodes it into a uint64_t
// On error, prints a message and returns 0
uint64_t DecodeInteger(const Slice& value, Logger* logger) const;
};
} // namespace ROCKSDB_NAMESPACE

View File

@ -215,7 +215,7 @@ Status TablePropertiesCollectorFactory::CreateFromString(
"");
});
return LoadSharedObject<TablePropertiesCollectorFactory>(options, value,
nullptr, result);
result);
}
} // namespace ROCKSDB_NAMESPACE

View File

@ -15,8 +15,7 @@ namespace ROCKSDB_NAMESPACE {
Status WalFilter::CreateFromString(const ConfigOptions& config_options,
const std::string& value,
WalFilter** filter) {
Status s =
LoadStaticObject<WalFilter>(config_options, value, nullptr, filter);
Status s = LoadStaticObject<WalFilter>(config_options, value, filter);
return s;
}