| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765 |
- // 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 "options/options_parser.h"
- #include <cmath>
- #include <map>
- #include <string>
- #include <utility>
- #include <vector>
- #include "file/file_util.h"
- #include "file/line_file_reader.h"
- #include "file/writable_file_writer.h"
- #include "options/cf_options.h"
- #include "options/db_options.h"
- #include "options/options_helper.h"
- #include "port/port.h"
- #include "rocksdb/convenience.h"
- #include "rocksdb/db.h"
- #include "rocksdb/utilities/options_type.h"
- #include "test_util/sync_point.h"
- #include "util/cast_util.h"
- #include "util/string_util.h"
- namespace ROCKSDB_NAMESPACE {
- static const std::string option_file_header =
- "# This is a RocksDB option file.\n"
- "#\n"
- "# For detailed file format spec, please refer to the example file\n"
- "# in examples/rocksdb_option_file_example.ini\n"
- "#\n"
- "\n";
- Status PersistRocksDBOptions(const WriteOptions& write_options,
- const DBOptions& db_opt,
- const std::vector<std::string>& cf_names,
- const std::vector<ColumnFamilyOptions>& cf_opts,
- const std::string& file_name, FileSystem* fs) {
- ConfigOptions
- config_options; // Use default for escaped(true) and check (exact)
- config_options.delimiter = "\n ";
- // Do not invoke PrepareOptions when we are doing validation.
- config_options.invoke_prepare_options = false;
- // If a readahead size was set in the input options, use it
- if (db_opt.log_readahead_size > 0) {
- config_options.file_readahead_size = db_opt.log_readahead_size;
- }
- return PersistRocksDBOptions(write_options, config_options, db_opt, cf_names,
- cf_opts, file_name, fs);
- }
- Status PersistRocksDBOptions(const WriteOptions& write_options,
- const ConfigOptions& config_options_in,
- const DBOptions& db_opt,
- const std::vector<std::string>& cf_names,
- const std::vector<ColumnFamilyOptions>& cf_opts,
- const std::string& file_name, FileSystem* fs) {
- ConfigOptions config_options = config_options_in;
- config_options.delimiter = "\n "; // Override the default to nl
- TEST_SYNC_POINT("PersistRocksDBOptions:start");
- if (cf_names.size() != cf_opts.size()) {
- return Status::InvalidArgument(
- "cf_names.size() and cf_opts.size() must be the same");
- }
- std::unique_ptr<FSWritableFile> wf;
- FileOptions file_options;
- file_options.temperature = db_opt.metadata_write_temperature;
- Status s = fs->NewWritableFile(file_name, file_options, &wf, nullptr);
- if (!s.ok()) {
- return s;
- }
- std::unique_ptr<WritableFileWriter> writable;
- writable.reset(new WritableFileWriter(std::move(wf), file_name, EnvOptions(),
- nullptr /* statistics */));
- TEST_SYNC_POINT("PersistRocksDBOptions:create");
- std::string options_file_content;
- IOOptions opts;
- s = WritableFileWriter::PrepareIOOptions(write_options, opts);
- if (s.ok()) {
- s = writable->Append(opts, option_file_header + "[" +
- opt_section_titles[kOptionSectionVersion] +
- "]\n"
- " rocksdb_version=" +
- std::to_string(ROCKSDB_MAJOR) + "." +
- std::to_string(ROCKSDB_MINOR) + "." +
- std::to_string(ROCKSDB_PATCH) + "\n");
- }
- if (s.ok()) {
- s = writable->Append(
- opts,
- " options_file_version=" + std::to_string(ROCKSDB_OPTION_FILE_MAJOR) +
- "." + std::to_string(ROCKSDB_OPTION_FILE_MINOR) + "\n");
- }
- if (s.ok()) {
- s = writable->Append(
- opts, "\n[" + opt_section_titles[kOptionSectionDBOptions] + "]\n ");
- }
- if (s.ok()) {
- s = GetStringFromDBOptions(config_options, db_opt, &options_file_content);
- }
- if (s.ok()) {
- s = writable->Append(opts, options_file_content + "\n");
- }
- for (size_t i = 0; s.ok() && i < cf_opts.size(); ++i) {
- // CFOptions section
- s = writable->Append(
- opts, "\n[" + opt_section_titles[kOptionSectionCFOptions] + " \"" +
- EscapeOptionString(cf_names[i]) + "\"]\n ");
- if (s.ok()) {
- s = GetStringFromColumnFamilyOptions(config_options, cf_opts[i],
- &options_file_content);
- }
- if (s.ok()) {
- s = writable->Append(opts, options_file_content + "\n");
- }
- // TableOptions section
- auto* tf = cf_opts[i].table_factory.get();
- if (tf != nullptr) {
- if (s.ok()) {
- s = writable->Append(
- opts, "[" + opt_section_titles[kOptionSectionTableOptions] +
- tf->Name() + " \"" + EscapeOptionString(cf_names[i]) +
- "\"]\n ");
- }
- if (s.ok()) {
- options_file_content.clear();
- s = tf->GetOptionString(config_options, &options_file_content);
- }
- if (s.ok()) {
- s = writable->Append(opts, options_file_content + "\n");
- }
- }
- }
- if (s.ok()) {
- s = writable->Sync(opts, true /* use_fsync */);
- }
- if (s.ok()) {
- s = writable->Close(opts);
- }
- TEST_SYNC_POINT("PersistRocksDBOptions:written");
- if (s.ok()) {
- return RocksDBOptionsParser::VerifyRocksDBOptionsFromFile(
- config_options, db_opt, cf_names, cf_opts, file_name, fs);
- }
- return s;
- }
- RocksDBOptionsParser::RocksDBOptionsParser() { Reset(); }
- void RocksDBOptionsParser::Reset() {
- db_opt_ = DBOptions();
- db_opt_map_.clear();
- cf_names_.clear();
- cf_opts_.clear();
- cf_opt_maps_.clear();
- has_version_section_ = false;
- has_db_options_ = false;
- has_default_cf_options_ = false;
- for (int i = 0; i < 3; ++i) {
- db_version[i] = 0;
- opt_file_version[i] = 0;
- }
- }
- bool RocksDBOptionsParser::IsSection(const std::string& line) {
- if (line.size() < 2) {
- return false;
- }
- if (line[0] != '[' || line[line.size() - 1] != ']') {
- return false;
- }
- return true;
- }
- Status RocksDBOptionsParser::ParseSection(OptionSection* section,
- std::string* title,
- std::string* argument,
- const std::string& line,
- const int line_num) {
- *section = kOptionSectionUnknown;
- // A section is of the form [<SectionName> "<SectionArg>"], where
- // "<SectionArg>" is optional.
- size_t arg_start_pos = line.find('\"');
- size_t arg_end_pos = line.rfind('\"');
- // The following if-then check tries to identify whether the input
- // section has the optional section argument.
- if (arg_start_pos != std::string::npos && arg_start_pos != arg_end_pos) {
- *title = TrimAndRemoveComment(line.substr(1, arg_start_pos - 1), true);
- *argument = UnescapeOptionString(
- line.substr(arg_start_pos + 1, arg_end_pos - arg_start_pos - 1));
- } else {
- *title = TrimAndRemoveComment(line.substr(1, line.size() - 2), true);
- *argument = "";
- }
- for (int i = 0; i < kOptionSectionUnknown; ++i) {
- if (title->find(opt_section_titles[i]) == 0) {
- if (i == kOptionSectionVersion || i == kOptionSectionDBOptions ||
- i == kOptionSectionCFOptions) {
- if (title->size() == opt_section_titles[i].size()) {
- // if true, then it indicats equal
- *section = static_cast<OptionSection>(i);
- return CheckSection(*section, *argument, line_num);
- }
- } else if (i == kOptionSectionTableOptions) {
- // This type of sections has a sufffix at the end of the
- // section title
- if (title->size() > opt_section_titles[i].size()) {
- *section = static_cast<OptionSection>(i);
- return CheckSection(*section, *argument, line_num);
- }
- }
- }
- }
- return Status::InvalidArgument(std::string("Unknown section ") + line);
- }
- Status RocksDBOptionsParser::InvalidArgument(const int line_num,
- const std::string& message) {
- return Status::InvalidArgument(
- "[RocksDBOptionsParser Error] ",
- message + " (at line " + std::to_string(line_num) + ")");
- }
- Status RocksDBOptionsParser::ParseStatement(std::string* name,
- std::string* value,
- const std::string& line,
- const int line_num) {
- size_t eq_pos = line.find('=');
- if (eq_pos == std::string::npos) {
- return InvalidArgument(line_num, "A valid statement must have a '='.");
- }
- *name = TrimAndRemoveComment(line.substr(0, eq_pos), true);
- *value =
- TrimAndRemoveComment(line.substr(eq_pos + 1, line.size() - eq_pos - 1));
- if (name->empty()) {
- return InvalidArgument(line_num,
- "A valid statement must have a variable name.");
- }
- return Status::OK();
- }
- Status RocksDBOptionsParser::Parse(const std::string& file_name, FileSystem* fs,
- bool ignore_unknown_options,
- size_t file_readahead_size) {
- ConfigOptions
- config_options; // Use default for escaped(true) and check (exact)
- config_options.ignore_unknown_options = ignore_unknown_options;
- if (file_readahead_size > 0) {
- config_options.file_readahead_size = file_readahead_size;
- }
- return Parse(config_options, file_name, fs);
- }
- Status RocksDBOptionsParser::Parse(const ConfigOptions& config_options_in,
- const std::string& file_name,
- FileSystem* fs) {
- Reset();
- ConfigOptions config_options = config_options_in;
- Status s;
- bool retry = false;
- do {
- std::unique_ptr<FSSequentialFile> seq_file;
- s = fs->NewSequentialFile(file_name, FileOptions(), &seq_file, nullptr);
- if (!s.ok()) {
- return s;
- }
- LineFileReader lf_reader(
- std::move(seq_file), file_name, config_options.file_readahead_size,
- nullptr, std::vector<std::shared_ptr<EventListener>>{}, nullptr, retry);
- OptionSection section = kOptionSectionUnknown;
- std::string title;
- std::string argument;
- std::unordered_map<std::string, std::string> opt_map;
- std::string line;
- // we only support single-lined statement.
- while (
- lf_reader.ReadLine(&line, Env::IO_TOTAL /* rate_limiter_priority */)) {
- int line_num = static_cast<int>(lf_reader.GetLineNumber());
- line = TrimAndRemoveComment(line);
- if (line.empty()) {
- continue;
- }
- if (IsSection(line)) {
- s = EndSection(config_options, section, title, argument, opt_map);
- opt_map.clear();
- if (!s.ok()) {
- break;
- }
- // If the option file is not generated by a higher version, unknown
- // option should only mean corruption.
- if (config_options.ignore_unknown_options &&
- section == kOptionSectionVersion) {
- using VTuple = std::tuple<int, int, int>;
- if (VTuple(db_version[0], db_version[1], db_version[2]) <=
- VTuple(ROCKSDB_MAJOR, ROCKSDB_MINOR, ROCKSDB_PATCH)) {
- config_options.ignore_unknown_options = false;
- }
- }
- s = ParseSection(§ion, &title, &argument, line, line_num);
- if (!s.ok()) {
- break;
- }
- } else {
- std::string name;
- std::string value;
- s = ParseStatement(&name, &value, line, line_num);
- if (!s.ok()) {
- break;
- }
- opt_map.insert({name, value});
- }
- }
- if (s.ok()) {
- s = lf_reader.GetStatus();
- }
- if (s.ok()) {
- s = EndSection(config_options, section, title, argument, opt_map);
- opt_map.clear();
- }
- if (s.ok()) {
- s = ValidityCheck();
- }
- if (!s.ok()) {
- if ((s.IsCorruption() || s.IsInvalidArgument()) && !retry &&
- CheckFSFeatureSupport(fs,
- FSSupportedOps::kVerifyAndReconstructRead)) {
- retry = true;
- Reset();
- } else {
- return s;
- }
- } else {
- return s;
- }
- } while (retry);
- return s;
- }
- Status RocksDBOptionsParser::CheckSection(const OptionSection section,
- const std::string& section_arg,
- const int line_num) {
- if (section == kOptionSectionDBOptions) {
- if (has_db_options_) {
- return InvalidArgument(
- line_num,
- "More than one DBOption section found in the option config file");
- }
- has_db_options_ = true;
- } else if (section == kOptionSectionCFOptions) {
- bool is_default_cf = (section_arg == kDefaultColumnFamilyName);
- if (cf_opts_.size() == 0 && !is_default_cf) {
- return InvalidArgument(
- line_num,
- "Default column family must be the first CFOptions section "
- "in the option config file");
- } else if (cf_opts_.size() != 0 && is_default_cf) {
- return InvalidArgument(
- line_num,
- "Default column family must be the first CFOptions section "
- "in the optio/n config file");
- } else if (GetCFOptions(section_arg) != nullptr) {
- return InvalidArgument(
- line_num,
- "Two identical column families found in option config file");
- }
- has_default_cf_options_ |= is_default_cf;
- } else if (section == kOptionSectionTableOptions) {
- if (GetCFOptions(section_arg) == nullptr) {
- return InvalidArgument(
- line_num, std::string("Does not find a matched column family name in "
- "TableOptions section. Column Family Name:") +
- section_arg);
- }
- } else if (section == kOptionSectionVersion) {
- if (has_version_section_) {
- return InvalidArgument(
- line_num,
- "More than one Version section found in the option config file.");
- }
- has_version_section_ = true;
- }
- return Status::OK();
- }
- Status RocksDBOptionsParser::ParseVersionNumber(const std::string& ver_name,
- const std::string& ver_string,
- const int max_count,
- int* version) {
- int version_index = 0;
- int current_number = 0;
- int current_digit_count = 0;
- bool has_dot = false;
- for (int i = 0; i < max_count; ++i) {
- version[i] = 0;
- }
- constexpr int kBufferSize = 200;
- char buffer[kBufferSize];
- for (size_t i = 0; i < ver_string.size(); ++i) {
- if (ver_string[i] == '.') {
- if (version_index >= max_count - 1) {
- snprintf(buffer, sizeof(buffer) - 1,
- "A valid %s can only contains at most %d dots.",
- ver_name.c_str(), max_count - 1);
- return Status::InvalidArgument(buffer);
- }
- if (current_digit_count == 0) {
- snprintf(buffer, sizeof(buffer) - 1,
- "A valid %s must have at least one digit before each dot.",
- ver_name.c_str());
- return Status::InvalidArgument(buffer);
- }
- version[version_index++] = current_number;
- current_number = 0;
- current_digit_count = 0;
- has_dot = true;
- } else if (isdigit(ver_string[i])) {
- current_number = current_number * 10 + (ver_string[i] - '0');
- current_digit_count++;
- } else {
- snprintf(buffer, sizeof(buffer) - 1,
- "A valid %s can only contains dots and numbers.",
- ver_name.c_str());
- return Status::InvalidArgument(buffer);
- }
- }
- version[version_index] = current_number;
- if (has_dot && current_digit_count == 0) {
- snprintf(buffer, sizeof(buffer) - 1,
- "A valid %s must have at least one digit after each dot.",
- ver_name.c_str());
- return Status::InvalidArgument(buffer);
- }
- return Status::OK();
- }
- Status RocksDBOptionsParser::EndSection(
- const ConfigOptions& config_options, const OptionSection section,
- const std::string& section_title, const std::string& section_arg,
- const std::unordered_map<std::string, std::string>& opt_map) {
- Status s;
- if (section == kOptionSectionDBOptions) {
- s = GetDBOptionsFromMap(config_options, DBOptions(), opt_map, &db_opt_);
- if (!s.ok()) {
- return s;
- }
- db_opt_map_ = opt_map;
- } else if (section == kOptionSectionCFOptions) {
- // This condition should be ensured earlier in ParseSection
- // so we make an assertion here.
- assert(GetCFOptions(section_arg) == nullptr);
- cf_names_.emplace_back(section_arg);
- cf_opts_.emplace_back();
- s = GetColumnFamilyOptionsFromMap(config_options, ColumnFamilyOptions(),
- opt_map, &cf_opts_.back());
- if (!s.ok()) {
- return s;
- }
- // keep the parsed string.
- cf_opt_maps_.emplace_back(opt_map);
- } else if (section == kOptionSectionTableOptions) {
- assert(GetCFOptions(section_arg) != nullptr);
- auto* cf_opt = GetCFOptionsImpl(section_arg);
- if (cf_opt == nullptr) {
- return Status::InvalidArgument(
- "The specified column family must be defined before the "
- "TableOptions section:",
- section_arg);
- }
- // Ignore error as table factory deserialization is optional
- cf_opt->table_factory.reset();
- s = TableFactory::CreateFromString(
- config_options,
- section_title.substr(
- opt_section_titles[kOptionSectionTableOptions].size()),
- &(cf_opt->table_factory));
- if (s.ok() && cf_opt->table_factory != nullptr) {
- s = cf_opt->table_factory->ConfigureFromMap(config_options, opt_map);
- // Translate any errors (NotFound, NotSupported, to InvalidArgument
- if (s.ok() || s.IsInvalidArgument()) {
- return s;
- } else {
- return Status::InvalidArgument(s.getState());
- }
- } else {
- // Return OK for not supported table factories as TableFactory
- // Deserialization is optional.
- cf_opt->table_factory.reset();
- return Status::OK();
- }
- } else if (section == kOptionSectionVersion) {
- for (const auto& pair : opt_map) {
- if (pair.first == "rocksdb_version") {
- s = ParseVersionNumber(pair.first, pair.second, 3, db_version);
- if (!s.ok()) {
- return s;
- }
- } else if (pair.first == "options_file_version") {
- s = ParseVersionNumber(pair.first, pair.second, 2, opt_file_version);
- if (!s.ok()) {
- return s;
- }
- if (opt_file_version[0] < 1) {
- return Status::InvalidArgument(
- "A valid options_file_version must be at least 1.");
- }
- }
- }
- }
- return s;
- }
- Status RocksDBOptionsParser::ValidityCheck() {
- if (!has_db_options_) {
- return Status::Corruption(
- "A RocksDB Option file must have a single DBOptions section");
- }
- if (!has_default_cf_options_) {
- return Status::Corruption(
- "A RocksDB Option file must have a single CFOptions:default section");
- }
- return Status::OK();
- }
- std::string RocksDBOptionsParser::TrimAndRemoveComment(const std::string& line,
- bool trim_only) {
- size_t start = 0;
- size_t end = line.size();
- // we only support "#" style comment
- if (!trim_only) {
- size_t search_pos = 0;
- while (search_pos < line.size()) {
- size_t comment_pos = line.find('#', search_pos);
- if (comment_pos == std::string::npos) {
- break;
- }
- if (comment_pos == 0 || line[comment_pos - 1] != '\\') {
- end = comment_pos;
- break;
- }
- search_pos = comment_pos + 1;
- }
- }
- while (start < end && isspace(line[start]) != 0) {
- ++start;
- }
- // start < end implies end > 0.
- while (start < end && isspace(line[end - 1]) != 0) {
- --end;
- }
- if (start < end) {
- return line.substr(start, end - start);
- }
- return "";
- }
- Status RocksDBOptionsParser::VerifyRocksDBOptionsFromFile(
- const ConfigOptions& config_options_in, const DBOptions& db_opt,
- const std::vector<std::string>& cf_names,
- const std::vector<ColumnFamilyOptions>& cf_opts,
- const std::string& file_name, FileSystem* fs) {
- RocksDBOptionsParser parser;
- 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;
- }
- // Verify DBOptions
- s = VerifyDBOptions(config_options, db_opt, *parser.db_opt(),
- parser.db_opt_map());
- if (!s.ok()) {
- return s;
- }
- // Verify ColumnFamily Name
- if (cf_names.size() != parser.cf_names()->size()) {
- if (config_options.sanity_level >=
- ConfigOptions::kSanityLevelLooselyCompatible) {
- return Status::InvalidArgument(
- "[RocksDBOptionParser Error] The persisted options does not have "
- "the same number of column family names as the db instance.");
- } else if (cf_opts.size() > parser.cf_opts()->size()) {
- return Status::InvalidArgument(
- "[RocksDBOptionsParser Error]",
- "The persisted options file has less number of column family "
- "names than that of the specified one.");
- }
- }
- for (size_t i = 0; i < cf_names.size(); ++i) {
- if (cf_names[i] != parser.cf_names()->at(i)) {
- return Status::InvalidArgument(
- "[RocksDBOptionParser Error] The persisted options and the db"
- "instance does not have the same name for column family ",
- std::to_string(i));
- }
- }
- // Verify Column Family Options
- if (cf_opts.size() != parser.cf_opts()->size()) {
- if (config_options.sanity_level >=
- ConfigOptions::kSanityLevelLooselyCompatible) {
- return Status::InvalidArgument(
- "[RocksDBOptionsParser Error]",
- "The persisted options does not have the same number of "
- "column families as the db instance.");
- } else if (cf_opts.size() > parser.cf_opts()->size()) {
- return Status::InvalidArgument(
- "[RocksDBOptionsParser Error]",
- "The persisted options file has less number of column families "
- "than that of the specified number.");
- }
- }
- for (size_t i = 0; i < cf_opts.size(); ++i) {
- s = VerifyCFOptions(config_options, cf_opts[i], parser.cf_opts()->at(i),
- &(parser.cf_opt_maps()->at(i)));
- if (!s.ok()) {
- return s;
- }
- s = VerifyTableFactory(config_options, cf_opts[i].table_factory.get(),
- parser.cf_opts()->at(i).table_factory.get());
- if (!s.ok()) {
- return s;
- }
- }
- return Status::OK();
- }
- 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, opt_map);
- auto file_config = DBOptionsAsConfigurable(file_opt, opt_map);
- std::string mismatch;
- if (!base_config->AreEquivalent(config_options, file_config.get(),
- &mismatch)) {
- const size_t kBufferSize = 2048;
- char buffer[kBufferSize];
- std::string base_value;
- std::string file_value;
- int offset = snprintf(buffer, sizeof(buffer),
- "[RocksDBOptionsParser]: "
- "failed the verification on DBOptions::%s -- ",
- mismatch.c_str());
- Status s = base_config->GetOption(config_options, mismatch, &base_value);
- if (s.ok()) {
- s = file_config->GetOption(config_options, mismatch, &file_value);
- }
- assert(offset >= 0);
- assert(static_cast<size_t>(offset) < sizeof(buffer));
- if (s.ok()) {
- snprintf(buffer + offset, sizeof(buffer) - static_cast<size_t>(offset),
- "-- The specified one is %s while the persisted one is %s.\n",
- base_value.c_str(), file_value.c_str());
- } else {
- snprintf(buffer + offset, sizeof(buffer) - static_cast<size_t>(offset),
- "-- Unable to re-serialize an option: %s.\n",
- s.ToString().c_str());
- }
- return Status::InvalidArgument(Slice(buffer, strlen(buffer)));
- }
- return Status::OK();
- }
- Status RocksDBOptionsParser::VerifyCFOptions(
- const ConfigOptions& config_options, const ColumnFamilyOptions& base_opt,
- const ColumnFamilyOptions& file_opt,
- const std::unordered_map<std::string, std::string>* opt_map) {
- auto base_config = CFOptionsAsConfigurable(base_opt, opt_map);
- auto file_config = CFOptionsAsConfigurable(file_opt, opt_map);
- std::string mismatch;
- if (!base_config->AreEquivalent(config_options, file_config.get(),
- &mismatch)) {
- std::string base_value;
- std::string file_value;
- // The options do not match
- const size_t kBufferSize = 2048;
- char buffer[kBufferSize];
- Status s = base_config->GetOption(config_options, mismatch, &base_value);
- if (s.ok()) {
- s = file_config->GetOption(config_options, mismatch, &file_value);
- // In file_opt, certain options like MergeOperator may be nullptr due to
- // factor methods not available. So we use opt_map to get
- // option value to use in the error message below.
- if (s.ok() && file_value == kNullptrString && opt_map) {
- auto const& opt_val_str = (opt_map->find(mismatch));
- if (opt_val_str != opt_map->end()) {
- file_value = opt_val_str->second;
- }
- }
- }
- int offset = snprintf(buffer, sizeof(buffer),
- "[RocksDBOptionsParser]: "
- "failed the verification on ColumnFamilyOptions::%s",
- mismatch.c_str());
- assert(offset >= 0);
- assert(static_cast<size_t>(offset) < sizeof(buffer));
- if (s.ok()) {
- snprintf(buffer + offset, sizeof(buffer) - static_cast<size_t>(offset),
- "--- The specified one is %s while the persisted one is %s.\n",
- base_value.c_str(), file_value.c_str());
- } else {
- snprintf(buffer + offset, sizeof(buffer) - static_cast<size_t>(offset),
- "--- Unable to re-serialize an option: %s.\n",
- s.ToString().c_str());
- }
- return Status::InvalidArgument(Slice(buffer, sizeof(buffer)));
- } // For each option
- return Status::OK();
- }
- Status RocksDBOptionsParser::VerifyTableFactory(
- const ConfigOptions& config_options, const TableFactory* base_tf,
- const TableFactory* file_tf) {
- std::string mismatch;
- if (base_tf && file_tf) {
- if (config_options.sanity_level > ConfigOptions::kSanityLevelNone &&
- std::string(base_tf->Name()) != std::string(file_tf->Name())) {
- return Status::Corruption(
- "[RocksDBOptionsParser]: "
- "failed the verification on TableFactory->Name()");
- } else if (!base_tf->AreEquivalent(config_options, file_tf, &mismatch)) {
- return Status::Corruption(std::string("[RocksDBOptionsParser]:"
- "failed the verification on ") +
- base_tf->Name() + "::",
- mismatch);
- }
- } else {
- // TODO(yhchiang): further support sanity check here
- }
- return Status::OK();
- }
- } // namespace ROCKSDB_NAMESPACE
|