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`.
|
||||
* 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.
|
||||
* 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.
|
||||
|
||||
### Default Option Change
|
||||
|
@ -34,7 +34,7 @@ class DBOptionsTest : public DBTestBase {
|
||||
const DBOptions& options) {
|
||||
std::string options_str;
|
||||
std::unordered_map<std::string, std::string> mutable_map;
|
||||
ConfigOptions config_options;
|
||||
ConfigOptions config_options(options);
|
||||
config_options.delimiter = "; ";
|
||||
|
||||
EXPECT_OK(GetStringFromMutableDBOptions(
|
||||
|
@ -16,6 +16,9 @@
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
class Env;
|
||||
class Logger;
|
||||
class ObjectRegistry;
|
||||
|
||||
struct ColumnFamilyOptions;
|
||||
struct DBOptions;
|
||||
struct Options;
|
||||
@ -27,6 +30,15 @@ struct Options;
|
||||
// of the serialization (e.g. delimiter), and how to compare
|
||||
// options (sanity_level).
|
||||
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.
|
||||
enum SanityLevel : unsigned char {
|
||||
kSanityLevelNone = 0x01, // Performs no sanity check at all.
|
||||
@ -78,6 +90,11 @@ struct ConfigOptions {
|
||||
// The environment to use for this option
|
||||
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 IsDetailed() const { return depth == Depth::kDepthDetailed; }
|
||||
|
||||
@ -500,7 +517,6 @@ Status VerifySstFileChecksum(const Options& options,
|
||||
const EnvOptions& env_options,
|
||||
const ReadOptions& read_options,
|
||||
const std::string& file_path);
|
||||
|
||||
#endif // ROCKSDB_LITE
|
||||
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
@ -17,12 +17,23 @@
|
||||
|
||||
namespace ROCKSDB_NAMESPACE {
|
||||
class Logger;
|
||||
class ObjectLibrary;
|
||||
|
||||
// Returns a new T when called with a string. Populates the std::unique_ptr
|
||||
// argument if granting ownership to caller.
|
||||
template <typename T>
|
||||
using FactoryFunc =
|
||||
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 {
|
||||
public:
|
||||
// Base class for an Entry in the Registry.
|
||||
@ -62,9 +73,18 @@ class ObjectLibrary {
|
||||
FactoryFunc<T> factory_;
|
||||
}; // End class FactoryEntry
|
||||
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
|
||||
const Entry* FindEntry(const std::string& type,
|
||||
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;
|
||||
|
||||
// Registers the factory with the library for the pattern.
|
||||
@ -76,6 +96,12 @@ class ObjectLibrary {
|
||||
AddEntry(T::Type(), entry);
|
||||
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
|
||||
static std::shared_ptr<ObjectLibrary>& Default();
|
||||
|
||||
@ -85,6 +111,9 @@ class ObjectLibrary {
|
||||
|
||||
// ** FactoryFunctions for this loader, organized by type
|
||||
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
|
||||
@ -93,11 +122,26 @@ class ObjectLibrary {
|
||||
class ObjectRegistry {
|
||||
public:
|
||||
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) {
|
||||
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
|
||||
@ -193,6 +237,10 @@ class ObjectRegistry {
|
||||
void Dump(Logger* logger) const;
|
||||
|
||||
private:
|
||||
explicit ObjectRegistry(const std::shared_ptr<ObjectLibrary>& library) {
|
||||
libraries_.push_back(library);
|
||||
}
|
||||
|
||||
const ObjectLibrary::Entry* FindEntry(const std::string& type,
|
||||
const std::string& name) const;
|
||||
|
||||
@ -200,6 +248,7 @@ class ObjectRegistry {
|
||||
// The libraries are searched in reverse order (back to front) when
|
||||
// searching for entries.
|
||||
std::vector<std::shared_ptr<ObjectLibrary>> libraries_;
|
||||
std::shared_ptr<ObjectRegistry> parent_;
|
||||
};
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
#endif // ROCKSDB_LITE
|
||||
|
@ -541,12 +541,12 @@ static std::unordered_map<std::string, OptionTypeInfo>
|
||||
OptionType::kComparator, OptionVerificationType::kByName,
|
||||
OptionTypeFlags::kCompareLoose,
|
||||
// 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) {
|
||||
auto old_comparator = reinterpret_cast<const Comparator**>(addr);
|
||||
const Comparator* new_comparator = *old_comparator;
|
||||
Status status = ObjectRegistry::NewInstance()->NewStaticObject(
|
||||
value, &new_comparator);
|
||||
Status status =
|
||||
opts.registry->NewStaticObject(value, &new_comparator);
|
||||
if (status.ok()) {
|
||||
*old_comparator = new_comparator;
|
||||
return status;
|
||||
@ -661,12 +661,11 @@ static std::unordered_map<std::string, OptionTypeInfo>
|
||||
OptionVerificationType::kByNameAllowFromNull,
|
||||
OptionTypeFlags::kCompareLoose,
|
||||
// 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) {
|
||||
auto mop = reinterpret_cast<std::shared_ptr<MergeOperator>*>(addr);
|
||||
Status status =
|
||||
ObjectRegistry::NewInstance()->NewSharedObject<MergeOperator>(
|
||||
value, mop);
|
||||
opts.registry->NewSharedObject<MergeOperator>(value, mop);
|
||||
// Only support static comparator for now.
|
||||
if (status.ok()) {
|
||||
return status;
|
||||
|
@ -83,12 +83,13 @@ static Status LoadSharedObject(const ConfigOptions& config_options,
|
||||
return Status::NotSupported("Cannot reset object ", id);
|
||||
} else {
|
||||
#ifndef ROCKSDB_LITE
|
||||
status = ObjectRegistry::NewInstance()->NewSharedObject(id, result);
|
||||
status = config_options.registry->NewSharedObject(id, result);
|
||||
#else
|
||||
status = Status::NotSupported("Cannot load object in LITE mode ", id);
|
||||
#endif
|
||||
if (!status.ok()) {
|
||||
if (config_options.ignore_unsupported_options) {
|
||||
if (config_options.ignore_unsupported_options &&
|
||||
status.IsNotSupported()) {
|
||||
return Status::OK();
|
||||
} else {
|
||||
return status;
|
||||
@ -142,12 +143,13 @@ static Status LoadUniqueObject(const ConfigOptions& config_options,
|
||||
return Status::NotSupported("Cannot reset object ", id);
|
||||
} else {
|
||||
#ifndef ROCKSDB_LITE
|
||||
status = ObjectRegistry::NewInstance()->NewUniqueObject(id, result);
|
||||
status = config_options.registry->NewUniqueObject(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) {
|
||||
if (config_options.ignore_unsupported_options &&
|
||||
status.IsNotSupported()) {
|
||||
return Status::OK();
|
||||
} else {
|
||||
return status;
|
||||
@ -199,12 +201,13 @@ static Status LoadStaticObject(const ConfigOptions& config_options,
|
||||
return Status::NotSupported("Cannot reset object ", id);
|
||||
} else {
|
||||
#ifndef ROCKSDB_LITE
|
||||
status = ObjectRegistry::NewInstance()->NewStaticObject(id, result);
|
||||
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) {
|
||||
if (config_options.ignore_unsupported_options &&
|
||||
status.IsNotSupported()) {
|
||||
return Status::OK();
|
||||
} else {
|
||||
return status;
|
||||
|
@ -695,6 +695,68 @@ TEST_F(CustomizableTest, MutableOptionsTest) {
|
||||
}
|
||||
#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
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
@ -28,6 +28,20 @@
|
||||
#include "util/string_util.h"
|
||||
|
||||
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,
|
||||
const ColumnFamilyOptions& cf_opts) {
|
||||
Status s;
|
||||
@ -703,7 +717,7 @@ Status GetStringFromMutableDBOptions(const ConfigOptions& config_options,
|
||||
Status GetStringFromDBOptions(std::string* opt_string,
|
||||
const DBOptions& db_options,
|
||||
const std::string& delimiter) {
|
||||
ConfigOptions config_options;
|
||||
ConfigOptions config_options(db_options);
|
||||
config_options.delimiter = delimiter;
|
||||
return GetStringFromDBOptions(config_options, db_options, opt_string);
|
||||
}
|
||||
@ -816,7 +830,7 @@ Status GetDBOptionsFromMap(
|
||||
const std::unordered_map<std::string, std::string>& opts_map,
|
||||
DBOptions* new_options, bool input_strings_escaped,
|
||||
bool ignore_unknown_options) {
|
||||
ConfigOptions config_options;
|
||||
ConfigOptions config_options(base_options);
|
||||
config_options.input_strings_escaped = input_strings_escaped;
|
||||
config_options.ignore_unknown_options = ignore_unknown_options;
|
||||
return GetDBOptionsFromMap(config_options, base_options, opts_map,
|
||||
@ -844,7 +858,7 @@ Status GetDBOptionsFromMap(
|
||||
Status GetDBOptionsFromString(const DBOptions& base_options,
|
||||
const std::string& opts_str,
|
||||
DBOptions* new_options) {
|
||||
ConfigOptions config_options;
|
||||
ConfigOptions config_options(base_options);
|
||||
config_options.input_strings_escaped = false;
|
||||
config_options.ignore_unknown_options = false;
|
||||
|
||||
@ -868,7 +882,7 @@ Status GetDBOptionsFromString(const ConfigOptions& config_options,
|
||||
|
||||
Status GetOptionsFromString(const Options& base_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.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> opts_map;
|
||||
|
||||
assert(new_options);
|
||||
*new_options = base_options;
|
||||
Status s = StringToMap(opts_str, &opts_map);
|
||||
if (!s.ok()) {
|
||||
|
@ -1808,6 +1808,23 @@ TEST_F(OptionsTest, ConvertOptionsTest) {
|
||||
}
|
||||
|
||||
#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.
|
||||
// Once those APIs are officially deprecated, this test suite can be deleted.
|
||||
class OptionsOldApiTest : public testing::Test {};
|
||||
@ -2507,14 +2524,8 @@ TEST_F(OptionsOldApiTest, GetOptionsFromStringTest) {
|
||||
NewBlockBasedTableFactory(block_based_table_options));
|
||||
|
||||
// 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>(
|
||||
kCustomEnvName,
|
||||
"CustomEnvDefault",
|
||||
[](const std::string& /*name*/, std::unique_ptr<Env>* /*env_guard*/,
|
||||
std::string* /* errmsg */) {
|
||||
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;"
|
||||
"bottommost_compression_opts=5:6:7;create_if_missing=true;max_open_files="
|
||||
"1;"
|
||||
"rate_limiter_bytes_per_sec=1024;env=CustomEnv",
|
||||
"rate_limiter_bytes_per_sec=1024;env=CustomEnvDefault",
|
||||
&new_options));
|
||||
|
||||
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_TRUE(new_options.rate_limiter.get() != nullptr);
|
||||
Env* newEnv = new_options.env;
|
||||
ASSERT_OK(Env::LoadEnv(kCustomEnvName, &newEnv));
|
||||
ASSERT_OK(Env::LoadEnv("CustomEnvDefault", &newEnv));
|
||||
ASSERT_EQ(newEnv, new_options.env);
|
||||
}
|
||||
|
||||
@ -3981,6 +3992,46 @@ TEST_F(OptionTypeInfoTest, TestVectorType) {
|
||||
ASSERT_EQ(vec1[1], "b1|b2");
|
||||
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
|
||||
} // namespace ROCKSDB_NAMESPACE
|
||||
|
||||
|
@ -32,6 +32,15 @@ void ObjectLibrary::AddEntry(const std::string &type,
|
||||
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 {
|
||||
for (const auto &iter : entries_) {
|
||||
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
|
||||
std::shared_ptr<ObjectLibrary> &ObjectLibrary::Default() {
|
||||
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;
|
||||
}
|
||||
|
||||
std::shared_ptr<ObjectRegistry> ObjectRegistry::NewInstance() {
|
||||
std::shared_ptr<ObjectRegistry> instance = std::make_shared<ObjectRegistry>();
|
||||
return instance;
|
||||
return std::make_shared<ObjectRegistry>(Default());
|
||||
}
|
||||
|
||||
ObjectRegistry::ObjectRegistry() {
|
||||
libraries_.push_back(ObjectLibrary::Default());
|
||||
std::shared_ptr<ObjectRegistry> ObjectRegistry::NewInstance(
|
||||
const std::shared_ptr<ObjectRegistry> &parent) {
|
||||
return std::make_shared<ObjectRegistry>(parent);
|
||||
}
|
||||
|
||||
// Searches (from back to front) the libraries looking for the
|
||||
@ -74,13 +89,20 @@ const ObjectLibrary::Entry *ObjectRegistry::FindEntry(
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
if (parent_ != nullptr) {
|
||||
return parent_->FindEntry(type, name);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectRegistry::Dump(Logger *logger) const {
|
||||
for (auto iter = libraries_.crbegin(); iter != libraries_.crend(); ++iter) {
|
||||
iter->get()->Dump(logger);
|
||||
}
|
||||
if (parent_ != nullptr) {
|
||||
parent_->Dump(logger);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ROCKSDB_LITE
|
||||
|
@ -62,7 +62,8 @@ TEST_F(EnvRegistryTest, LocalRegistry) {
|
||||
std::string msg;
|
||||
std::unique_ptr<Env> guard;
|
||||
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);
|
||||
library->Register<Env>(
|
||||
"test-local",
|
||||
@ -87,7 +88,8 @@ TEST_F(EnvRegistryTest, LocalRegistry) {
|
||||
TEST_F(EnvRegistryTest, CheckShared) {
|
||||
std::shared_ptr<Env> shared;
|
||||
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);
|
||||
library->Register<Env>(
|
||||
"unguarded",
|
||||
@ -111,7 +113,8 @@ TEST_F(EnvRegistryTest, CheckShared) {
|
||||
TEST_F(EnvRegistryTest, CheckStatic) {
|
||||
Env* env = nullptr;
|
||||
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);
|
||||
library->Register<Env>(
|
||||
"unguarded",
|
||||
@ -135,7 +138,8 @@ TEST_F(EnvRegistryTest, CheckStatic) {
|
||||
TEST_F(EnvRegistryTest, CheckUnique) {
|
||||
std::unique_ptr<Env> unique;
|
||||
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);
|
||||
library->Register<Env>(
|
||||
"unguarded",
|
||||
@ -156,6 +160,51 @@ TEST_F(EnvRegistryTest, CheckUnique) {
|
||||
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
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
@ -121,7 +121,7 @@ Status CheckOptionsCompatibility(
|
||||
const std::string& dbpath, Env* env, const DBOptions& db_options,
|
||||
const std::vector<ColumnFamilyDescriptor>& cf_descs,
|
||||
bool ignore_unknown_options) {
|
||||
ConfigOptions config_options;
|
||||
ConfigOptions config_options(db_options);
|
||||
config_options.sanity_level = ConfigOptions::kSanityLevelLooselyCompatible;
|
||||
config_options.ignore_unknown_options = ignore_unknown_options;
|
||||
config_options.input_strings_escaped = true;
|
||||
|
Loading…
Reference in New Issue
Block a user