| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782 |
- // 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).
- #include "rocksdb/utilities/options_util.h"
- #include <cctype>
- #include <cinttypes>
- #include <unordered_map>
- #include "env/mock_env.h"
- #include "file/filename.h"
- #include "options/options_parser.h"
- #include "rocksdb/convenience.h"
- #include "rocksdb/db.h"
- #include "rocksdb/table.h"
- #include "test_util/testharness.h"
- #include "test_util/testutil.h"
- #include "util/random.h"
- #ifndef GFLAGS
- bool FLAGS_enable_print = false;
- #else
- #include "util/gflags_compat.h"
- using GFLAGS_NAMESPACE::ParseCommandLineFlags;
- DEFINE_bool(enable_print, false, "Print options generated to console.");
- #endif // GFLAGS
- namespace ROCKSDB_NAMESPACE {
- class OptionsUtilTest : public testing::Test {
- public:
- OptionsUtilTest() : rnd_(0xFB) {
- env_.reset(NewMemEnv(Env::Default()));
- dbname_ = test::PerThreadDBPath("options_util_test");
- }
- protected:
- std::unique_ptr<Env> env_;
- std::string dbname_;
- Random rnd_;
- };
- TEST_F(OptionsUtilTest, SaveAndLoad) {
- const size_t kCFCount = 5;
- DBOptions db_opt;
- std::vector<std::string> cf_names;
- std::vector<ColumnFamilyOptions> cf_opts;
- test::RandomInitDBOptions(&db_opt, &rnd_);
- for (size_t i = 0; i < kCFCount; ++i) {
- cf_names.push_back(i == 0 ? kDefaultColumnFamilyName
- : test::RandomName(&rnd_, 10));
- cf_opts.emplace_back();
- test::RandomInitCFOptions(&cf_opts.back(), db_opt, &rnd_);
- }
- const std::string kFileName = "OPTIONS-123456";
- ASSERT_OK(PersistRocksDBOptions(WriteOptions(), db_opt, cf_names, cf_opts,
- kFileName, env_->GetFileSystem().get()));
- DBOptions loaded_db_opt;
- std::vector<ColumnFamilyDescriptor> loaded_cf_descs;
- ConfigOptions config_options;
- config_options.ignore_unknown_options = false;
- config_options.input_strings_escaped = true;
- config_options.env = env_.get();
- ASSERT_OK(LoadOptionsFromFile(config_options, kFileName, &loaded_db_opt,
- &loaded_cf_descs));
- ConfigOptions exact;
- exact.sanity_level = ConfigOptions::kSanityLevelExactMatch;
- ASSERT_OK(
- RocksDBOptionsParser::VerifyDBOptions(exact, db_opt, loaded_db_opt));
- test::RandomInitDBOptions(&db_opt, &rnd_);
- ASSERT_NOK(
- RocksDBOptionsParser::VerifyDBOptions(exact, db_opt, loaded_db_opt));
- for (size_t i = 0; i < kCFCount; ++i) {
- ASSERT_EQ(cf_names[i], loaded_cf_descs[i].name);
- ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(
- exact, cf_opts[i], loaded_cf_descs[i].options));
- ASSERT_OK(RocksDBOptionsParser::VerifyTableFactory(
- exact, cf_opts[i].table_factory.get(),
- loaded_cf_descs[i].options.table_factory.get()));
- test::RandomInitCFOptions(&cf_opts[i], db_opt, &rnd_);
- ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions(
- exact, cf_opts[i], loaded_cf_descs[i].options));
- }
- ASSERT_OK(DestroyDB(dbname_, Options(db_opt, cf_opts[0])));
- for (size_t i = 0; i < kCFCount; ++i) {
- if (cf_opts[i].compaction_filter) {
- delete cf_opts[i].compaction_filter;
- }
- }
- }
- TEST_F(OptionsUtilTest, SaveAndLoadWithCacheCheck) {
- // creating db
- DBOptions db_opt;
- db_opt.create_if_missing = true;
- // initialize BlockBasedTableOptions
- std::shared_ptr<Cache> cache = NewLRUCache(1 * 1024);
- BlockBasedTableOptions bbt_opts;
- bbt_opts.block_size = 32 * 1024;
- // saving cf options
- std::vector<ColumnFamilyOptions> cf_opts;
- ColumnFamilyOptions default_column_family_opt = ColumnFamilyOptions();
- default_column_family_opt.table_factory.reset(
- NewBlockBasedTableFactory(bbt_opts));
- cf_opts.push_back(default_column_family_opt);
- ColumnFamilyOptions cf_opt_sample = ColumnFamilyOptions();
- cf_opt_sample.table_factory.reset(NewBlockBasedTableFactory(bbt_opts));
- cf_opts.push_back(cf_opt_sample);
- ColumnFamilyOptions cf_opt_plain_table_opt = ColumnFamilyOptions();
- cf_opt_plain_table_opt.table_factory.reset(NewPlainTableFactory());
- cf_opts.push_back(cf_opt_plain_table_opt);
- std::vector<std::string> cf_names;
- cf_names.push_back(kDefaultColumnFamilyName);
- cf_names.emplace_back("cf_sample");
- cf_names.emplace_back("cf_plain_table_sample");
- // Saving DB in file
- const std::string kFileName = "OPTIONS-LOAD_CACHE_123456";
- ASSERT_OK(PersistRocksDBOptions(WriteOptions(), db_opt, cf_names, cf_opts,
- kFileName, env_->GetFileSystem().get()));
- DBOptions loaded_db_opt;
- std::vector<ColumnFamilyDescriptor> loaded_cf_descs;
- ConfigOptions config_options;
- config_options.ignore_unknown_options = false;
- config_options.input_strings_escaped = true;
- config_options.env = env_.get();
- ASSERT_OK(LoadOptionsFromFile(config_options, kFileName, &loaded_db_opt,
- &loaded_cf_descs, &cache));
- for (size_t i = 0; i < loaded_cf_descs.size(); i++) {
- auto* loaded_bbt_opt =
- loaded_cf_descs[i]
- .options.table_factory->GetOptions<BlockBasedTableOptions>();
- // Expect the same cache will be loaded
- if (loaded_bbt_opt != nullptr) {
- ASSERT_EQ(loaded_bbt_opt->block_cache.get(), cache.get());
- }
- }
- ASSERT_OK(DestroyDB(dbname_, Options(loaded_db_opt, cf_opts[0])));
- }
- namespace {
- class DummyTableFactory : public TableFactory {
- public:
- DummyTableFactory() = default;
- ~DummyTableFactory() override = default;
- const char* Name() const override { return "DummyTableFactory"; }
- using TableFactory::NewTableReader;
- Status NewTableReader(
- const ReadOptions& /*ro*/,
- const TableReaderOptions& /*table_reader_options*/,
- std::unique_ptr<RandomAccessFileReader>&& /*file*/,
- uint64_t /*file_size*/, std::unique_ptr<TableReader>* /*table_reader*/,
- bool /*prefetch_index_and_filter_in_cache*/) const override {
- return Status::NotSupported();
- }
- TableBuilder* NewTableBuilder(
- const TableBuilderOptions& /*table_builder_options*/,
- WritableFileWriter* /*file*/) const override {
- return nullptr;
- }
- Status ValidateOptions(
- const DBOptions& /*db_opts*/,
- const ColumnFamilyOptions& /*cf_opts*/) const override {
- return Status::NotSupported();
- }
- std::string GetPrintableOptions() const override { return ""; }
- std::unique_ptr<TableFactory> Clone() const override { return nullptr; }
- };
- class DummyMergeOperator : public MergeOperator {
- public:
- DummyMergeOperator() = default;
- ~DummyMergeOperator() override = default;
- bool FullMergeV2(const MergeOperationInput& /*merge_in*/,
- MergeOperationOutput* /*merge_out*/) const override {
- return false;
- }
- bool PartialMergeMulti(const Slice& /*key*/,
- const std::deque<Slice>& /*operand_list*/,
- std::string* /*new_value*/,
- Logger* /*logger*/) const override {
- return false;
- }
- const char* Name() const override { return "DummyMergeOperator"; }
- };
- class DummySliceTransform : public SliceTransform {
- public:
- DummySliceTransform() = default;
- ~DummySliceTransform() override = default;
- // Return the name of this transformation.
- const char* Name() const override { return "DummySliceTransform"; }
- // transform a src in domain to a dst in the range
- Slice Transform(const Slice& src) const override { return src; }
- // determine whether this is a valid src upon the function applies
- bool InDomain(const Slice& /*src*/) const override { return false; }
- // determine whether dst=Transform(src) for some src
- bool InRange(const Slice& /*dst*/) const override { return false; }
- };
- } // namespace
- TEST_F(OptionsUtilTest, SanityCheck) {
- DBOptions db_opt;
- std::vector<ColumnFamilyDescriptor> cf_descs;
- const size_t kCFCount = 5;
- for (size_t i = 0; i < kCFCount; ++i) {
- cf_descs.emplace_back();
- cf_descs.back().name =
- (i == 0) ? kDefaultColumnFamilyName : test::RandomName(&rnd_, 10);
- cf_descs.back().options.table_factory.reset(NewBlockBasedTableFactory());
- // Assign non-null values to prefix_extractors except the first cf.
- cf_descs.back().options.prefix_extractor.reset(
- i != 0 ? test::RandomSliceTransform(&rnd_) : nullptr);
- cf_descs.back().options.merge_operator.reset(
- test::RandomMergeOperator(&rnd_));
- }
- db_opt.create_missing_column_families = true;
- db_opt.create_if_missing = true;
- ASSERT_OK(DestroyDB(dbname_, Options(db_opt, cf_descs[0].options)));
- DB* db;
- std::vector<ColumnFamilyHandle*> handles;
- // open and persist the options
- ASSERT_OK(DB::Open(db_opt, dbname_, cf_descs, &handles, &db));
- // close the db
- for (auto* handle : handles) {
- delete handle;
- }
- delete db;
- ConfigOptions config_options;
- config_options.ignore_unknown_options = false;
- config_options.input_strings_escaped = true;
- config_options.sanity_level = ConfigOptions::kSanityLevelLooselyCompatible;
- // perform sanity check
- ASSERT_OK(
- CheckOptionsCompatibility(config_options, dbname_, db_opt, cf_descs));
- ASSERT_GE(kCFCount, 5);
- // merge operator
- {
- std::shared_ptr<MergeOperator> merge_op =
- cf_descs[0].options.merge_operator;
- ASSERT_NE(merge_op.get(), nullptr);
- cf_descs[0].options.merge_operator.reset();
- ASSERT_NOK(
- CheckOptionsCompatibility(config_options, dbname_, db_opt, cf_descs));
- cf_descs[0].options.merge_operator.reset(new DummyMergeOperator());
- ASSERT_NOK(
- CheckOptionsCompatibility(config_options, dbname_, db_opt, cf_descs));
- cf_descs[0].options.merge_operator = merge_op;
- ASSERT_OK(
- CheckOptionsCompatibility(config_options, dbname_, db_opt, cf_descs));
- }
- // prefix extractor
- {
- std::shared_ptr<const SliceTransform> prefix_extractor =
- cf_descs[1].options.prefix_extractor;
- // It's okay to set prefix_extractor to nullptr.
- ASSERT_NE(prefix_extractor, nullptr);
- cf_descs[1].options.prefix_extractor.reset();
- ASSERT_OK(
- CheckOptionsCompatibility(config_options, dbname_, db_opt, cf_descs));
- cf_descs[1].options.prefix_extractor.reset(new DummySliceTransform());
- ASSERT_OK(
- CheckOptionsCompatibility(config_options, dbname_, db_opt, cf_descs));
- cf_descs[1].options.prefix_extractor = prefix_extractor;
- ASSERT_OK(
- CheckOptionsCompatibility(config_options, dbname_, db_opt, cf_descs));
- }
- // prefix extractor nullptr case
- {
- std::shared_ptr<const SliceTransform> prefix_extractor =
- cf_descs[0].options.prefix_extractor;
- // It's okay to set prefix_extractor to nullptr.
- ASSERT_EQ(prefix_extractor, nullptr);
- cf_descs[0].options.prefix_extractor.reset();
- ASSERT_OK(
- CheckOptionsCompatibility(config_options, dbname_, db_opt, cf_descs));
- // It's okay to change prefix_extractor from nullptr to non-nullptr
- cf_descs[0].options.prefix_extractor.reset(new DummySliceTransform());
- ASSERT_OK(
- CheckOptionsCompatibility(config_options, dbname_, db_opt, cf_descs));
- cf_descs[0].options.prefix_extractor = prefix_extractor;
- ASSERT_OK(
- CheckOptionsCompatibility(config_options, dbname_, db_opt, cf_descs));
- }
- // comparator
- {
- test::SimpleSuffixReverseComparator comparator;
- auto* prev_comparator = cf_descs[2].options.comparator;
- cf_descs[2].options.comparator = &comparator;
- ASSERT_NOK(
- CheckOptionsCompatibility(config_options, dbname_, db_opt, cf_descs));
- cf_descs[2].options.comparator = prev_comparator;
- ASSERT_OK(
- CheckOptionsCompatibility(config_options, dbname_, db_opt, cf_descs));
- }
- // table factory
- {
- std::shared_ptr<TableFactory> table_factory =
- cf_descs[3].options.table_factory;
- ASSERT_NE(table_factory, nullptr);
- cf_descs[3].options.table_factory.reset(new DummyTableFactory());
- ASSERT_NOK(
- CheckOptionsCompatibility(config_options, dbname_, db_opt, cf_descs));
- cf_descs[3].options.table_factory = table_factory;
- ASSERT_OK(
- CheckOptionsCompatibility(config_options, dbname_, db_opt, cf_descs));
- }
- // persist_user_defined_timestamps
- {
- bool prev_persist_user_defined_timestamps =
- cf_descs[2].options.persist_user_defined_timestamps;
- cf_descs[2].options.persist_user_defined_timestamps = false;
- ASSERT_NOK(
- CheckOptionsCompatibility(config_options, dbname_, db_opt, cf_descs));
- cf_descs[2].options.persist_user_defined_timestamps =
- prev_persist_user_defined_timestamps;
- ASSERT_OK(
- CheckOptionsCompatibility(config_options, dbname_, db_opt, cf_descs));
- }
- ASSERT_OK(DestroyDB(dbname_, Options(db_opt, cf_descs[0].options)));
- }
- TEST_F(OptionsUtilTest, LatestOptionsNotFound) {
- std::unique_ptr<Env> env(NewMemEnv(Env::Default()));
- Status s;
- Options options;
- ConfigOptions config_opts;
- std::vector<ColumnFamilyDescriptor> cf_descs;
- options.env = env.get();
- options.create_if_missing = true;
- config_opts.env = options.env;
- config_opts.ignore_unknown_options = false;
- std::vector<std::string> children;
- std::string options_file_name;
- ASSERT_OK(DestroyDB(dbname_, options));
- // First, test where the db directory does not exist
- ASSERT_NOK(options.env->GetChildren(dbname_, &children));
- s = GetLatestOptionsFileName(dbname_, options.env, &options_file_name);
- ASSERT_TRUE(s.IsNotFound());
- ASSERT_TRUE(s.IsPathNotFound());
- s = LoadLatestOptions(config_opts, dbname_, &options, &cf_descs);
- ASSERT_TRUE(s.IsNotFound());
- ASSERT_TRUE(s.IsPathNotFound());
- s = GetLatestOptionsFileName(dbname_, options.env, &options_file_name);
- ASSERT_TRUE(s.IsNotFound());
- ASSERT_TRUE(s.IsPathNotFound());
- // Second, test where the db directory exists but is empty
- ASSERT_OK(options.env->CreateDir(dbname_));
- s = GetLatestOptionsFileName(dbname_, options.env, &options_file_name);
- ASSERT_TRUE(s.IsNotFound());
- ASSERT_TRUE(s.IsPathNotFound());
- s = LoadLatestOptions(config_opts, dbname_, &options, &cf_descs);
- ASSERT_TRUE(s.IsNotFound());
- ASSERT_TRUE(s.IsPathNotFound());
- // Finally, test where a file exists but is not an "Options" file
- std::unique_ptr<WritableFile> file;
- ASSERT_OK(
- options.env->NewWritableFile(dbname_ + "/temp.txt", &file, EnvOptions()));
- ASSERT_OK(file->Close());
- s = GetLatestOptionsFileName(dbname_, options.env, &options_file_name);
- ASSERT_TRUE(s.IsNotFound());
- ASSERT_TRUE(s.IsPathNotFound());
- s = LoadLatestOptions(config_opts, dbname_, &options, &cf_descs);
- ASSERT_TRUE(s.IsNotFound());
- ASSERT_TRUE(s.IsPathNotFound());
- ASSERT_OK(options.env->DeleteFile(dbname_ + "/temp.txt"));
- ASSERT_OK(options.env->DeleteDir(dbname_));
- }
- TEST_F(OptionsUtilTest, LoadLatestOptions) {
- Options options;
- options.OptimizeForSmallDb();
- ColumnFamilyDescriptor cf_desc;
- ConfigOptions config_opts;
- DBOptions db_opts;
- std::vector<ColumnFamilyDescriptor> cf_descs;
- std::vector<ColumnFamilyHandle*> handles;
- DB* db;
- options.create_if_missing = true;
- ASSERT_OK(DestroyDB(dbname_, options));
- cf_descs.emplace_back();
- cf_descs.back().name = kDefaultColumnFamilyName;
- cf_descs.back().options.table_factory.reset(NewBlockBasedTableFactory());
- cf_descs.emplace_back();
- cf_descs.back().name = "Plain";
- cf_descs.back().options.table_factory.reset(NewPlainTableFactory());
- db_opts.create_missing_column_families = true;
- db_opts.create_if_missing = true;
- // open and persist the options
- ASSERT_OK(DB::Open(db_opts, dbname_, cf_descs, &handles, &db));
- std::string options_file_name;
- std::string new_options_file;
- ASSERT_OK(GetLatestOptionsFileName(dbname_, options.env, &options_file_name));
- ASSERT_OK(LoadLatestOptions(config_opts, dbname_, &db_opts, &cf_descs));
- ASSERT_EQ(cf_descs.size(), 2U);
- ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(config_opts,
- db->GetDBOptions(), db_opts));
- ASSERT_OK(handles[0]->GetDescriptor(&cf_desc));
- ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_opts, cf_desc.options,
- cf_descs[0].options));
- ASSERT_OK(handles[1]->GetDescriptor(&cf_desc));
- ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_opts, cf_desc.options,
- cf_descs[1].options));
- // Now change some of the DBOptions
- ASSERT_OK(db->SetDBOptions(
- {{"delayed_write_rate", "1234"}, {"bytes_per_sync", "32768"}}));
- ASSERT_OK(GetLatestOptionsFileName(dbname_, options.env, &new_options_file));
- ASSERT_NE(options_file_name, new_options_file);
- ASSERT_OK(LoadLatestOptions(config_opts, dbname_, &db_opts, &cf_descs));
- ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(config_opts,
- db->GetDBOptions(), db_opts));
- options_file_name = new_options_file;
- // Now change some of the ColumnFamilyOptions
- ASSERT_OK(db->SetOptions(handles[1], {{"write_buffer_size", "32768"}}));
- ASSERT_OK(GetLatestOptionsFileName(dbname_, options.env, &new_options_file));
- ASSERT_NE(options_file_name, new_options_file);
- ASSERT_OK(LoadLatestOptions(config_opts, dbname_, &db_opts, &cf_descs));
- ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(config_opts,
- db->GetDBOptions(), db_opts));
- ASSERT_OK(handles[0]->GetDescriptor(&cf_desc));
- ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_opts, cf_desc.options,
- cf_descs[0].options));
- ASSERT_OK(handles[1]->GetDescriptor(&cf_desc));
- ASSERT_OK(RocksDBOptionsParser::VerifyCFOptions(config_opts, cf_desc.options,
- cf_descs[1].options));
- // close the db
- for (auto* handle : handles) {
- delete handle;
- }
- delete db;
- ASSERT_OK(DestroyDB(dbname_, options, cf_descs));
- }
- static void WriteOptionsFile(Env* env, const std::string& path,
- const std::string& options_file, int major,
- int minor, const std::string& db_opts,
- const std::string& cf_opts,
- const std::string& bbt_opts = "") {
- std::string options_file_header =
- "\n"
- "[Version]\n"
- " rocksdb_version=" +
- std::to_string(major) + "." + std::to_string(minor) +
- ".0\n"
- " options_file_version=1\n";
- std::unique_ptr<WritableFile> wf;
- ASSERT_OK(env->NewWritableFile(path + "/" + options_file, &wf, EnvOptions()));
- ASSERT_OK(
- wf->Append(options_file_header + "[ DBOptions ]\n" + db_opts + "\n"));
- ASSERT_OK(wf->Append(
- "[CFOptions \"default\"] # column family must be specified\n" +
- cf_opts + "\n"));
- ASSERT_OK(wf->Append("[TableOptions/BlockBasedTable \"default\"]\n" +
- bbt_opts + "\n"));
- ASSERT_OK(wf->Close());
- std::string latest_options_file;
- ASSERT_OK(GetLatestOptionsFileName(path, env, &latest_options_file));
- ASSERT_EQ(latest_options_file, options_file);
- }
- TEST_F(OptionsUtilTest, BadLatestOptions) {
- Status s;
- ConfigOptions config_opts;
- DBOptions db_opts;
- std::vector<ColumnFamilyDescriptor> cf_descs;
- Options options;
- options.env = env_.get();
- config_opts.env = env_.get();
- config_opts.ignore_unknown_options = false;
- config_opts.delimiter = "\n";
- ConfigOptions ignore_opts = config_opts;
- ignore_opts.ignore_unknown_options = true;
- std::string options_file_name;
- // Test where the db directory exists but is empty
- ASSERT_OK(options.env->CreateDir(dbname_));
- ASSERT_NOK(
- GetLatestOptionsFileName(dbname_, options.env, &options_file_name));
- ASSERT_NOK(LoadLatestOptions(config_opts, dbname_, &db_opts, &cf_descs));
- // Write an options file for a previous major release with an unknown DB
- // Option
- WriteOptionsFile(options.env, dbname_, "OPTIONS-0001", ROCKSDB_MAJOR - 1,
- ROCKSDB_MINOR, "unknown_db_opt=true", "");
- s = LoadLatestOptions(config_opts, dbname_, &db_opts, &cf_descs);
- ASSERT_NOK(s);
- ASSERT_TRUE(s.IsInvalidArgument());
- // Even though ignore_unknown_options=true, we still return an error...
- s = LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs);
- ASSERT_NOK(s);
- ASSERT_TRUE(s.IsInvalidArgument());
- // Write an options file for a previous minor release with an unknown CF
- // Option
- WriteOptionsFile(options.env, dbname_, "OPTIONS-0002", ROCKSDB_MAJOR,
- ROCKSDB_MINOR - 1, "", "unknown_cf_opt=true");
- s = LoadLatestOptions(config_opts, dbname_, &db_opts, &cf_descs);
- ASSERT_NOK(s);
- ASSERT_TRUE(s.IsInvalidArgument());
- // Even though ignore_unknown_options=true, we still return an error...
- s = LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs);
- ASSERT_NOK(s);
- ASSERT_TRUE(s.IsInvalidArgument());
- // Write an options file for a previous minor release with an unknown BBT
- // Option
- WriteOptionsFile(options.env, dbname_, "OPTIONS-0003", ROCKSDB_MAJOR,
- ROCKSDB_MINOR - 1, "", "", "unknown_bbt_opt=true");
- s = LoadLatestOptions(config_opts, dbname_, &db_opts, &cf_descs);
- ASSERT_NOK(s);
- ASSERT_TRUE(s.IsInvalidArgument());
- // Even though ignore_unknown_options=true, we still return an error...
- s = LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs);
- ASSERT_NOK(s);
- ASSERT_TRUE(s.IsInvalidArgument());
- // Write an options file for the current release with an unknown DB Option
- WriteOptionsFile(options.env, dbname_, "OPTIONS-0004", ROCKSDB_MAJOR,
- ROCKSDB_MINOR, "unknown_db_opt=true", "");
- s = LoadLatestOptions(config_opts, dbname_, &db_opts, &cf_descs);
- ASSERT_NOK(s);
- ASSERT_TRUE(s.IsInvalidArgument());
- // Even though ignore_unknown_options=true, we still return an error...
- s = LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs);
- ASSERT_NOK(s);
- ASSERT_TRUE(s.IsInvalidArgument());
- // Write an options file for the current release with an unknown CF Option
- WriteOptionsFile(options.env, dbname_, "OPTIONS-0005", ROCKSDB_MAJOR,
- ROCKSDB_MINOR, "", "unknown_cf_opt=true");
- s = LoadLatestOptions(config_opts, dbname_, &db_opts, &cf_descs);
- ASSERT_NOK(s);
- ASSERT_TRUE(s.IsInvalidArgument());
- // Even though ignore_unknown_options=true, we still return an error...
- s = LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs);
- ASSERT_NOK(s);
- ASSERT_TRUE(s.IsInvalidArgument());
- // Write an options file for the current release with an invalid DB Option
- WriteOptionsFile(options.env, dbname_, "OPTIONS-0006", ROCKSDB_MAJOR,
- ROCKSDB_MINOR, "create_if_missing=hello", "");
- s = LoadLatestOptions(config_opts, dbname_, &db_opts, &cf_descs);
- ASSERT_NOK(s);
- ASSERT_TRUE(s.IsInvalidArgument());
- // Even though ignore_unknown_options=true, we still return an error...
- s = LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs);
- ASSERT_NOK(s);
- ASSERT_TRUE(s.IsInvalidArgument());
- // Write an options file for the next release with an invalid DB Option
- WriteOptionsFile(options.env, dbname_, "OPTIONS-0007", ROCKSDB_MAJOR,
- ROCKSDB_MINOR + 1, "create_if_missing=hello", "");
- ASSERT_NOK(LoadLatestOptions(config_opts, dbname_, &db_opts, &cf_descs));
- ASSERT_OK(LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs));
- // Write an options file for the next release with an unknown DB Option
- WriteOptionsFile(options.env, dbname_, "OPTIONS-0008", ROCKSDB_MAJOR,
- ROCKSDB_MINOR + 1, "unknown_db_opt=true", "");
- ASSERT_NOK(LoadLatestOptions(config_opts, dbname_, &db_opts, &cf_descs));
- // Ignore the errors for future releases when ignore_unknown_options=true
- ASSERT_OK(LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs));
- // Write an options file for the next major release with an unknown CF Option
- WriteOptionsFile(options.env, dbname_, "OPTIONS-0009", ROCKSDB_MAJOR + 1,
- ROCKSDB_MINOR, "", "unknown_cf_opt=true");
- ASSERT_NOK(LoadLatestOptions(config_opts, dbname_, &db_opts, &cf_descs));
- // Ignore the errors for future releases when ignore_unknown_options=true
- ASSERT_OK(LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs));
- }
- TEST_F(OptionsUtilTest, RenameDatabaseDirectory) {
- DB* db;
- Options options;
- DBOptions db_opts;
- std::vector<ColumnFamilyDescriptor> cf_descs;
- std::vector<ColumnFamilyHandle*> handles;
- ConfigOptions ignore_opts;
- ignore_opts.ignore_unknown_options = false;
- ignore_opts.env = options.env;
- options.create_if_missing = true;
- ASSERT_OK(DB::Open(options, dbname_, &db));
- ASSERT_OK(db->Put(WriteOptions(), "foo", "value0"));
- delete db;
- auto new_dbname = dbname_ + "_2";
- ASSERT_OK(options.env->RenameFile(dbname_, new_dbname));
- ASSERT_OK(LoadLatestOptions(ignore_opts, new_dbname, &db_opts, &cf_descs));
- ASSERT_EQ(cf_descs.size(), 1U);
- db_opts.create_if_missing = false;
- ASSERT_OK(DB::Open(db_opts, new_dbname, cf_descs, &handles, &db));
- std::string value;
- ASSERT_OK(db->Get(ReadOptions(), "foo", &value));
- ASSERT_EQ("value0", value);
- // close the db
- for (auto* handle : handles) {
- delete handle;
- }
- delete db;
- Options new_options(db_opts, cf_descs[0].options);
- ASSERT_OK(DestroyDB(new_dbname, new_options, cf_descs));
- ASSERT_OK(DestroyDB(dbname_, options));
- }
- TEST_F(OptionsUtilTest, WalDirSettings) {
- DB* db;
- Options options;
- DBOptions db_opts;
- std::vector<ColumnFamilyDescriptor> cf_descs;
- std::vector<ColumnFamilyHandle*> handles;
- ConfigOptions ignore_opts;
- ignore_opts.ignore_unknown_options = false;
- ignore_opts.env = options.env;
- options.create_if_missing = true;
- // Open a DB with no wal dir set. The wal_dir should stay empty
- ASSERT_OK(DB::Open(options, dbname_, &db));
- delete db;
- ASSERT_OK(LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs));
- ASSERT_EQ(db_opts.wal_dir, "");
- // Open a DB with wal_dir == dbname. The wal_dir should be set to empty
- options.wal_dir = dbname_;
- ASSERT_OK(DB::Open(options, dbname_, &db));
- delete db;
- ASSERT_OK(LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs));
- ASSERT_EQ(db_opts.wal_dir, "");
- // Open a DB with no wal_dir but a db_path==dbname_. The wal_dir should be
- // empty
- options.wal_dir = "";
- options.db_paths.emplace_back(dbname_, std::numeric_limits<uint64_t>::max());
- ASSERT_OK(DB::Open(options, dbname_, &db));
- delete db;
- ASSERT_OK(LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs));
- ASSERT_EQ(db_opts.wal_dir, "");
- // Open a DB with no wal_dir==dbname_ and db_path==dbname_. The wal_dir
- // should be empty
- options.wal_dir = dbname_ + "/";
- options.db_paths.emplace_back(dbname_, std::numeric_limits<uint64_t>::max());
- ASSERT_OK(DB::Open(options, dbname_, &db));
- delete db;
- ASSERT_OK(LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs));
- ASSERT_EQ(db_opts.wal_dir, "");
- ASSERT_OK(DestroyDB(dbname_, options));
- // Open a DB with no wal_dir but db_path != db_name. The wal_dir == dbname_
- options.wal_dir = "";
- options.db_paths.clear();
- options.db_paths.emplace_back(dbname_ + "_0",
- std::numeric_limits<uint64_t>::max());
- ASSERT_OK(DB::Open(options, dbname_, &db));
- delete db;
- ASSERT_OK(LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs));
- ASSERT_EQ(db_opts.wal_dir, dbname_);
- ASSERT_OK(DestroyDB(dbname_, options));
- // Open a DB with wal_dir != db_name. The wal_dir remains unchanged
- options.wal_dir = dbname_ + "/wal";
- options.db_paths.clear();
- ASSERT_OK(DB::Open(options, dbname_, &db));
- delete db;
- ASSERT_OK(LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs));
- ASSERT_EQ(db_opts.wal_dir, dbname_ + "/wal");
- ASSERT_OK(DestroyDB(dbname_, options));
- }
- TEST_F(OptionsUtilTest, WalDirInOptins) {
- DB* db;
- Options options;
- DBOptions db_opts;
- std::vector<ColumnFamilyDescriptor> cf_descs;
- std::vector<ColumnFamilyHandle*> handles;
- ConfigOptions ignore_opts;
- ignore_opts.ignore_unknown_options = false;
- ignore_opts.env = options.env;
- // Store an options file with wal_dir=dbname_ and make sure it still loads
- // when the input wal_dir is empty
- options.create_if_missing = true;
- options.wal_dir = "";
- ASSERT_OK(DB::Open(options, dbname_, &db));
- delete db;
- options.wal_dir = dbname_;
- std::string options_file;
- ASSERT_OK(GetLatestOptionsFileName(dbname_, options.env, &options_file));
- ASSERT_OK(PersistRocksDBOptions(WriteOptions(), options, {"default"},
- {options}, dbname_ + "/" + options_file,
- options.env->GetFileSystem().get()));
- ASSERT_OK(LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs));
- ASSERT_EQ(db_opts.wal_dir, dbname_);
- options.wal_dir = "";
- ASSERT_OK(DB::Open(options, dbname_, &db));
- delete db;
- ASSERT_OK(LoadLatestOptions(ignore_opts, dbname_, &db_opts, &cf_descs));
- ASSERT_EQ(db_opts.wal_dir, "");
- }
- } // namespace ROCKSDB_NAMESPACE
- int main(int argc, char** argv) {
- ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
- ::testing::InitGoogleTest(&argc, argv);
- #ifdef GFLAGS
- ParseCommandLineFlags(&argc, &argv, true);
- #endif // GFLAGS
- return RUN_ALL_TESTS();
- }
|