Option string/map/file can set env from object registry (#5237)

Summary:
- By providing the "env" field in any text-based options (i.e., string, map, or file), we can use `NewCustomObject` to deserialize the text value into an actual `Env` object.
- Currently factory functions for `Env` registered with object registry should only return pointer to static `Env` objects. That's because `DBOptions::env` is a raw pointer so we cannot easily delegate cleanup.
- Note I did not add `env` to `db_option_type_info`. It wasn't needed for (de)serialization, and I believe we don't want to do verification on `env`, even by checking name. That's because the user should be able to copy their DB from Linux to Windows, change envs, and not see an option verification error.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/5237

Differential Revision: D15056360

Pulled By: siying

fbshipit-source-id: 4b5f0b83297a5058f8949ec955dbf27d98d73d7e
main
Andrew Kryczka 6 years ago committed by Facebook Github Bot
parent 084a3c697c
commit 6eb317bb4c
  1. 5
      HISTORY.md
  2. 5
      include/rocksdb/utilities/options_util.h
  3. 16
      options/options_helper.cc
  4. 3
      options/options_helper.h
  5. 19
      options/options_test.cc

@ -2,12 +2,11 @@
## Unreleased ## Unreleased
### New Features ### New Features
* Add an option `strict_bytes_per_sync` that causes a file-writing thread to block rather than exceed the limit on bytes pending writeback specified by `bytes_per_sync` or `wal_bytes_per_sync`. * Add an option `strict_bytes_per_sync` that causes a file-writing thread to block rather than exceed the limit on bytes pending writeback specified by `bytes_per_sync` or `wal_bytes_per_sync`.
## Unreleased
### New Features
* Improve range scan performance by avoiding per-key upper bound check in BlockBasedTableIterator. * Improve range scan performance by avoiding per-key upper bound check in BlockBasedTableIterator.
* Introduce Periodic Compaction for Level style compaction. Files are re-compacted periodically and put in the same level. * Introduce Periodic Compaction for Level style compaction. Files are re-compacted periodically and put in the same level.
* Block-based table index now contains exact highest key in the file, rather than an upper bound. This may improve Get() and iterator Seek() performance in some situations, especially when direct IO is enabled and block cache is disabled. A setting BlockBasedTableOptions::index_shortening is introduced to control this behavior. Set it to kShortenSeparatorsAndSuccessor to get the old behavior. * Block-based table index now contains exact highest key in the file, rather than an upper bound. This may improve Get() and iterator Seek() performance in some situations, especially when direct IO is enabled and block cache is disabled. A setting BlockBasedTableOptions::index_shortening is introduced to control this behavior. Set it to kShortenSeparatorsAndSuccessor to get the old behavior.
* When reading from option file/string/map, customized envs can be filled according to object registry.
### Public API Change ### Public API Change
* Change the behavior of OptimizeForPointLookup(): move away from hash-based block-based-table index, and use whole key memtable filtering. * Change the behavior of OptimizeForPointLookup(): move away from hash-based block-based-table index, and use whole key memtable filtering.
* Change the behavior of OptimizeForSmallDb(): use a 16MB block cache, put index and filter blocks into it, and cost the memtable size to it. DBOptions.OptimizeForSmallDb() and ColumnFamilyOptions.OptimizeForSmallDb() start to take an optional cache object. * Change the behavior of OptimizeForSmallDb(): use a 16MB block cache, put index and filter blocks into it, and cost the memtable size to it. DBOptions.OptimizeForSmallDb() and ColumnFamilyOptions.OptimizeForSmallDb() start to take an optional cache object.

@ -33,9 +33,10 @@ namespace rocksdb {
// * merge_operator // * merge_operator
// * compaction_filter // * compaction_filter
// //
// User can also choose to load customized comparator and/or merge_operator // User can also choose to load customized comparator, env, and/or
// through object registry: // merge_operator through object registry:
// * comparator needs to be registered through Registrar<const Comparator> // * comparator needs to be registered through Registrar<const Comparator>
// * env needs to be registered through Registrar<Env>
// * merge operator needs to be registered through // * merge operator needs to be registered through
// Registrar<std::shared_ptr<MergeOperator>>. // Registrar<std::shared_ptr<MergeOperator>>.
// //

@ -247,6 +247,7 @@ std::unordered_map<std::string, CompressionType>
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
const std::string kNameComparator = "comparator"; const std::string kNameComparator = "comparator";
const std::string kNameEnv = "env";
const std::string kNameMergeOperator = "merge_operator"; const std::string kNameMergeOperator = "merge_operator";
template <typename T> template <typename T>
@ -1179,6 +1180,14 @@ Status ParseDBOption(const std::string& name,
if (name == "rate_limiter_bytes_per_sec") { if (name == "rate_limiter_bytes_per_sec") {
new_options->rate_limiter.reset( new_options->rate_limiter.reset(
NewGenericRateLimiter(static_cast<int64_t>(ParseUint64(value)))); NewGenericRateLimiter(static_cast<int64_t>(ParseUint64(value))));
} else if (name == kNameEnv) {
// Currently `Env` can be deserialized from object registry only.
std::unique_ptr<Env> env_guard;
Env* env = NewCustomObject<Env>(value, &env_guard);
// Only support static env for now.
if (env != nullptr && !env_guard) {
new_options->env = env;
}
} else { } else {
auto iter = db_options_type_info.find(name); auto iter = db_options_type_info.find(name);
if (iter == db_options_type_info.end()) { if (iter == db_options_type_info.end()) {
@ -1388,7 +1397,6 @@ std::unordered_map<std::string, OptionTypeInfo>
OptionsHelper::db_options_type_info = { OptionsHelper::db_options_type_info = {
/* /*
// not yet supported // not yet supported
Env* env;
std::shared_ptr<Cache> row_cache; std::shared_ptr<Cache> row_cache;
std::shared_ptr<DeleteScheduler> delete_scheduler; std::shared_ptr<DeleteScheduler> delete_scheduler;
std::shared_ptr<Logger> info_log; std::shared_ptr<Logger> info_log;
@ -1553,8 +1561,8 @@ std::unordered_map<std::string, OptionTypeInfo>
OptionVerificationType::kNormal, true, OptionVerificationType::kNormal, true,
offsetof(struct MutableDBOptions, wal_bytes_per_sync)}}, offsetof(struct MutableDBOptions, wal_bytes_per_sync)}},
{"strict_bytes_per_sync", {"strict_bytes_per_sync",
{offsetof(struct DBOptions, strict_bytes_per_sync), OptionType::kBoolean, {offsetof(struct DBOptions, strict_bytes_per_sync),
OptionVerificationType::kNormal, true, OptionType::kBoolean, OptionVerificationType::kNormal, true,
offsetof(struct MutableDBOptions, strict_bytes_per_sync)}}, offsetof(struct MutableDBOptions, strict_bytes_per_sync)}},
{"stats_dump_period_sec", {"stats_dump_period_sec",
{offsetof(struct DBOptions, stats_dump_period_sec), OptionType::kUInt, {offsetof(struct DBOptions, stats_dump_period_sec), OptionType::kUInt,
@ -1639,7 +1647,7 @@ std::unordered_map<std::string, OptionTypeInfo>
{"avoid_unnecessary_blocking_io", {"avoid_unnecessary_blocking_io",
{offsetof(struct DBOptions, avoid_unnecessary_blocking_io), {offsetof(struct DBOptions, avoid_unnecessary_blocking_io),
OptionType::kBoolean, OptionVerificationType::kNormal, false, OptionType::kBoolean, OptionVerificationType::kNormal, false,
offsetof(struct ImmutableDBOptions, avoid_unnecessary_blocking_io)}} offsetof(struct ImmutableDBOptions, avoid_unnecessary_blocking_io)}},
}; };
std::unordered_map<std::string, BlockBasedTableOptions::IndexType> std::unordered_map<std::string, BlockBasedTableOptions::IndexType>

@ -81,7 +81,8 @@ enum class OptionType {
kAccessHint, kAccessHint,
kInfoLogLevel, kInfoLogLevel,
kLRUCacheOptions, kLRUCacheOptions,
kUnknown kEnv,
kUnknown,
}; };
enum class OptionVerificationType { enum class OptionVerificationType {

@ -759,6 +759,21 @@ TEST_F(OptionsTest, GetOptionsFromStringTest) {
block_based_table_options.cache_index_and_filter_blocks = true; block_based_table_options.cache_index_and_filter_blocks = true;
base_options.table_factory.reset( base_options.table_factory.reset(
NewBlockBasedTableFactory(block_based_table_options)); 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) {}
};
static Registrar<Env> test_reg_env(
kCustomEnvName,
[](const std::string& /*name*/, std::unique_ptr<Env>* /*env_guard*/) {
static CustomEnv env(Env::Default());
return &env;
});
ASSERT_OK(GetOptionsFromString( ASSERT_OK(GetOptionsFromString(
base_options, base_options,
"write_buffer_size=10;max_write_buffer_number=16;" "write_buffer_size=10;max_write_buffer_number=16;"
@ -766,7 +781,7 @@ TEST_F(OptionsTest, GetOptionsFromStringTest) {
"compression_opts=4:5:6;create_if_missing=true;max_open_files=1;" "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=" "bottommost_compression_opts=5:6:7;create_if_missing=true;max_open_files="
"1;" "1;"
"rate_limiter_bytes_per_sec=1024", "rate_limiter_bytes_per_sec=1024;env=CustomEnv",
&new_options)); &new_options));
ASSERT_EQ(new_options.compression_opts.window_bits, 4); ASSERT_EQ(new_options.compression_opts.window_bits, 4);
@ -795,6 +810,8 @@ TEST_F(OptionsTest, GetOptionsFromStringTest) {
ASSERT_EQ(new_options.create_if_missing, true); ASSERT_EQ(new_options.create_if_missing, true);
ASSERT_EQ(new_options.max_open_files, 1); ASSERT_EQ(new_options.max_open_files, 1);
ASSERT_TRUE(new_options.rate_limiter.get() != nullptr); ASSERT_TRUE(new_options.rate_limiter.get() != nullptr);
std::unique_ptr<Env> env_guard;
ASSERT_EQ(NewCustomObject<Env>(kCustomEnvName, &env_guard), new_options.env);
} }
TEST_F(OptionsTest, DBOptionsSerialization) { TEST_F(OptionsTest, DBOptionsSerialization) {

Loading…
Cancel
Save