Summary: This patch adds OptionsUtil::LoadOptionsFromFile() and OptionsUtil::LoadLatestOptionsFromDB(), which allow developers to construct DBOptions and ColumnFamilyOptions from a RocksDB options file. Note that most pointer-typed options such as merge_operator will not be constructed. With this API, developers no longer need to remember all the options in order to reopen an existing rocksdb instance like the following: DBOptions db_options; std::vector<std::string> cf_names; std::vector<ColumnFamilyOptions> cf_opts; // Load primitive-typed options from an existing DB OptionsUtil::LoadLatestOptionsFromDB( dbname, &db_options, &cf_names, &cf_opts); // Initialize necessary pointer-typed options cf_opts[0].merge_operator.reset(new MyMergeOperator()); ... // Construct the vector of ColumnFamilyDescriptor std::vector<ColumnFamilyDescriptor> cf_descs; for (size_t i = 0; i < cf_opts.size(); ++i) { cf_descs.emplace_back(cf_names[i], cf_opts[i]); } // Open the DB DB* db = nullptr; std::vector<ColumnFamilyHandle*> cf_handles; auto s = DB::Open(db_options, dbname, cf_descs, &handles, &db); Test Plan: Augment existing tests in column_family_test options_test db_test Reviewers: igor, IslamAbdelRahman, sdong, anthony Reviewed By: anthony Subscribers: dhruba, leveldb Differential Revision: https://reviews.facebook.net/D49095main
parent
e78389b554
commit
e11f676e34
@ -0,0 +1,113 @@ |
|||||||
|
// Copyright (c) 2013, Facebook, Inc. All rights reserved.
|
||||||
|
// This source code is licensed under the BSD-style license found in the
|
||||||
|
// LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
// of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
//
|
||||||
|
// This file demonstrates how to use the utility functions defined in
|
||||||
|
// rocksdb/utilities/options_util.h to open a rocksdb database without
|
||||||
|
// remembering all the rocksdb options.
|
||||||
|
#include <cstdio> |
||||||
|
#include <string> |
||||||
|
#include <vector> |
||||||
|
|
||||||
|
#include "rocksdb/cache.h" |
||||||
|
#include "rocksdb/compaction_filter.h" |
||||||
|
#include "rocksdb/db.h" |
||||||
|
#include "rocksdb/options.h" |
||||||
|
#include "rocksdb/slice.h" |
||||||
|
#include "rocksdb/table.h" |
||||||
|
#include "rocksdb/utilities/options_util.h" |
||||||
|
|
||||||
|
using namespace rocksdb; |
||||||
|
|
||||||
|
std::string kDBPath = "/tmp/rocksdb_options_file_example"; |
||||||
|
|
||||||
|
namespace { |
||||||
|
// A dummy compaction filter
|
||||||
|
class DummyCompactionFilter : public CompactionFilter { |
||||||
|
public: |
||||||
|
virtual ~DummyCompactionFilter() {} |
||||||
|
virtual bool Filter(int level, const Slice& key, const Slice& existing_value, |
||||||
|
std::string* new_value, bool* value_changed) const { |
||||||
|
return false; |
||||||
|
} |
||||||
|
virtual const char* Name() const { return "DummyCompactionFilter"; } |
||||||
|
}; |
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int main() { |
||||||
|
DBOptions db_opt; |
||||||
|
db_opt.create_if_missing = true; |
||||||
|
|
||||||
|
std::vector<ColumnFamilyDescriptor> cf_descs; |
||||||
|
cf_descs.push_back({kDefaultColumnFamilyName, ColumnFamilyOptions()}); |
||||||
|
cf_descs.push_back({"new_cf", ColumnFamilyOptions()}); |
||||||
|
|
||||||
|
// initialize BlockBasedTableOptions
|
||||||
|
auto cache = NewLRUCache(1 * 1024 * 1024 * 1024); |
||||||
|
BlockBasedTableOptions bbt_opts; |
||||||
|
bbt_opts.block_size = 32 * 1024; |
||||||
|
bbt_opts.block_cache = cache; |
||||||
|
|
||||||
|
// initialize column families options
|
||||||
|
std::unique_ptr<CompactionFilter> compaction_filter; |
||||||
|
compaction_filter.reset(new DummyCompactionFilter()); |
||||||
|
cf_descs[0].options.table_factory.reset(NewBlockBasedTableFactory(bbt_opts)); |
||||||
|
cf_descs[0].options.compaction_filter = compaction_filter.get(); |
||||||
|
cf_descs[1].options.table_factory.reset(NewBlockBasedTableFactory(bbt_opts)); |
||||||
|
|
||||||
|
// destroy and open DB
|
||||||
|
DB* db; |
||||||
|
Status s = DestroyDB(kDBPath, Options(db_opt, cf_descs[0].options)); |
||||||
|
assert(s.ok()); |
||||||
|
s = DB::Open(Options(db_opt, cf_descs[0].options), kDBPath, &db); |
||||||
|
assert(s.ok()); |
||||||
|
|
||||||
|
// Create column family, and rocksdb will persist the options.
|
||||||
|
ColumnFamilyHandle* cf; |
||||||
|
s = db->CreateColumnFamily(ColumnFamilyOptions(), "new_cf", &cf); |
||||||
|
assert(s.ok()); |
||||||
|
|
||||||
|
// close DB
|
||||||
|
delete cf; |
||||||
|
delete db; |
||||||
|
|
||||||
|
// In the following code, we will reopen the rocksdb instance using
|
||||||
|
// the options file stored in the db directory.
|
||||||
|
|
||||||
|
// Load the options file.
|
||||||
|
DBOptions loaded_db_opt; |
||||||
|
std::vector<ColumnFamilyDescriptor> loaded_cf_descs; |
||||||
|
s = LoadLatestOptions(kDBPath, Env::Default(), &loaded_db_opt, |
||||||
|
&loaded_cf_descs); |
||||||
|
assert(s.ok()); |
||||||
|
assert(loaded_db_opt.create_if_missing == db_opt.create_if_missing); |
||||||
|
|
||||||
|
// Initialize pointer options for each column family
|
||||||
|
for (size_t i = 0; i < loaded_cf_descs.size(); ++i) { |
||||||
|
auto* loaded_bbt_opt = reinterpret_cast<BlockBasedTableOptions*>( |
||||||
|
loaded_cf_descs[0].options.table_factory->GetOptions()); |
||||||
|
// Expect the same as BlockBasedTableOptions will be loaded form file.
|
||||||
|
assert(loaded_bbt_opt->block_size == bbt_opts.block_size); |
||||||
|
// However, block_cache needs to be manually initialized as documented
|
||||||
|
// in rocksdb/utilities/options_util.h.
|
||||||
|
loaded_bbt_opt->block_cache = cache; |
||||||
|
} |
||||||
|
// In addition, as pointer options are initialized with default value,
|
||||||
|
// we need to properly initialized all the pointer options if non-defalut
|
||||||
|
// values are used before calling DB::Open().
|
||||||
|
assert(loaded_cf_descs[0].options.compaction_filter == nullptr); |
||||||
|
loaded_cf_descs[0].options.compaction_filter = compaction_filter.get(); |
||||||
|
|
||||||
|
// reopen the db using the loaded options.
|
||||||
|
std::vector<ColumnFamilyHandle*> handles; |
||||||
|
s = DB::Open(loaded_db_opt, kDBPath, loaded_cf_descs, &handles, &db); |
||||||
|
assert(s.ok()); |
||||||
|
|
||||||
|
// close DB
|
||||||
|
for (auto* handle : handles) { |
||||||
|
delete handle; |
||||||
|
} |
||||||
|
delete db; |
||||||
|
} |
@ -0,0 +1,65 @@ |
|||||||
|
// Copyright (c) 2015, Facebook, Inc. All rights reserved.
|
||||||
|
// This source code is licensed under the BSD-style license found in the
|
||||||
|
// LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
// of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
|
||||||
|
// This file contains utility functions for RocksDB Options.
|
||||||
|
#pragma once |
||||||
|
|
||||||
|
#ifndef ROCKSDB_LITE |
||||||
|
|
||||||
|
#include <string> |
||||||
|
#include <vector> |
||||||
|
|
||||||
|
#include "rocksdb/db.h" |
||||||
|
#include "rocksdb/env.h" |
||||||
|
#include "rocksdb/options.h" |
||||||
|
#include "rocksdb/status.h" |
||||||
|
|
||||||
|
namespace rocksdb { |
||||||
|
// Constructs the DBOptions and ColumnFamilyDescriptors by loading the
|
||||||
|
// latest RocksDB options file stored in the specified rocksdb database.
|
||||||
|
//
|
||||||
|
// Note that the all the pointer options (except table_factory, which will
|
||||||
|
// be described in more details below) will be initialized with the default
|
||||||
|
// values. Developers can further initialize them after this function call.
|
||||||
|
// Below is an example list of pointer options which will be initialized
|
||||||
|
//
|
||||||
|
// * env
|
||||||
|
// * memtable_factory
|
||||||
|
// * compaction_filter_factory
|
||||||
|
// * prefix_extractor
|
||||||
|
// * comparator
|
||||||
|
// * merge_operator
|
||||||
|
// * compaction_filter
|
||||||
|
//
|
||||||
|
// For table_factory, this function further supports deserializing
|
||||||
|
// BlockBasedTableFactory and its BlockBasedTableOptions except the
|
||||||
|
// pointer options of BlockBasedTableOptions (flush_block_policy_factory,
|
||||||
|
// block_cache, and block_cache_compressed), which will be initialized with
|
||||||
|
// default values. Developers can further specify these three options by
|
||||||
|
// casting the return value of TableFactoroy::GetOptions() to
|
||||||
|
// BlockBasedTableOptions and making necessary changes.
|
||||||
|
//
|
||||||
|
// examples/options_file_example.cc demonstrates how to use this function
|
||||||
|
// to open a RocksDB instance.
|
||||||
|
//
|
||||||
|
// @see LoadOptionsFromFile
|
||||||
|
Status LoadLatestOptions(const std::string& dbpath, Env* env, |
||||||
|
DBOptions* db_options, |
||||||
|
std::vector<ColumnFamilyDescriptor>* cf_descs); |
||||||
|
|
||||||
|
// Similar to LoadLatestOptions, this function constructs the DBOptions
|
||||||
|
// and ColumnFamilyDescriptors based on the specified RocksDB Options file.
|
||||||
|
//
|
||||||
|
// @see LoadLatestOptions
|
||||||
|
Status LoadOptionsFromFile(const std::string& options_file_name, Env* env, |
||||||
|
DBOptions* db_options, |
||||||
|
std::vector<ColumnFamilyDescriptor>* cf_descs); |
||||||
|
|
||||||
|
// Returns the latest options file name under the specified db path.
|
||||||
|
Status GetLatestOptionsFileName(const std::string& dbpath, Env* env, |
||||||
|
std::string* options_file_name); |
||||||
|
|
||||||
|
} // namespace rocksdb
|
||||||
|
#endif // !ROCKSDB_LITE
|
@ -0,0 +1,76 @@ |
|||||||
|
// Copyright (c) 2014, Facebook, Inc. All rights reserved.
|
||||||
|
// This source code is licensed under the BSD-style license found in the
|
||||||
|
// LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
// of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
|
||||||
|
#ifndef ROCKSDB_LITE |
||||||
|
|
||||||
|
#include "rocksdb/utilities/options_util.h" |
||||||
|
|
||||||
|
#include "db/filename.h" |
||||||
|
#include "rocksdb/options.h" |
||||||
|
#include "util/options_parser.h" |
||||||
|
|
||||||
|
namespace rocksdb { |
||||||
|
Status LoadOptionsFromFile(const std::string& file_name, Env* env, |
||||||
|
DBOptions* db_options, |
||||||
|
std::vector<ColumnFamilyDescriptor>* cf_descs) { |
||||||
|
RocksDBOptionsParser parser; |
||||||
|
Status s = parser.Parse(file_name, env); |
||||||
|
if (!s.ok()) { |
||||||
|
return s; |
||||||
|
} |
||||||
|
|
||||||
|
*db_options = *parser.db_opt(); |
||||||
|
|
||||||
|
const std::vector<std::string>& cf_names = *parser.cf_names(); |
||||||
|
const std::vector<ColumnFamilyOptions>& cf_opts = *parser.cf_opts(); |
||||||
|
cf_descs->clear(); |
||||||
|
for (size_t i = 0; i < cf_opts.size(); ++i) { |
||||||
|
cf_descs->push_back({cf_names[i], cf_opts[i]}); |
||||||
|
} |
||||||
|
return Status::OK(); |
||||||
|
} |
||||||
|
|
||||||
|
Status GetLatestOptionsFileName(const std::string& dbpath, |
||||||
|
Env* env, std::string* options_file_name) { |
||||||
|
Status s; |
||||||
|
std::string latest_file_name; |
||||||
|
uint64_t latest_time_stamp = 0; |
||||||
|
std::vector<std::string> file_names; |
||||||
|
s = env->GetChildren(dbpath, &file_names); |
||||||
|
if (!s.ok()) { |
||||||
|
return s; |
||||||
|
} |
||||||
|
for (auto& file_name : file_names) { |
||||||
|
uint64_t time_stamp; |
||||||
|
FileType type; |
||||||
|
if (ParseFileName(file_name, &time_stamp, &type) && type == kOptionsFile) { |
||||||
|
if (time_stamp > latest_time_stamp) { |
||||||
|
latest_time_stamp = time_stamp; |
||||||
|
latest_file_name = file_name; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (latest_file_name.size() == 0) { |
||||||
|
return Status::NotFound("No options files found in the DB directory."); |
||||||
|
} |
||||||
|
*options_file_name = latest_file_name; |
||||||
|
return Status::OK(); |
||||||
|
} |
||||||
|
|
||||||
|
Status LoadLatestOptions(const std::string& dbpath, Env* env, |
||||||
|
DBOptions* db_options, |
||||||
|
std::vector<ColumnFamilyDescriptor>* cf_descs) { |
||||||
|
std::string options_file_name; |
||||||
|
Status s = GetLatestOptionsFileName(dbpath, env, &options_file_name); |
||||||
|
if (!s.ok()) { |
||||||
|
return s; |
||||||
|
} |
||||||
|
|
||||||
|
return LoadOptionsFromFile(dbpath + "/" + options_file_name, env, |
||||||
|
db_options, cf_descs); |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace rocksdb
|
||||||
|
#endif // !ROCKSDB_LITE
|
@ -0,0 +1,102 @@ |
|||||||
|
// Copyright (c) 2013, Facebook, Inc. All rights reserved.
|
||||||
|
// This source code is licensed under the BSD-style license found in the
|
||||||
|
// LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
// of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
|
||||||
|
#ifndef ROCKSDB_LITE |
||||||
|
#ifndef __STDC_FORMAT_MACROS |
||||||
|
#define __STDC_FORMAT_MACROS |
||||||
|
#endif |
||||||
|
|
||||||
|
#include <inttypes.h> |
||||||
|
|
||||||
|
#include <cctype> |
||||||
|
#include <unordered_map> |
||||||
|
|
||||||
|
#include "rocksdb/utilities/options_util.h" |
||||||
|
#include "util/options_parser.h" |
||||||
|
#include "util/random.h" |
||||||
|
#include "util/testharness.h" |
||||||
|
#include "util/testutil.h" |
||||||
|
|
||||||
|
#ifndef GFLAGS |
||||||
|
bool FLAGS_enable_print = false; |
||||||
|
#else |
||||||
|
#include <gflags/gflags.h> |
||||||
|
using GFLAGS::ParseCommandLineFlags; |
||||||
|
DEFINE_bool(enable_print, false, "Print options generated to console."); |
||||||
|
#endif // GFLAGS
|
||||||
|
|
||||||
|
namespace rocksdb { |
||||||
|
class OptionsUtilTest : public testing::Test { |
||||||
|
public: |
||||||
|
OptionsUtilTest() { env_.reset(new test::StringEnv(Env::Default())); } |
||||||
|
|
||||||
|
protected: |
||||||
|
std::unique_ptr<test::StringEnv> env_; |
||||||
|
}; |
||||||
|
|
||||||
|
bool IsBlockBasedTableFactory(TableFactory* tf) { |
||||||
|
return tf->Name() == BlockBasedTableFactory().Name(); |
||||||
|
} |
||||||
|
|
||||||
|
TEST_F(OptionsUtilTest, SaveAndLoad) { |
||||||
|
const size_t kCFCount = 5; |
||||||
|
Random rnd(0xFB); |
||||||
|
|
||||||
|
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(), &rnd); |
||||||
|
} |
||||||
|
|
||||||
|
const std::string kFileName = "OPTIONS-123456"; |
||||||
|
PersistRocksDBOptions(db_opt, cf_names, cf_opts, kFileName, env_.get()); |
||||||
|
|
||||||
|
DBOptions loaded_db_opt; |
||||||
|
std::vector<ColumnFamilyDescriptor> loaded_cf_descs; |
||||||
|
ASSERT_OK(LoadOptionsFromFile(kFileName, env_.get(), &loaded_db_opt, |
||||||
|
&loaded_cf_descs)); |
||||||
|
|
||||||
|
ASSERT_OK(RocksDBOptionsParser::VerifyDBOptions(db_opt, loaded_db_opt)); |
||||||
|
test::RandomInitDBOptions(&db_opt, &rnd); |
||||||
|
ASSERT_NOK(RocksDBOptionsParser::VerifyDBOptions(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( |
||||||
|
cf_opts[i], loaded_cf_descs[i].options)); |
||||||
|
if (IsBlockBasedTableFactory(cf_opts[i].table_factory.get())) { |
||||||
|
ASSERT_OK(RocksDBOptionsParser::VerifyTableFactory( |
||||||
|
cf_opts[i].table_factory.get(), |
||||||
|
loaded_cf_descs[i].options.table_factory.get())); |
||||||
|
} |
||||||
|
test::RandomInitCFOptions(&cf_opts[i], &rnd); |
||||||
|
ASSERT_NOK(RocksDBOptionsParser::VerifyCFOptions( |
||||||
|
cf_opts[i], loaded_cf_descs[i].options)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} // namespace rocksdb
|
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
::testing::InitGoogleTest(&argc, argv); |
||||||
|
#ifdef GFLAGS |
||||||
|
ParseCommandLineFlags(&argc, &argv, true); |
||||||
|
#endif // GFLAGS
|
||||||
|
return RUN_ALL_TESTS(); |
||||||
|
} |
||||||
|
|
||||||
|
#else |
||||||
|
#include <cstdio> |
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
printf("Skipped in RocksDBLite as utilities are not supported.\n"); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
#endif // !ROCKSDB_LITE
|
Loading…
Reference in new issue