Skip to content

Commit

Permalink
Allow unregistered options to be ignored in DBOptions from files (fac…
Browse files Browse the repository at this point in the history
…ebook#9045)

Summary:
Adds changes to DBOptions (comparable to ColumnFamilyOptions) to allow some option values to be ignored on rehydration from the Options file.  This is necessary for some customizable classes that were not registered with the ObjectRegistry but are saved/restored from the Options file.

All tests pass.  Will run check_format_compatible.sh shortly.

Pull Request resolved: facebook#9045

Reviewed By: zhichao-cao

Differential Revision: D31761664

Pulled By: mrambacher

fbshipit-source-id: 300c2251639cce2b223481c3bb2a63877b1f3766
  • Loading branch information
mrambacher authored and facebook-github-bot committed Oct 19, 2021
1 parent 8d615a2 commit 8fb3fe8
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 97 deletions.
23 changes: 11 additions & 12 deletions options/customizable_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1463,7 +1463,6 @@ class LoadCustomizableTest : public testing::Test {
};

TEST_F(LoadCustomizableTest, LoadTableFactoryTest) {
ColumnFamilyOptions cf_opts;
std::shared_ptr<TableFactory> factory;
ASSERT_NOK(TableFactory::CreateFromString(
config_options_, mock::MockTableFactory::kClassName(), &factory));
Expand All @@ -1474,10 +1473,10 @@ TEST_F(LoadCustomizableTest, LoadTableFactoryTest) {
#ifndef ROCKSDB_LITE
std::string opts_str = "table_factory=";
ASSERT_OK(GetColumnFamilyOptionsFromString(
config_options_, ColumnFamilyOptions(),
opts_str + TableFactory::kBlockBasedTableName(), &cf_opts));
ASSERT_NE(cf_opts.table_factory.get(), nullptr);
ASSERT_STREQ(cf_opts.table_factory->Name(),
config_options_, cf_opts_,
opts_str + TableFactory::kBlockBasedTableName(), &cf_opts_));
ASSERT_NE(cf_opts_.table_factory.get(), nullptr);
ASSERT_STREQ(cf_opts_.table_factory->Name(),
TableFactory::kBlockBasedTableName());
#endif // ROCKSDB_LITE
if (RegisterTests("Test")) {
Expand All @@ -1487,10 +1486,10 @@ TEST_F(LoadCustomizableTest, LoadTableFactoryTest) {
ASSERT_STREQ(factory->Name(), mock::MockTableFactory::kClassName());
#ifndef ROCKSDB_LITE
ASSERT_OK(GetColumnFamilyOptionsFromString(
config_options_, ColumnFamilyOptions(),
opts_str + mock::MockTableFactory::kClassName(), &cf_opts));
ASSERT_NE(cf_opts.table_factory.get(), nullptr);
ASSERT_STREQ(cf_opts.table_factory->Name(),
config_options_, cf_opts_,
opts_str + mock::MockTableFactory::kClassName(), &cf_opts_));
ASSERT_NE(cf_opts_.table_factory.get(), nullptr);
ASSERT_STREQ(cf_opts_.table_factory->Name(),
mock::MockTableFactory::kClassName());
#endif // ROCKSDB_LITE
}
Expand Down Expand Up @@ -1763,12 +1762,12 @@ TEST_F(LoadCustomizableTest, LoadEncryptionProviderTest) {
EncryptionProvider::CreateFromString(config_options_, "CTR", &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), "CTR");
ASSERT_NOK(result->ValidateOptions(DBOptions(), ColumnFamilyOptions()));
ASSERT_NOK(result->ValidateOptions(db_opts_, cf_opts_));
ASSERT_OK(EncryptionProvider::CreateFromString(config_options_, "CTR://test",
&result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), "CTR");
ASSERT_OK(result->ValidateOptions(DBOptions(), ColumnFamilyOptions()));
ASSERT_OK(result->ValidateOptions(db_opts_, cf_opts_));

if (RegisterTests("Test")) {
ASSERT_OK(
Expand All @@ -1779,7 +1778,7 @@ TEST_F(LoadCustomizableTest, LoadEncryptionProviderTest) {
"Mock://test", &result));
ASSERT_NE(result, nullptr);
ASSERT_STREQ(result->Name(), "Mock");
ASSERT_OK(result->ValidateOptions(DBOptions(), ColumnFamilyOptions()));
ASSERT_OK(result->ValidateOptions(db_opts_, cf_opts_));
}
}

Expand Down
61 changes: 54 additions & 7 deletions options/db_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -452,7 +452,8 @@ static std::unordered_map<std::string, OptionTypeInfo>
{"file_checksum_gen_factory",
OptionTypeInfo::AsCustomSharedPtr<FileChecksumGenFactory>(
offsetof(struct ImmutableDBOptions, file_checksum_gen_factory),
OptionVerificationType::kByName, OptionTypeFlags::kAllowNull)},
OptionVerificationType::kByNameAllowFromNull,
OptionTypeFlags::kAllowNull)},
{"statistics",
OptionTypeInfo::AsCustomSharedPtr<Statistics>(
// Statistics should not be compared and can be null
Expand Down Expand Up @@ -529,19 +530,63 @@ const std::string OptionsHelper::kDBOptionsName = "DBOptions";

class MutableDBConfigurable : public Configurable {
public:
explicit MutableDBConfigurable(const MutableDBOptions& mdb) {
mutable_ = mdb;
explicit MutableDBConfigurable(
const MutableDBOptions& mdb,
const std::unordered_map<std::string, std::string>* map = nullptr)
: mutable_(mdb), opt_map_(map) {
RegisterOptions(&mutable_, &db_mutable_options_type_info);
}

bool OptionsAreEqual(const ConfigOptions& config_options,
const OptionTypeInfo& opt_info,
const std::string& opt_name, const void* const this_ptr,
const void* const that_ptr,
std::string* mismatch) const override {
bool equals = opt_info.AreEqual(config_options, opt_name, this_ptr,
that_ptr, mismatch);
if (!equals && opt_info.IsByName()) {
if (opt_map_ == nullptr) {
equals = true;
} else {
const auto& iter = opt_map_->find(opt_name);
if (iter == opt_map_->end()) {
equals = true;
} else {
equals = opt_info.AreEqualByName(config_options, opt_name, this_ptr,
iter->second);
}
}
if (equals) { // False alarm, clear mismatch
*mismatch = "";
}
}
if (equals && opt_info.IsConfigurable() && opt_map_ != nullptr) {
const auto* this_config = opt_info.AsRawPointer<Configurable>(this_ptr);
if (this_config == nullptr) {
const auto& iter = opt_map_->find(opt_name);
// If the name exists in the map and is not empty/null,
// then the this_config should be set.
if (iter != opt_map_->end() && !iter->second.empty() &&
iter->second != kNullptrString) {
*mismatch = opt_name;
equals = false;
}
}
}
return equals;
}

protected:
MutableDBOptions mutable_;
const std::unordered_map<std::string, std::string>* opt_map_;
};

class DBOptionsConfigurable : public MutableDBConfigurable {
public:
explicit DBOptionsConfigurable(const DBOptions& opts)
: MutableDBConfigurable(MutableDBOptions(opts)), db_options_(opts) {
explicit DBOptionsConfigurable(
const DBOptions& opts,
const std::unordered_map<std::string, std::string>* map = nullptr)
: MutableDBConfigurable(MutableDBOptions(opts), map), db_options_(opts) {
// The ImmutableDBOptions currently requires the env to be non-null. Make
// sure it is
if (opts.env != nullptr) {
Expand Down Expand Up @@ -585,8 +630,10 @@ std::unique_ptr<Configurable> DBOptionsAsConfigurable(
std::unique_ptr<Configurable> ptr(new MutableDBConfigurable(opts));
return ptr;
}
std::unique_ptr<Configurable> DBOptionsAsConfigurable(const DBOptions& opts) {
std::unique_ptr<Configurable> ptr(new DBOptionsConfigurable(opts));
std::unique_ptr<Configurable> DBOptionsAsConfigurable(
const DBOptions& opts,
const std::unordered_map<std::string, std::string>* opt_map) {
std::unique_ptr<Configurable> ptr(new DBOptionsConfigurable(opts, opt_map));
return ptr;
}
#endif // ROCKSDB_LITE
Expand Down
4 changes: 3 additions & 1 deletion options/options_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ void UpdateColumnFamilyOptions(const MutableCFOptions& moptions,
#ifndef ROCKSDB_LITE
std::unique_ptr<Configurable> DBOptionsAsConfigurable(
const MutableDBOptions& opts);
std::unique_ptr<Configurable> DBOptionsAsConfigurable(const DBOptions& opts);
std::unique_ptr<Configurable> DBOptionsAsConfigurable(
const DBOptions& opts,
const std::unordered_map<std::string, std::string>* opt_map = nullptr);
std::unique_ptr<Configurable> CFOptionsAsConfigurable(
const MutableCFOptions& opts);
std::unique_ptr<Configurable> CFOptionsAsConfigurable(
Expand Down
12 changes: 9 additions & 3 deletions options/options_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,12 @@ Status RocksDBOptionsParser::VerifyRocksDBOptionsFromFile(
ConfigOptions config_options = config_options_in;
config_options.invoke_prepare_options =
false; // No need to do a prepare for verify
if (config_options.sanity_level < ConfigOptions::kSanityLevelExactMatch) {
// If we are not doing an exact comparison, we should ignore
// unsupported options, as they may cause the Parse to fail
// (if the ObjectRegistry is not initialized)
config_options.ignore_unsupported_options = true;
}
Status s = parser.Parse(config_options, file_name, fs);
if (!s.ok()) {
return s;
Expand Down Expand Up @@ -622,9 +628,9 @@ Status RocksDBOptionsParser::VerifyRocksDBOptionsFromFile(
Status RocksDBOptionsParser::VerifyDBOptions(
const ConfigOptions& config_options, const DBOptions& base_opt,
const DBOptions& file_opt,
const std::unordered_map<std::string, std::string>* /*opt_map*/) {
auto base_config = DBOptionsAsConfigurable(base_opt);
auto file_config = DBOptionsAsConfigurable(file_opt);
const std::unordered_map<std::string, std::string>* opt_map) {
auto base_config = DBOptionsAsConfigurable(base_opt, opt_map);
auto file_config = DBOptionsAsConfigurable(file_opt, opt_map);
std::string mismatch;
if (!base_config->AreEquivalent(config_options, file_config.get(),
&mismatch)) {
Expand Down
Loading

0 comments on commit 8fb3fe8

Please sign in to comment.