Add ObjectRegistry to ConfigOptions (#8166)
Summary: This change enables a couple of things: - Different ConfigOptions can have different registry/factory associated with it, thereby allowing things like a "Test" ConfigOptions versus a "Production" - The ObjectRegistry is created fewer times and can be re-used The ConfigOptions can also be initialized/constructed from a DBOptions, in which case it will grab some of its settings (Env, Logger) from the DBOptions. Pull Request resolved: https://github.com/facebook/rocksdb/pull/8166 Reviewed By: zhichao-cao Differential Revision: D27657952 Pulled By: mrambacher fbshipit-source-id: ae1d6200bb7ab127405cdeefaba43c7fe694dfdd
This commit is contained in:
parent
ff463742b5
commit
9f2d255aed
@ -23,6 +23,8 @@
|
|||||||
* Removed unused structure `CompactionFilterContext`.
|
* Removed unused structure `CompactionFilterContext`.
|
||||||
* The `skip_filters` parameter to SstFileWriter is now considered deprecated. Use `BlockBasedTableOptions::filter_policy` to control generation of filters.
|
* The `skip_filters` parameter to SstFileWriter is now considered deprecated. Use `BlockBasedTableOptions::filter_policy` to control generation of filters.
|
||||||
* ClockCache is known to have bugs that could lead to crash or corruption, so should not be used until fixed. Use NewLRUCache instead.
|
* ClockCache is known to have bugs that could lead to crash or corruption, so should not be used until fixed. Use NewLRUCache instead.
|
||||||
|
* Added the ObjectRegistry to the ConfigOptions class. This registry instance will be used to find any customizable loadable objects during initialization.
|
||||||
|
* Expanded the ObjectRegistry functionality to allow nested ObjectRegistry instances. Added methods to register a set of functions with the registry/library as a group.
|
||||||
* Deprecated backupable_db.h and BackupableDBOptions in favor of new versions with appropriate names: backup_engine.h and BackupEngineOptions. Old API compatibility is preserved.
|
* Deprecated backupable_db.h and BackupableDBOptions in favor of new versions with appropriate names: backup_engine.h and BackupEngineOptions. Old API compatibility is preserved.
|
||||||
|
|
||||||
### Default Option Change
|
### Default Option Change
|
||||||
|
@ -34,7 +34,7 @@ class DBOptionsTest : public DBTestBase {
|
|||||||
const DBOptions& options) {
|
const DBOptions& options) {
|
||||||
std::string options_str;
|
std::string options_str;
|
||||||
std::unordered_map<std::string, std::string> mutable_map;
|
std::unordered_map<std::string, std::string> mutable_map;
|
||||||
ConfigOptions config_options;
|
ConfigOptions config_options(options);
|
||||||
config_options.delimiter = "; ";
|
config_options.delimiter = "; ";
|
||||||
|
|
||||||
EXPECT_OK(GetStringFromMutableDBOptions(
|
EXPECT_OK(GetStringFromMutableDBOptions(
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
namespace ROCKSDB_NAMESPACE {
|
namespace ROCKSDB_NAMESPACE {
|
||||||
class Env;
|
class Env;
|
||||||
|
class Logger;
|
||||||
|
class ObjectRegistry;
|
||||||
|
|
||||||
struct ColumnFamilyOptions;
|
struct ColumnFamilyOptions;
|
||||||
struct DBOptions;
|
struct DBOptions;
|
||||||
struct Options;
|
struct Options;
|
||||||
@ -27,6 +30,15 @@ struct Options;
|
|||||||
// of the serialization (e.g. delimiter), and how to compare
|
// of the serialization (e.g. delimiter), and how to compare
|
||||||
// options (sanity_level).
|
// options (sanity_level).
|
||||||
struct ConfigOptions {
|
struct ConfigOptions {
|
||||||
|
// Constructs a new ConfigOptions with a new object registry.
|
||||||
|
// This method should only be used when a DBOptions is not available,
|
||||||
|
// else registry settings may be lost
|
||||||
|
ConfigOptions();
|
||||||
|
|
||||||
|
// Constructs a new ConfigOptions using the settings from
|
||||||
|
// the input DBOptions. Currently constructs a new object registry.
|
||||||
|
explicit ConfigOptions(const DBOptions&);
|
||||||
|
|
||||||
// This enum defines the RocksDB options sanity level.
|
// This enum defines the RocksDB options sanity level.
|
||||||
enum SanityLevel : unsigned char {
|
enum SanityLevel : unsigned char {
|
||||||
kSanityLevelNone = 0x01, // Performs no sanity check at all.
|
kSanityLevelNone = 0x01, // Performs no sanity check at all.
|
||||||
@ -78,6 +90,11 @@ struct ConfigOptions {
|
|||||||
// The environment to use for this option
|
// The environment to use for this option
|
||||||
Env* env = Env::Default();
|
Env* env = Env::Default();
|
||||||
|
|
||||||
|
#ifndef ROCKSDB_LITE
|
||||||
|
// The object registry to use for this options
|
||||||
|
std::shared_ptr<ObjectRegistry> registry;
|
||||||
|
#endif
|
||||||
|
|
||||||
bool IsShallow() const { return depth == Depth::kDepthShallow; }
|
bool IsShallow() const { return depth == Depth::kDepthShallow; }
|
||||||
bool IsDetailed() const { return depth == Depth::kDepthDetailed; }
|
bool IsDetailed() const { return depth == Depth::kDepthDetailed; }
|
||||||
|
|
||||||
@ -500,7 +517,6 @@ Status VerifySstFileChecksum(const Options& options,
|
|||||||
const EnvOptions& env_options,
|
const EnvOptions& env_options,
|
||||||
const ReadOptions& read_options,
|
const ReadOptions& read_options,
|
||||||
const std::string& file_path);
|
const std::string& file_path);
|
||||||
|
|
||||||
#endif // ROCKSDB_LITE
|
#endif // ROCKSDB_LITE
|
||||||
|
|
||||||
} // namespace ROCKSDB_NAMESPACE
|
} // namespace ROCKSDB_NAMESPACE
|
||||||
|
@ -17,12 +17,23 @@
|
|||||||
|
|
||||||
namespace ROCKSDB_NAMESPACE {
|
namespace ROCKSDB_NAMESPACE {
|
||||||
class Logger;
|
class Logger;
|
||||||
|
class ObjectLibrary;
|
||||||
|
|
||||||
// Returns a new T when called with a string. Populates the std::unique_ptr
|
// Returns a new T when called with a string. Populates the std::unique_ptr
|
||||||
// argument if granting ownership to caller.
|
// argument if granting ownership to caller.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using FactoryFunc =
|
using FactoryFunc =
|
||||||
std::function<T*(const std::string&, std::unique_ptr<T>*, std::string*)>;
|
std::function<T*(const std::string&, std::unique_ptr<T>*, std::string*)>;
|
||||||
|
|
||||||
|
// The signature of the function for loading factories
|
||||||
|
// into an object library. This method is expected to register
|
||||||
|
// factory functions in the supplied ObjectLibrary.
|
||||||
|
// The ObjectLibrary is the library in which the factories will be loaded.
|
||||||
|
// The std::string is the argument passed to the loader function.
|
||||||
|
// The RegistrarFunc should return the number of objects loaded into this
|
||||||
|
// library
|
||||||
|
using RegistrarFunc = std::function<int(ObjectLibrary&, const std::string&)>;
|
||||||
|
|
||||||
class ObjectLibrary {
|
class ObjectLibrary {
|
||||||
public:
|
public:
|
||||||
// Base class for an Entry in the Registry.
|
// Base class for an Entry in the Registry.
|
||||||
@ -62,9 +73,18 @@ class ObjectLibrary {
|
|||||||
FactoryFunc<T> factory_;
|
FactoryFunc<T> factory_;
|
||||||
}; // End class FactoryEntry
|
}; // End class FactoryEntry
|
||||||
public:
|
public:
|
||||||
|
explicit ObjectLibrary(const std::string& id) { id_ = id; }
|
||||||
|
|
||||||
|
const std::string& GetID() const { return id_; }
|
||||||
// Finds the entry matching the input name and type
|
// Finds the entry matching the input name and type
|
||||||
const Entry* FindEntry(const std::string& type,
|
const Entry* FindEntry(const std::string& type,
|
||||||
const std::string& name) const;
|
const std::string& name) const;
|
||||||
|
|
||||||
|
// Returns the total number of factories registered for this library.
|
||||||
|
// This method returns the sum of all factories registered for all types.
|
||||||
|
// @param num_types returns how many unique types are registered.
|
||||||
|
size_t GetFactoryCount(size_t* num_types) const;
|
||||||
|
|
||||||
void Dump(Logger* logger) const;
|
void Dump(Logger* logger) const;
|
||||||
|
|
||||||
// Registers the factory with the library for the pattern.
|
// Registers the factory with the library for the pattern.
|
||||||
@ -76,6 +96,12 @@ class ObjectLibrary {
|
|||||||
AddEntry(T::Type(), entry);
|
AddEntry(T::Type(), entry);
|
||||||
return factory;
|
return factory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Invokes the registrar function with the supplied arg for this library.
|
||||||
|
int Register(const RegistrarFunc& registrar, const std::string& arg) {
|
||||||
|
return registrar(*this, arg);
|
||||||
|
}
|
||||||
|
|
||||||
// Returns the default ObjectLibrary
|
// Returns the default ObjectLibrary
|
||||||
static std::shared_ptr<ObjectLibrary>& Default();
|
static std::shared_ptr<ObjectLibrary>& Default();
|
||||||
|
|
||||||
@ -85,6 +111,9 @@ class ObjectLibrary {
|
|||||||
|
|
||||||
// ** FactoryFunctions for this loader, organized by type
|
// ** FactoryFunctions for this loader, organized by type
|
||||||
std::unordered_map<std::string, std::vector<std::unique_ptr<Entry>>> entries_;
|
std::unordered_map<std::string, std::vector<std::unique_ptr<Entry>>> entries_;
|
||||||
|
|
||||||
|
// The name for this library
|
||||||
|
std::string id_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// The ObjectRegistry is used to register objects that can be created by a
|
// The ObjectRegistry is used to register objects that can be created by a
|
||||||
@ -93,11 +122,26 @@ class ObjectLibrary {
|
|||||||
class ObjectRegistry {
|
class ObjectRegistry {
|
||||||
public:
|
public:
|
||||||
static std::shared_ptr<ObjectRegistry> NewInstance();
|
static std::shared_ptr<ObjectRegistry> NewInstance();
|
||||||
|
static std::shared_ptr<ObjectRegistry> NewInstance(
|
||||||
|
const std::shared_ptr<ObjectRegistry>& parent);
|
||||||
|
static std::shared_ptr<ObjectRegistry> Default();
|
||||||
|
explicit ObjectRegistry(const std::shared_ptr<ObjectRegistry>& parent)
|
||||||
|
: parent_(parent) {}
|
||||||
|
|
||||||
ObjectRegistry();
|
std::shared_ptr<ObjectLibrary> AddLibrary(const std::string& id) {
|
||||||
|
auto library = std::make_shared<ObjectLibrary>(id);
|
||||||
|
libraries_.push_back(library);
|
||||||
|
return library;
|
||||||
|
}
|
||||||
|
|
||||||
void AddLibrary(const std::shared_ptr<ObjectLibrary>& library) {
|
void AddLibrary(const std::shared_ptr<ObjectLibrary>& library) {
|
||||||
libraries_.emplace_back(library);
|
libraries_.push_back(library);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddLibrary(const std::string& id, const RegistrarFunc& registrar,
|
||||||
|
const std::string& arg) {
|
||||||
|
auto library = AddLibrary(id);
|
||||||
|
library->Register(registrar, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a new T using the factory function that was registered with a
|
// Creates a new T using the factory function that was registered with a
|
||||||
@ -193,6 +237,10 @@ class ObjectRegistry {
|
|||||||
void Dump(Logger* logger) const;
|
void Dump(Logger* logger) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
explicit ObjectRegistry(const std::shared_ptr<ObjectLibrary>& library) {
|
||||||
|
libraries_.push_back(library);
|
||||||
|
}
|
||||||
|
|
||||||
const ObjectLibrary::Entry* FindEntry(const std::string& type,
|
const ObjectLibrary::Entry* FindEntry(const std::string& type,
|
||||||
const std::string& name) const;
|
const std::string& name) const;
|
||||||
|
|
||||||
@ -200,6 +248,7 @@ class ObjectRegistry {
|
|||||||
// The libraries are searched in reverse order (back to front) when
|
// The libraries are searched in reverse order (back to front) when
|
||||||
// searching for entries.
|
// searching for entries.
|
||||||
std::vector<std::shared_ptr<ObjectLibrary>> libraries_;
|
std::vector<std::shared_ptr<ObjectLibrary>> libraries_;
|
||||||
|
std::shared_ptr<ObjectRegistry> parent_;
|
||||||
};
|
};
|
||||||
} // namespace ROCKSDB_NAMESPACE
|
} // namespace ROCKSDB_NAMESPACE
|
||||||
#endif // ROCKSDB_LITE
|
#endif // ROCKSDB_LITE
|
||||||
|
@ -541,12 +541,12 @@ static std::unordered_map<std::string, OptionTypeInfo>
|
|||||||
OptionType::kComparator, OptionVerificationType::kByName,
|
OptionType::kComparator, OptionVerificationType::kByName,
|
||||||
OptionTypeFlags::kCompareLoose,
|
OptionTypeFlags::kCompareLoose,
|
||||||
// Parses the string and sets the corresponding comparator
|
// Parses the string and sets the corresponding comparator
|
||||||
[](const ConfigOptions& /*opts*/, const std::string& /*name*/,
|
[](const ConfigOptions& opts, const std::string& /*name*/,
|
||||||
const std::string& value, char* addr) {
|
const std::string& value, char* addr) {
|
||||||
auto old_comparator = reinterpret_cast<const Comparator**>(addr);
|
auto old_comparator = reinterpret_cast<const Comparator**>(addr);
|
||||||
const Comparator* new_comparator = *old_comparator;
|
const Comparator* new_comparator = *old_comparator;
|
||||||
Status status = ObjectRegistry::NewInstance()->NewStaticObject(
|
Status status =
|
||||||
value, &new_comparator);
|
opts.registry->NewStaticObject(value, &new_comparator);
|
||||||
if (status.ok()) {
|
if (status.ok()) {
|
||||||
*old_comparator = new_comparator;
|
*old_comparator = new_comparator;
|
||||||
return status;
|
return status;
|
||||||
@ -661,12 +661,11 @@ static std::unordered_map<std::string, OptionTypeInfo>
|
|||||||
OptionVerificationType::kByNameAllowFromNull,
|
OptionVerificationType::kByNameAllowFromNull,
|
||||||
OptionTypeFlags::kCompareLoose,
|
OptionTypeFlags::kCompareLoose,
|
||||||
// Parses the input value as a MergeOperator, updating the value
|
// Parses the input value as a MergeOperator, updating the value
|
||||||
[](const ConfigOptions& /*opts*/, const std::string& /*name*/,
|
[](const ConfigOptions& opts, const std::string& /*name*/,
|
||||||
const std::string& value, char* addr) {
|
const std::string& value, char* addr) {
|
||||||
auto mop = reinterpret_cast<std::shared_ptr<MergeOperator>*>(addr);
|
auto mop = reinterpret_cast<std::shared_ptr<MergeOperator>*>(addr);
|
||||||
Status status =
|
Status status =
|
||||||
ObjectRegistry::NewInstance()->NewSharedObject<MergeOperator>(
|
opts.registry->NewSharedObject<MergeOperator>(value, mop);
|
||||||
value, mop);
|
|
||||||
// Only support static comparator for now.
|
// Only support static comparator for now.
|
||||||
if (status.ok()) {
|
if (status.ok()) {
|
||||||
return status;
|
return status;
|
||||||
|
@ -83,12 +83,13 @@ static Status LoadSharedObject(const ConfigOptions& config_options,
|
|||||||
return Status::NotSupported("Cannot reset object ", id);
|
return Status::NotSupported("Cannot reset object ", id);
|
||||||
} else {
|
} else {
|
||||||
#ifndef ROCKSDB_LITE
|
#ifndef ROCKSDB_LITE
|
||||||
status = ObjectRegistry::NewInstance()->NewSharedObject(id, result);
|
status = config_options.registry->NewSharedObject(id, result);
|
||||||
#else
|
#else
|
||||||
status = Status::NotSupported("Cannot load object in LITE mode ", id);
|
status = Status::NotSupported("Cannot load object in LITE mode ", id);
|
||||||
#endif
|
#endif
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
if (config_options.ignore_unsupported_options) {
|
if (config_options.ignore_unsupported_options &&
|
||||||
|
status.IsNotSupported()) {
|
||||||
return Status::OK();
|
return Status::OK();
|
||||||
} else {
|
} else {
|
||||||
return status;
|
return status;
|
||||||
@ -142,12 +143,13 @@ static Status LoadUniqueObject(const ConfigOptions& config_options,
|
|||||||
return Status::NotSupported("Cannot reset object ", id);
|
return Status::NotSupported("Cannot reset object ", id);
|
||||||
} else {
|
} else {
|
||||||
#ifndef ROCKSDB_LITE
|
#ifndef ROCKSDB_LITE
|
||||||
status = ObjectRegistry::NewInstance()->NewUniqueObject(id, result);
|
status = config_options.registry->NewUniqueObject(id, result);
|
||||||
#else
|
#else
|
||||||
status = Status::NotSupported("Cannot load object in LITE mode ", id);
|
status = Status::NotSupported("Cannot load object in LITE mode ", id);
|
||||||
#endif // ROCKSDB_LITE
|
#endif // ROCKSDB_LITE
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
if (config_options.ignore_unsupported_options) {
|
if (config_options.ignore_unsupported_options &&
|
||||||
|
status.IsNotSupported()) {
|
||||||
return Status::OK();
|
return Status::OK();
|
||||||
} else {
|
} else {
|
||||||
return status;
|
return status;
|
||||||
@ -199,12 +201,13 @@ static Status LoadStaticObject(const ConfigOptions& config_options,
|
|||||||
return Status::NotSupported("Cannot reset object ", id);
|
return Status::NotSupported("Cannot reset object ", id);
|
||||||
} else {
|
} else {
|
||||||
#ifndef ROCKSDB_LITE
|
#ifndef ROCKSDB_LITE
|
||||||
status = ObjectRegistry::NewInstance()->NewStaticObject(id, result);
|
status = config_options.registry->NewStaticObject(id, result);
|
||||||
#else
|
#else
|
||||||
status = Status::NotSupported("Cannot load object in LITE mode ", id);
|
status = Status::NotSupported("Cannot load object in LITE mode ", id);
|
||||||
#endif // ROCKSDB_LITE
|
#endif // ROCKSDB_LITE
|
||||||
if (!status.ok()) {
|
if (!status.ok()) {
|
||||||
if (config_options.ignore_unsupported_options) {
|
if (config_options.ignore_unsupported_options &&
|
||||||
|
status.IsNotSupported()) {
|
||||||
return Status::OK();
|
return Status::OK();
|
||||||
} else {
|
} else {
|
||||||
return status;
|
return status;
|
||||||
|
@ -695,6 +695,68 @@ TEST_F(CustomizableTest, MutableOptionsTest) {
|
|||||||
}
|
}
|
||||||
#endif // !ROCKSDB_LITE
|
#endif // !ROCKSDB_LITE
|
||||||
|
|
||||||
|
#ifndef ROCKSDB_LITE
|
||||||
|
// This method loads existing test classes into the ObjectRegistry
|
||||||
|
static int RegisterTestObjects(ObjectLibrary& library,
|
||||||
|
const std::string& /*arg*/) {
|
||||||
|
size_t num_types;
|
||||||
|
library.Register<TableFactory>(
|
||||||
|
"MockTable",
|
||||||
|
[](const std::string& /*uri*/, std::unique_ptr<TableFactory>* guard,
|
||||||
|
std::string* /* errmsg */) {
|
||||||
|
guard->reset(new mock::MockTableFactory());
|
||||||
|
return guard->get();
|
||||||
|
});
|
||||||
|
return static_cast<int>(library.GetFactoryCount(&num_types));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int RegisterLocalObjects(ObjectLibrary& library,
|
||||||
|
const std::string& /*arg*/) {
|
||||||
|
size_t num_types;
|
||||||
|
// Load any locally defined objects here
|
||||||
|
return static_cast<int>(library.GetFactoryCount(&num_types));
|
||||||
|
}
|
||||||
|
|
||||||
|
class LoadCustomizableTest : public testing::Test {
|
||||||
|
public:
|
||||||
|
LoadCustomizableTest() { config_options_.ignore_unsupported_options = false; }
|
||||||
|
bool RegisterTests(const std::string& arg) {
|
||||||
|
#ifndef ROCKSDB_LITE
|
||||||
|
config_options_.registry->AddLibrary("custom-tests", RegisterTestObjects,
|
||||||
|
arg);
|
||||||
|
config_options_.registry->AddLibrary("local-tests", RegisterLocalObjects,
|
||||||
|
arg);
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
(void)arg;
|
||||||
|
return false;
|
||||||
|
#endif // !ROCKSDB_LITE
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
DBOptions db_opts_;
|
||||||
|
ColumnFamilyOptions cf_opts_;
|
||||||
|
ConfigOptions config_options_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(LoadCustomizableTest, LoadTableFactoryTest) {
|
||||||
|
std::shared_ptr<TableFactory> factory;
|
||||||
|
ASSERT_NOK(
|
||||||
|
TableFactory::CreateFromString(config_options_, "MockTable", &factory));
|
||||||
|
ASSERT_OK(TableFactory::CreateFromString(
|
||||||
|
config_options_, TableFactory::kBlockBasedTableName(), &factory));
|
||||||
|
ASSERT_NE(factory, nullptr);
|
||||||
|
ASSERT_STREQ(factory->Name(), TableFactory::kBlockBasedTableName());
|
||||||
|
|
||||||
|
if (RegisterTests("Test")) {
|
||||||
|
ASSERT_OK(
|
||||||
|
TableFactory::CreateFromString(config_options_, "MockTable", &factory));
|
||||||
|
ASSERT_NE(factory, nullptr);
|
||||||
|
ASSERT_STREQ(factory->Name(), "MockTable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // !ROCKSDB_LITE
|
||||||
|
|
||||||
} // namespace ROCKSDB_NAMESPACE
|
} // namespace ROCKSDB_NAMESPACE
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
::testing::InitGoogleTest(&argc, argv);
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
@ -28,6 +28,20 @@
|
|||||||
#include "util/string_util.h"
|
#include "util/string_util.h"
|
||||||
|
|
||||||
namespace ROCKSDB_NAMESPACE {
|
namespace ROCKSDB_NAMESPACE {
|
||||||
|
ConfigOptions::ConfigOptions()
|
||||||
|
#ifndef ROCKSDB_LITE
|
||||||
|
: registry(ObjectRegistry::NewInstance())
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
env = Env::Default();
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigOptions::ConfigOptions(const DBOptions& db_opts) : env(db_opts.env) {
|
||||||
|
#ifndef ROCKSDB_LITE
|
||||||
|
registry = ObjectRegistry::NewInstance();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
Status ValidateOptions(const DBOptions& db_opts,
|
Status ValidateOptions(const DBOptions& db_opts,
|
||||||
const ColumnFamilyOptions& cf_opts) {
|
const ColumnFamilyOptions& cf_opts) {
|
||||||
Status s;
|
Status s;
|
||||||
@ -703,7 +717,7 @@ Status GetStringFromMutableDBOptions(const ConfigOptions& config_options,
|
|||||||
Status GetStringFromDBOptions(std::string* opt_string,
|
Status GetStringFromDBOptions(std::string* opt_string,
|
||||||
const DBOptions& db_options,
|
const DBOptions& db_options,
|
||||||
const std::string& delimiter) {
|
const std::string& delimiter) {
|
||||||
ConfigOptions config_options;
|
ConfigOptions config_options(db_options);
|
||||||
config_options.delimiter = delimiter;
|
config_options.delimiter = delimiter;
|
||||||
return GetStringFromDBOptions(config_options, db_options, opt_string);
|
return GetStringFromDBOptions(config_options, db_options, opt_string);
|
||||||
}
|
}
|
||||||
@ -816,7 +830,7 @@ Status GetDBOptionsFromMap(
|
|||||||
const std::unordered_map<std::string, std::string>& opts_map,
|
const std::unordered_map<std::string, std::string>& opts_map,
|
||||||
DBOptions* new_options, bool input_strings_escaped,
|
DBOptions* new_options, bool input_strings_escaped,
|
||||||
bool ignore_unknown_options) {
|
bool ignore_unknown_options) {
|
||||||
ConfigOptions config_options;
|
ConfigOptions config_options(base_options);
|
||||||
config_options.input_strings_escaped = input_strings_escaped;
|
config_options.input_strings_escaped = input_strings_escaped;
|
||||||
config_options.ignore_unknown_options = ignore_unknown_options;
|
config_options.ignore_unknown_options = ignore_unknown_options;
|
||||||
return GetDBOptionsFromMap(config_options, base_options, opts_map,
|
return GetDBOptionsFromMap(config_options, base_options, opts_map,
|
||||||
@ -844,7 +858,7 @@ Status GetDBOptionsFromMap(
|
|||||||
Status GetDBOptionsFromString(const DBOptions& base_options,
|
Status GetDBOptionsFromString(const DBOptions& base_options,
|
||||||
const std::string& opts_str,
|
const std::string& opts_str,
|
||||||
DBOptions* new_options) {
|
DBOptions* new_options) {
|
||||||
ConfigOptions config_options;
|
ConfigOptions config_options(base_options);
|
||||||
config_options.input_strings_escaped = false;
|
config_options.input_strings_escaped = false;
|
||||||
config_options.ignore_unknown_options = false;
|
config_options.ignore_unknown_options = false;
|
||||||
|
|
||||||
@ -868,7 +882,7 @@ Status GetDBOptionsFromString(const ConfigOptions& config_options,
|
|||||||
|
|
||||||
Status GetOptionsFromString(const Options& base_options,
|
Status GetOptionsFromString(const Options& base_options,
|
||||||
const std::string& opts_str, Options* new_options) {
|
const std::string& opts_str, Options* new_options) {
|
||||||
ConfigOptions config_options;
|
ConfigOptions config_options(base_options);
|
||||||
config_options.input_strings_escaped = false;
|
config_options.input_strings_escaped = false;
|
||||||
config_options.ignore_unknown_options = false;
|
config_options.ignore_unknown_options = false;
|
||||||
|
|
||||||
@ -883,6 +897,7 @@ Status GetOptionsFromString(const ConfigOptions& config_options,
|
|||||||
std::unordered_map<std::string, std::string> unused_opts;
|
std::unordered_map<std::string, std::string> unused_opts;
|
||||||
std::unordered_map<std::string, std::string> opts_map;
|
std::unordered_map<std::string, std::string> opts_map;
|
||||||
|
|
||||||
|
assert(new_options);
|
||||||
*new_options = base_options;
|
*new_options = base_options;
|
||||||
Status s = StringToMap(opts_str, &opts_map);
|
Status s = StringToMap(opts_str, &opts_map);
|
||||||
if (!s.ok()) {
|
if (!s.ok()) {
|
||||||
|
@ -1808,6 +1808,23 @@ TEST_F(OptionsTest, ConvertOptionsTest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef ROCKSDB_LITE
|
#ifndef ROCKSDB_LITE
|
||||||
|
const static std::string kCustomEnvName = "Custom";
|
||||||
|
const static std::string kCustomEnvProp = "env=" + kCustomEnvName;
|
||||||
|
class CustomEnv : public EnvWrapper {
|
||||||
|
public:
|
||||||
|
explicit CustomEnv(Env* _target) : EnvWrapper(_target) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int RegisterCustomEnv(ObjectLibrary& library, const std::string& arg) {
|
||||||
|
library.Register<Env>(
|
||||||
|
arg, [](const std::string& /*name*/, std::unique_ptr<Env>* /*env_guard*/,
|
||||||
|
std::string* /* errmsg */) {
|
||||||
|
static CustomEnv env(Env::Default());
|
||||||
|
return &env;
|
||||||
|
});
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// This test suite tests the old APIs into the Configure options methods.
|
// This test suite tests the old APIs into the Configure options methods.
|
||||||
// Once those APIs are officially deprecated, this test suite can be deleted.
|
// Once those APIs are officially deprecated, this test suite can be deleted.
|
||||||
class OptionsOldApiTest : public testing::Test {};
|
class OptionsOldApiTest : public testing::Test {};
|
||||||
@ -2507,14 +2524,8 @@ TEST_F(OptionsOldApiTest, GetOptionsFromStringTest) {
|
|||||||
NewBlockBasedTableFactory(block_based_table_options));
|
NewBlockBasedTableFactory(block_based_table_options));
|
||||||
|
|
||||||
// Register an Env with object registry.
|
// Register an Env with object registry.
|
||||||
const static char* kCustomEnvName = "CustomEnv";
|
|
||||||
class CustomEnv : public EnvWrapper {
|
|
||||||
public:
|
|
||||||
explicit CustomEnv(Env* _target) : EnvWrapper(_target) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
ObjectLibrary::Default()->Register<Env>(
|
ObjectLibrary::Default()->Register<Env>(
|
||||||
kCustomEnvName,
|
"CustomEnvDefault",
|
||||||
[](const std::string& /*name*/, std::unique_ptr<Env>* /*env_guard*/,
|
[](const std::string& /*name*/, std::unique_ptr<Env>* /*env_guard*/,
|
||||||
std::string* /* errmsg */) {
|
std::string* /* errmsg */) {
|
||||||
static CustomEnv env(Env::Default());
|
static CustomEnv env(Env::Default());
|
||||||
@ -2528,7 +2539,7 @@ TEST_F(OptionsOldApiTest, GetOptionsFromStringTest) {
|
|||||||
"compression_opts=4:5:6;create_if_missing=true;max_open_files=1;"
|
"compression_opts=4:5:6;create_if_missing=true;max_open_files=1;"
|
||||||
"bottommost_compression_opts=5:6:7;create_if_missing=true;max_open_files="
|
"bottommost_compression_opts=5:6:7;create_if_missing=true;max_open_files="
|
||||||
"1;"
|
"1;"
|
||||||
"rate_limiter_bytes_per_sec=1024;env=CustomEnv",
|
"rate_limiter_bytes_per_sec=1024;env=CustomEnvDefault",
|
||||||
&new_options));
|
&new_options));
|
||||||
|
|
||||||
ASSERT_EQ(new_options.compression_opts.window_bits, 4);
|
ASSERT_EQ(new_options.compression_opts.window_bits, 4);
|
||||||
@ -2562,7 +2573,7 @@ TEST_F(OptionsOldApiTest, GetOptionsFromStringTest) {
|
|||||||
ASSERT_EQ(new_options.max_open_files, 1);
|
ASSERT_EQ(new_options.max_open_files, 1);
|
||||||
ASSERT_TRUE(new_options.rate_limiter.get() != nullptr);
|
ASSERT_TRUE(new_options.rate_limiter.get() != nullptr);
|
||||||
Env* newEnv = new_options.env;
|
Env* newEnv = new_options.env;
|
||||||
ASSERT_OK(Env::LoadEnv(kCustomEnvName, &newEnv));
|
ASSERT_OK(Env::LoadEnv("CustomEnvDefault", &newEnv));
|
||||||
ASSERT_EQ(newEnv, new_options.env);
|
ASSERT_EQ(newEnv, new_options.env);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3981,6 +3992,46 @@ TEST_F(OptionTypeInfoTest, TestVectorType) {
|
|||||||
ASSERT_EQ(vec1[1], "b1|b2");
|
ASSERT_EQ(vec1[1], "b1|b2");
|
||||||
ASSERT_EQ(vec1[2], "c1|c2|{d1|d2}");
|
ASSERT_EQ(vec1[2], "c1|c2|{d1|d2}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ConfigOptionsTest : public testing::Test {};
|
||||||
|
|
||||||
|
TEST_F(ConfigOptionsTest, EnvFromConfigOptions) {
|
||||||
|
ConfigOptions config_options;
|
||||||
|
DBOptions db_opts;
|
||||||
|
Options opts;
|
||||||
|
Env* mem_env = NewMemEnv(Env::Default());
|
||||||
|
config_options.registry->AddLibrary("custom-env", RegisterCustomEnv,
|
||||||
|
kCustomEnvName);
|
||||||
|
|
||||||
|
config_options.env = mem_env;
|
||||||
|
// First test that we can get the env as expected
|
||||||
|
ASSERT_OK(GetDBOptionsFromString(config_options, DBOptions(), kCustomEnvProp,
|
||||||
|
&db_opts));
|
||||||
|
ASSERT_OK(
|
||||||
|
GetOptionsFromString(config_options, Options(), kCustomEnvProp, &opts));
|
||||||
|
ASSERT_NE(config_options.env, db_opts.env);
|
||||||
|
ASSERT_EQ(opts.env, db_opts.env);
|
||||||
|
Env* custom_env = db_opts.env;
|
||||||
|
|
||||||
|
// Now try a "bad" env" and check that nothing changed
|
||||||
|
config_options.ignore_unsupported_options = true;
|
||||||
|
ASSERT_OK(
|
||||||
|
GetDBOptionsFromString(config_options, db_opts, "env=unknown", &db_opts));
|
||||||
|
ASSERT_OK(GetOptionsFromString(config_options, opts, "env=unknown", &opts));
|
||||||
|
ASSERT_EQ(config_options.env, mem_env);
|
||||||
|
ASSERT_EQ(db_opts.env, custom_env);
|
||||||
|
ASSERT_EQ(opts.env, db_opts.env);
|
||||||
|
|
||||||
|
// Now try a "bad" env" ignoring unknown objects
|
||||||
|
config_options.ignore_unsupported_options = false;
|
||||||
|
ASSERT_NOK(
|
||||||
|
GetDBOptionsFromString(config_options, db_opts, "env=unknown", &db_opts));
|
||||||
|
ASSERT_EQ(config_options.env, mem_env);
|
||||||
|
ASSERT_EQ(db_opts.env, custom_env);
|
||||||
|
ASSERT_EQ(opts.env, db_opts.env);
|
||||||
|
|
||||||
|
delete mem_env;
|
||||||
|
}
|
||||||
#endif // !ROCKSDB_LITE
|
#endif // !ROCKSDB_LITE
|
||||||
} // namespace ROCKSDB_NAMESPACE
|
} // namespace ROCKSDB_NAMESPACE
|
||||||
|
|
||||||
|
@ -32,6 +32,15 @@ void ObjectLibrary::AddEntry(const std::string &type,
|
|||||||
entries.emplace_back(std::move(entry));
|
entries.emplace_back(std::move(entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t ObjectLibrary::GetFactoryCount(size_t *types) const {
|
||||||
|
*types = entries_.size();
|
||||||
|
size_t factories = 0;
|
||||||
|
for (const auto &e : entries_) {
|
||||||
|
factories += e.second.size();
|
||||||
|
}
|
||||||
|
return factories;
|
||||||
|
}
|
||||||
|
|
||||||
void ObjectLibrary::Dump(Logger *logger) const {
|
void ObjectLibrary::Dump(Logger *logger) const {
|
||||||
for (const auto &iter : entries_) {
|
for (const auto &iter : entries_) {
|
||||||
ROCKS_LOG_HEADER(logger, " Registered factories for type[%s] ",
|
ROCKS_LOG_HEADER(logger, " Registered factories for type[%s] ",
|
||||||
@ -50,17 +59,23 @@ void ObjectLibrary::Dump(Logger *logger) const {
|
|||||||
// This instance will contain most of the "standard" registered objects
|
// This instance will contain most of the "standard" registered objects
|
||||||
std::shared_ptr<ObjectLibrary> &ObjectLibrary::Default() {
|
std::shared_ptr<ObjectLibrary> &ObjectLibrary::Default() {
|
||||||
static std::shared_ptr<ObjectLibrary> instance =
|
static std::shared_ptr<ObjectLibrary> instance =
|
||||||
std::make_shared<ObjectLibrary>();
|
std::make_shared<ObjectLibrary>("default");
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<ObjectRegistry> ObjectRegistry::Default() {
|
||||||
|
static std::shared_ptr<ObjectRegistry> instance(
|
||||||
|
new ObjectRegistry(ObjectLibrary::Default()));
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ObjectRegistry> ObjectRegistry::NewInstance() {
|
std::shared_ptr<ObjectRegistry> ObjectRegistry::NewInstance() {
|
||||||
std::shared_ptr<ObjectRegistry> instance = std::make_shared<ObjectRegistry>();
|
return std::make_shared<ObjectRegistry>(Default());
|
||||||
return instance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectRegistry::ObjectRegistry() {
|
std::shared_ptr<ObjectRegistry> ObjectRegistry::NewInstance(
|
||||||
libraries_.push_back(ObjectLibrary::Default());
|
const std::shared_ptr<ObjectRegistry> &parent) {
|
||||||
|
return std::make_shared<ObjectRegistry>(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Searches (from back to front) the libraries looking for the
|
// Searches (from back to front) the libraries looking for the
|
||||||
@ -74,13 +89,20 @@ const ObjectLibrary::Entry *ObjectRegistry::FindEntry(
|
|||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
if (parent_ != nullptr) {
|
||||||
|
return parent_->FindEntry(type, name);
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectRegistry::Dump(Logger *logger) const {
|
void ObjectRegistry::Dump(Logger *logger) const {
|
||||||
for (auto iter = libraries_.crbegin(); iter != libraries_.crend(); ++iter) {
|
for (auto iter = libraries_.crbegin(); iter != libraries_.crend(); ++iter) {
|
||||||
iter->get()->Dump(logger);
|
iter->get()->Dump(logger);
|
||||||
}
|
}
|
||||||
|
if (parent_ != nullptr) {
|
||||||
|
parent_->Dump(logger);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // ROCKSDB_LITE
|
#endif // ROCKSDB_LITE
|
||||||
|
@ -62,7 +62,8 @@ TEST_F(EnvRegistryTest, LocalRegistry) {
|
|||||||
std::string msg;
|
std::string msg;
|
||||||
std::unique_ptr<Env> guard;
|
std::unique_ptr<Env> guard;
|
||||||
auto registry = ObjectRegistry::NewInstance();
|
auto registry = ObjectRegistry::NewInstance();
|
||||||
std::shared_ptr<ObjectLibrary> library = std::make_shared<ObjectLibrary>();
|
std::shared_ptr<ObjectLibrary> library =
|
||||||
|
std::make_shared<ObjectLibrary>("local");
|
||||||
registry->AddLibrary(library);
|
registry->AddLibrary(library);
|
||||||
library->Register<Env>(
|
library->Register<Env>(
|
||||||
"test-local",
|
"test-local",
|
||||||
@ -87,7 +88,8 @@ TEST_F(EnvRegistryTest, LocalRegistry) {
|
|||||||
TEST_F(EnvRegistryTest, CheckShared) {
|
TEST_F(EnvRegistryTest, CheckShared) {
|
||||||
std::shared_ptr<Env> shared;
|
std::shared_ptr<Env> shared;
|
||||||
std::shared_ptr<ObjectRegistry> registry = ObjectRegistry::NewInstance();
|
std::shared_ptr<ObjectRegistry> registry = ObjectRegistry::NewInstance();
|
||||||
std::shared_ptr<ObjectLibrary> library = std::make_shared<ObjectLibrary>();
|
std::shared_ptr<ObjectLibrary> library =
|
||||||
|
std::make_shared<ObjectLibrary>("shared");
|
||||||
registry->AddLibrary(library);
|
registry->AddLibrary(library);
|
||||||
library->Register<Env>(
|
library->Register<Env>(
|
||||||
"unguarded",
|
"unguarded",
|
||||||
@ -111,7 +113,8 @@ TEST_F(EnvRegistryTest, CheckShared) {
|
|||||||
TEST_F(EnvRegistryTest, CheckStatic) {
|
TEST_F(EnvRegistryTest, CheckStatic) {
|
||||||
Env* env = nullptr;
|
Env* env = nullptr;
|
||||||
std::shared_ptr<ObjectRegistry> registry = ObjectRegistry::NewInstance();
|
std::shared_ptr<ObjectRegistry> registry = ObjectRegistry::NewInstance();
|
||||||
std::shared_ptr<ObjectLibrary> library = std::make_shared<ObjectLibrary>();
|
std::shared_ptr<ObjectLibrary> library =
|
||||||
|
std::make_shared<ObjectLibrary>("static");
|
||||||
registry->AddLibrary(library);
|
registry->AddLibrary(library);
|
||||||
library->Register<Env>(
|
library->Register<Env>(
|
||||||
"unguarded",
|
"unguarded",
|
||||||
@ -135,7 +138,8 @@ TEST_F(EnvRegistryTest, CheckStatic) {
|
|||||||
TEST_F(EnvRegistryTest, CheckUnique) {
|
TEST_F(EnvRegistryTest, CheckUnique) {
|
||||||
std::unique_ptr<Env> unique;
|
std::unique_ptr<Env> unique;
|
||||||
std::shared_ptr<ObjectRegistry> registry = ObjectRegistry::NewInstance();
|
std::shared_ptr<ObjectRegistry> registry = ObjectRegistry::NewInstance();
|
||||||
std::shared_ptr<ObjectLibrary> library = std::make_shared<ObjectLibrary>();
|
std::shared_ptr<ObjectLibrary> library =
|
||||||
|
std::make_shared<ObjectLibrary>("unique");
|
||||||
registry->AddLibrary(library);
|
registry->AddLibrary(library);
|
||||||
library->Register<Env>(
|
library->Register<Env>(
|
||||||
"unguarded",
|
"unguarded",
|
||||||
@ -156,6 +160,51 @@ TEST_F(EnvRegistryTest, CheckUnique) {
|
|||||||
ASSERT_EQ(unique, nullptr);
|
ASSERT_EQ(unique, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(EnvRegistryTest, TestRegistryParents) {
|
||||||
|
auto grand = ObjectRegistry::Default();
|
||||||
|
auto parent = ObjectRegistry::NewInstance(); // parent with a grandparent
|
||||||
|
auto uncle = ObjectRegistry::NewInstance(grand);
|
||||||
|
auto child = ObjectRegistry::NewInstance(parent);
|
||||||
|
auto cousin = ObjectRegistry::NewInstance(uncle);
|
||||||
|
|
||||||
|
auto library = parent->AddLibrary("parent");
|
||||||
|
library->Register<Env>(
|
||||||
|
"parent", [](const std::string& /*uri*/, std::unique_ptr<Env>* guard,
|
||||||
|
std::string* /* errmsg */) {
|
||||||
|
guard->reset(new EnvWrapper(Env::Default()));
|
||||||
|
return guard->get();
|
||||||
|
});
|
||||||
|
library = cousin->AddLibrary("cousin");
|
||||||
|
library->Register<Env>(
|
||||||
|
"cousin", [](const std::string& /*uri*/, std::unique_ptr<Env>* guard,
|
||||||
|
std::string* /* errmsg */) {
|
||||||
|
guard->reset(new EnvWrapper(Env::Default()));
|
||||||
|
return guard->get();
|
||||||
|
});
|
||||||
|
|
||||||
|
std::unique_ptr<Env> guard;
|
||||||
|
std::string msg;
|
||||||
|
|
||||||
|
// a:://* is registered in Default, so they should all workd
|
||||||
|
ASSERT_NE(parent->NewObject<Env>("a://test", &guard, &msg), nullptr);
|
||||||
|
ASSERT_NE(child->NewObject<Env>("a://test", &guard, &msg), nullptr);
|
||||||
|
ASSERT_NE(uncle->NewObject<Env>("a://test", &guard, &msg), nullptr);
|
||||||
|
ASSERT_NE(cousin->NewObject<Env>("a://test", &guard, &msg), nullptr);
|
||||||
|
|
||||||
|
// The parent env is only registered for parent, not uncle,
|
||||||
|
// So parent and child should return success and uncle and cousin should fail
|
||||||
|
ASSERT_OK(parent->NewUniqueObject<Env>("parent", &guard));
|
||||||
|
ASSERT_OK(child->NewUniqueObject<Env>("parent", &guard));
|
||||||
|
ASSERT_NOK(uncle->NewUniqueObject<Env>("parent", &guard));
|
||||||
|
ASSERT_NOK(cousin->NewUniqueObject<Env>("parent", &guard));
|
||||||
|
|
||||||
|
// The cousin is only registered in the cousin, so all of the others should
|
||||||
|
// fail
|
||||||
|
ASSERT_OK(cousin->NewUniqueObject<Env>("cousin", &guard));
|
||||||
|
ASSERT_NOK(parent->NewUniqueObject<Env>("cousin", &guard));
|
||||||
|
ASSERT_NOK(child->NewUniqueObject<Env>("cousin", &guard));
|
||||||
|
ASSERT_NOK(uncle->NewUniqueObject<Env>("cousin", &guard));
|
||||||
|
}
|
||||||
} // namespace ROCKSDB_NAMESPACE
|
} // namespace ROCKSDB_NAMESPACE
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
|
@ -121,7 +121,7 @@ Status CheckOptionsCompatibility(
|
|||||||
const std::string& dbpath, Env* env, const DBOptions& db_options,
|
const std::string& dbpath, Env* env, const DBOptions& db_options,
|
||||||
const std::vector<ColumnFamilyDescriptor>& cf_descs,
|
const std::vector<ColumnFamilyDescriptor>& cf_descs,
|
||||||
bool ignore_unknown_options) {
|
bool ignore_unknown_options) {
|
||||||
ConfigOptions config_options;
|
ConfigOptions config_options(db_options);
|
||||||
config_options.sanity_level = ConfigOptions::kSanityLevelLooselyCompatible;
|
config_options.sanity_level = ConfigOptions::kSanityLevelLooselyCompatible;
|
||||||
config_options.ignore_unknown_options = ignore_unknown_options;
|
config_options.ignore_unknown_options = ignore_unknown_options;
|
||||||
config_options.input_strings_escaped = true;
|
config_options.input_strings_escaped = true;
|
||||||
|
Loading…
Reference in New Issue
Block a user