From cd0d581ff5154ea4d99c278599805ee6ed83745d Mon Sep 17 00:00:00 2001 From: Lei Jin Date: Fri, 10 Oct 2014 10:00:12 -0700 Subject: [PATCH] convert Options from string Summary: Allow accepting Options as a string of key/value pairs Test Plan: unit test Reviewers: yhchiang, sdong, igor Reviewed By: igor Subscribers: dhruba, leveldb Differential Revision: https://reviews.facebook.net/D24597 --- HISTORY.md | 6 + include/rocksdb/options.h | 5 - util/options_helper.cc | 101 +++++++++++++- util/options_test.cc | 236 +++++++++++++++++++------------- utilities/options/convenience.h | 40 ++++++ 5 files changed, 285 insertions(+), 103 deletions(-) create mode 100644 utilities/options/convenience.h diff --git a/HISTORY.md b/HISTORY.md index 7451a8dc83..06660a0e8c 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,5 +1,11 @@ # Rocksdb Change Log +## Unreleased + +### Public API changes +* Introduce 4 new convenient functions for converting Options from string: GetColumnFamilyOptionsFromMap(), GetColumnFamilyOptionsFromString(), GetDBOptionsFromMap(), GetDBOptionsFromString() + + ## 3.6.0 (10/7/2014) ### Disk format changes * If you're using RocksDB on ARM platforms and you're using default bloom filter, there is a disk format change you need to be aware of. There are three steps you need to do when you convert to new release: 1. turn off filter policy, 2. compact the whole database, 3. turn on filter policy diff --git a/include/rocksdb/options.h b/include/rocksdb/options.h index 467c7bb1e6..d9a82fd5a5 100644 --- a/include/rocksdb/options.h +++ b/include/rocksdb/options.h @@ -1012,11 +1012,6 @@ extern Options GetOptions(size_t total_write_buffer_limit, int write_amplification_threshold = 32, uint64_t target_db_size = 68719476736 /* 64GB */); -bool GetOptionsFromStrings( - const Options& base_options, - const std::unordered_map& options_map, - Options* new_options); - } // namespace rocksdb #endif // STORAGE_ROCKSDB_INCLUDE_OPTIONS_H_ diff --git a/util/options_helper.cc b/util/options_helper.cc index 2a61c8b69f..67726dc8f0 100644 --- a/util/options_helper.cc +++ b/util/options_helper.cc @@ -4,6 +4,7 @@ // of patent rights can be found in the PATENTS file in the same directory. #include +#include #include #include "rocksdb/options.h" #include "util/options_helper.h" @@ -161,13 +162,61 @@ bool GetMutableOptionsFromStrings( return true; } -bool GetOptionsFromStrings( - const Options& base_options, - const std::unordered_map& options_map, - Options* new_options) { +namespace { + +std::string trim(const std::string& str) { + size_t start = 0; + size_t end = str.size() - 1; + while (isspace(str[start]) != 0 && start <= end) { + ++start; + } + while (isspace(str[end]) != 0 && start <= end) { + --end; + } + if (start <= end) { + return str.substr(start, end - start + 1); + } + return std::string(); +} + +bool StringToMap(const std::string& opts_str, + std::unordered_map* opts_map) { + assert(opts_map); + // Example: + // opts_str = "write_buffer_size=1024;max_write_buffer_number=2" + size_t pos = 0; + + std::string opts = trim(opts_str); + while (pos < opts.size()) { + size_t eq_pos = opts.find('=', pos); + if (eq_pos == std::string::npos) { + return false; + } + std::string key = trim(opts.substr(pos, eq_pos - pos)); + + size_t sc_pos = opts.find(';', eq_pos + 1); + if (sc_pos == std::string::npos) { + (*opts_map)[key] = trim(opts.substr(eq_pos + 1)); + // It either ends with a trailing semi-colon or the last key-value pair + break; + } else { + (*opts_map)[key] = trim(opts.substr(eq_pos + 1, sc_pos - eq_pos - 1)); + } + pos = sc_pos + 1; + } + + return true; +} + +} // anonymous namespace + +bool GetColumnFamilyOptionsFromMap( + const ColumnFamilyOptions& base_options, + const std::unordered_map& opts_map, + ColumnFamilyOptions* new_options) { assert(new_options); *new_options = base_options; - for (const auto& o : options_map) { + for (const auto& o : opts_map) { try { if (ParseMemtableOptions(o.first, o.second, new_options)) { } else if (ParseCompactionOptions(o.first, o.second, new_options)) { @@ -247,7 +296,36 @@ bool GetOptionsFromStrings( new_options->bloom_locality = ParseUint32(o.second); } else if (o.first == "min_partial_merge_operands") { new_options->min_partial_merge_operands = ParseUint32(o.second); - } else if (o.first == "create_if_missing") { + } else { + return false; + } + } catch (std::exception) { + return false; + } + } + return true; +} + +bool GetColumnFamilyOptionsFromString( + const ColumnFamilyOptions& base_options, + const std::string& opts_str, + ColumnFamilyOptions* new_options) { + std::unordered_map opts_map; + if (!StringToMap(opts_str, &opts_map)) { + return false; + } + return GetColumnFamilyOptionsFromMap(base_options, opts_map, new_options); +} + +bool GetDBOptionsFromMap( + const DBOptions& base_options, + const std::unordered_map& opts_map, + DBOptions* new_options) { + assert(new_options); + *new_options = base_options; + for (const auto& o : opts_map) { + try { + if (o.first == "create_if_missing") { new_options->create_if_missing = ParseBoolean(o.first, o.second); } else if (o.first == "create_missing_column_families") { new_options->create_missing_column_families = @@ -325,4 +403,15 @@ bool GetOptionsFromStrings( return true; } +bool GetDBOptionsFromString( + const DBOptions& base_options, + const std::string& opts_str, + DBOptions* new_options) { + std::unordered_map opts_map; + if (!StringToMap(opts_str, &opts_map)) { + return false; + } + return GetDBOptionsFromMap(base_options, opts_map, new_options); +} + } // namespace rocksdb diff --git a/util/options_test.cc b/util/options_test.cc index 1e26c343d4..6f6745aa04 100644 --- a/util/options_test.cc +++ b/util/options_test.cc @@ -17,6 +17,7 @@ #include "rocksdb/options.h" #include "util/testharness.h" +#include "utilities/options/convenience.h" using GFLAGS::ParseCommandLineFlags; DEFINE_bool(enable_print, false, "Print options generated to console."); @@ -77,8 +78,8 @@ TEST(OptionsTest, LooseCondition) { PrintAndGetOptions(128 * 1024 * 1024, 4, 8); } -TEST(OptionsTest, GetOptionsFromStringsTest) { - std::unordered_map options_map = { +TEST(OptionsTest, GetOptionsFromMapTest) { + std::unordered_map cf_options_map = { {"write_buffer_size", "1"}, {"max_write_buffer_number", "2"}, {"min_write_buffer_number_to_merge", "3"}, @@ -120,7 +121,10 @@ TEST(OptionsTest, GetOptionsFromStringsTest) { {"memtable_prefix_bloom_huge_page_tlb_size", "28"}, {"bloom_locality", "29"}, {"max_successive_merges", "30"}, - {"min_partial_merge_operands", "31"}, + {"min_partial_merge_operands", "31"} + }; + + std::unordered_map db_options_map = { {"create_if_missing", "false"}, {"create_missing_column_families", "true"}, {"error_if_exists", "false"}, @@ -154,98 +158,146 @@ TEST(OptionsTest, GetOptionsFromStringsTest) { {"bytes_per_sync", "47"}, }; - Options base_opt; - Options new_opt; - ASSERT_TRUE(GetOptionsFromStrings(base_opt, options_map, &new_opt)); - ASSERT_EQ(new_opt.write_buffer_size, 1U); - ASSERT_EQ(new_opt.max_write_buffer_number, 2); - ASSERT_EQ(new_opt.min_write_buffer_number_to_merge, 3); - ASSERT_EQ(new_opt.compression, kSnappyCompression); - ASSERT_EQ(new_opt.compression_per_level.size(), 6U); - ASSERT_EQ(new_opt.compression_per_level[0], kNoCompression); - ASSERT_EQ(new_opt.compression_per_level[1], kSnappyCompression); - ASSERT_EQ(new_opt.compression_per_level[2], kZlibCompression); - ASSERT_EQ(new_opt.compression_per_level[3], kBZip2Compression); - ASSERT_EQ(new_opt.compression_per_level[4], kLZ4Compression); - ASSERT_EQ(new_opt.compression_per_level[5], kLZ4HCCompression); - ASSERT_EQ(new_opt.compression_opts.window_bits, 4); - ASSERT_EQ(new_opt.compression_opts.level, 5); - ASSERT_EQ(new_opt.compression_opts.strategy, 6); - ASSERT_EQ(new_opt.num_levels, 7); - ASSERT_EQ(new_opt.level0_file_num_compaction_trigger, 8); - ASSERT_EQ(new_opt.level0_slowdown_writes_trigger, 9); - ASSERT_EQ(new_opt.level0_stop_writes_trigger, 10); - ASSERT_EQ(new_opt.max_mem_compaction_level, 11); - ASSERT_EQ(new_opt.target_file_size_base, static_cast(12)); - ASSERT_EQ(new_opt.target_file_size_multiplier, 13); - ASSERT_EQ(new_opt.max_bytes_for_level_base, 14U); - ASSERT_EQ(new_opt.max_bytes_for_level_multiplier, 15); - ASSERT_EQ(new_opt.max_bytes_for_level_multiplier_additional.size(), 3U); - ASSERT_EQ(new_opt.max_bytes_for_level_multiplier_additional[0], 16); - ASSERT_EQ(new_opt.max_bytes_for_level_multiplier_additional[1], 17); - ASSERT_EQ(new_opt.max_bytes_for_level_multiplier_additional[2], 18); - ASSERT_EQ(new_opt.expanded_compaction_factor, 19); - ASSERT_EQ(new_opt.source_compaction_factor, 20); - ASSERT_EQ(new_opt.max_grandparent_overlap_factor, 21); - ASSERT_EQ(new_opt.soft_rate_limit, 1.1); - ASSERT_EQ(new_opt.hard_rate_limit, 2.1); - ASSERT_EQ(new_opt.arena_block_size, 22U); - ASSERT_EQ(new_opt.disable_auto_compactions, true); - ASSERT_EQ(new_opt.purge_redundant_kvs_while_flush, true); - ASSERT_EQ(new_opt.compaction_style, kCompactionStyleLevel); - ASSERT_EQ(new_opt.verify_checksums_in_compaction, false); - ASSERT_EQ(new_opt.compaction_options_fifo.max_table_files_size, + ColumnFamilyOptions base_cf_opt; + ColumnFamilyOptions new_cf_opt; + ASSERT_TRUE(GetColumnFamilyOptionsFromMap( + base_cf_opt, cf_options_map, &new_cf_opt)); + ASSERT_EQ(new_cf_opt.write_buffer_size, 1U); + ASSERT_EQ(new_cf_opt.max_write_buffer_number, 2); + ASSERT_EQ(new_cf_opt.min_write_buffer_number_to_merge, 3); + ASSERT_EQ(new_cf_opt.compression, kSnappyCompression); + ASSERT_EQ(new_cf_opt.compression_per_level.size(), 6U); + ASSERT_EQ(new_cf_opt.compression_per_level[0], kNoCompression); + ASSERT_EQ(new_cf_opt.compression_per_level[1], kSnappyCompression); + ASSERT_EQ(new_cf_opt.compression_per_level[2], kZlibCompression); + ASSERT_EQ(new_cf_opt.compression_per_level[3], kBZip2Compression); + ASSERT_EQ(new_cf_opt.compression_per_level[4], kLZ4Compression); + ASSERT_EQ(new_cf_opt.compression_per_level[5], kLZ4HCCompression); + ASSERT_EQ(new_cf_opt.compression_opts.window_bits, 4); + ASSERT_EQ(new_cf_opt.compression_opts.level, 5); + ASSERT_EQ(new_cf_opt.compression_opts.strategy, 6); + ASSERT_EQ(new_cf_opt.num_levels, 7); + ASSERT_EQ(new_cf_opt.level0_file_num_compaction_trigger, 8); + ASSERT_EQ(new_cf_opt.level0_slowdown_writes_trigger, 9); + ASSERT_EQ(new_cf_opt.level0_stop_writes_trigger, 10); + ASSERT_EQ(new_cf_opt.max_mem_compaction_level, 11); + ASSERT_EQ(new_cf_opt.target_file_size_base, static_cast(12)); + ASSERT_EQ(new_cf_opt.target_file_size_multiplier, 13); + ASSERT_EQ(new_cf_opt.max_bytes_for_level_base, 14U); + ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier, 15); + ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier_additional.size(), 3U); + ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier_additional[0], 16); + ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier_additional[1], 17); + ASSERT_EQ(new_cf_opt.max_bytes_for_level_multiplier_additional[2], 18); + ASSERT_EQ(new_cf_opt.expanded_compaction_factor, 19); + ASSERT_EQ(new_cf_opt.source_compaction_factor, 20); + ASSERT_EQ(new_cf_opt.max_grandparent_overlap_factor, 21); + ASSERT_EQ(new_cf_opt.soft_rate_limit, 1.1); + ASSERT_EQ(new_cf_opt.hard_rate_limit, 2.1); + ASSERT_EQ(new_cf_opt.arena_block_size, 22U); + ASSERT_EQ(new_cf_opt.disable_auto_compactions, true); + ASSERT_EQ(new_cf_opt.purge_redundant_kvs_while_flush, true); + ASSERT_EQ(new_cf_opt.compaction_style, kCompactionStyleLevel); + ASSERT_EQ(new_cf_opt.verify_checksums_in_compaction, false); + ASSERT_EQ(new_cf_opt.compaction_options_fifo.max_table_files_size, static_cast(23)); - ASSERT_EQ(new_opt.filter_deletes, false); - ASSERT_EQ(new_opt.max_sequential_skip_in_iterations, + ASSERT_EQ(new_cf_opt.filter_deletes, false); + ASSERT_EQ(new_cf_opt.max_sequential_skip_in_iterations, static_cast(24)); - ASSERT_EQ(new_opt.inplace_update_support, true); - ASSERT_EQ(new_opt.inplace_update_num_locks, 25U); - ASSERT_EQ(new_opt.memtable_prefix_bloom_bits, 26U); - ASSERT_EQ(new_opt.memtable_prefix_bloom_probes, 27U); - ASSERT_EQ(new_opt.memtable_prefix_bloom_huge_page_tlb_size, 28U); - ASSERT_EQ(new_opt.bloom_locality, 29U); - ASSERT_EQ(new_opt.max_successive_merges, 30U); - ASSERT_EQ(new_opt.min_partial_merge_operands, 31U); - ASSERT_EQ(new_opt.create_if_missing, false); - ASSERT_EQ(new_opt.create_missing_column_families, true); - ASSERT_EQ(new_opt.error_if_exists, false); - ASSERT_EQ(new_opt.paranoid_checks, true); - ASSERT_EQ(new_opt.max_open_files, 32); - ASSERT_EQ(new_opt.max_total_wal_size, static_cast(33)); - ASSERT_EQ(new_opt.disableDataSync, false); - ASSERT_EQ(new_opt.use_fsync, true); - ASSERT_EQ(new_opt.db_log_dir, "/db_log_dir"); - ASSERT_EQ(new_opt.wal_dir, "/wal_dir"); - ASSERT_EQ(new_opt.delete_obsolete_files_period_micros, - static_cast(34)); - ASSERT_EQ(new_opt.max_background_compactions, 35); - ASSERT_EQ(new_opt.max_background_flushes, 36); - ASSERT_EQ(new_opt.max_log_file_size, 37U); - ASSERT_EQ(new_opt.log_file_time_to_roll, 38U); - ASSERT_EQ(new_opt.keep_log_file_num, 39U); - ASSERT_EQ(new_opt.max_manifest_file_size, static_cast(40)); - ASSERT_EQ(new_opt.table_cache_numshardbits, 41); - ASSERT_EQ(new_opt.table_cache_remove_scan_count_limit, 42); - ASSERT_EQ(new_opt.WAL_ttl_seconds, static_cast(43)); - ASSERT_EQ(new_opt.WAL_size_limit_MB, static_cast(44)); - ASSERT_EQ(new_opt.manifest_preallocation_size, 45U); - ASSERT_EQ(new_opt.allow_os_buffer, false); - ASSERT_EQ(new_opt.allow_mmap_reads, true); - ASSERT_EQ(new_opt.allow_mmap_writes, false); - ASSERT_EQ(new_opt.is_fd_close_on_exec, true); - ASSERT_EQ(new_opt.skip_log_error_on_recovery, false); - ASSERT_EQ(new_opt.stats_dump_period_sec, 46U); - ASSERT_EQ(new_opt.advise_random_on_open, true); - ASSERT_EQ(new_opt.use_adaptive_mutex, false); - ASSERT_EQ(new_opt.bytes_per_sync, static_cast(47)); + ASSERT_EQ(new_cf_opt.inplace_update_support, true); + ASSERT_EQ(new_cf_opt.inplace_update_num_locks, 25U); + ASSERT_EQ(new_cf_opt.memtable_prefix_bloom_bits, 26U); + ASSERT_EQ(new_cf_opt.memtable_prefix_bloom_probes, 27U); + ASSERT_EQ(new_cf_opt.memtable_prefix_bloom_huge_page_tlb_size, 28U); + ASSERT_EQ(new_cf_opt.bloom_locality, 29U); + ASSERT_EQ(new_cf_opt.max_successive_merges, 30U); + ASSERT_EQ(new_cf_opt.min_partial_merge_operands, 31U); - options_map["write_buffer_size"] = "hello"; - ASSERT_TRUE(!GetOptionsFromStrings(base_opt, options_map, &new_opt)); - options_map["write_buffer_size"] = "1"; - ASSERT_TRUE(GetOptionsFromStrings(base_opt, options_map, &new_opt)); - options_map["unknown_option"] = "1"; - ASSERT_TRUE(!GetOptionsFromStrings(base_opt, options_map, &new_opt)); + cf_options_map["write_buffer_size"] = "hello"; + ASSERT_TRUE(!GetColumnFamilyOptionsFromMap( + base_cf_opt, cf_options_map, &new_cf_opt)); + cf_options_map["write_buffer_size"] = "1"; + ASSERT_TRUE(GetColumnFamilyOptionsFromMap( + base_cf_opt, cf_options_map, &new_cf_opt)); + cf_options_map["unknown_option"] = "1"; + ASSERT_TRUE(!GetColumnFamilyOptionsFromMap( + base_cf_opt, cf_options_map, &new_cf_opt)); + + DBOptions base_db_opt; + DBOptions new_db_opt; + ASSERT_TRUE(GetDBOptionsFromMap(base_db_opt, db_options_map, &new_db_opt)); + ASSERT_EQ(new_db_opt.create_if_missing, false); + ASSERT_EQ(new_db_opt.create_missing_column_families, true); + ASSERT_EQ(new_db_opt.error_if_exists, false); + ASSERT_EQ(new_db_opt.paranoid_checks, true); + ASSERT_EQ(new_db_opt.max_open_files, 32); + ASSERT_EQ(new_db_opt.max_total_wal_size, static_cast(33)); + ASSERT_EQ(new_db_opt.disableDataSync, false); + ASSERT_EQ(new_db_opt.use_fsync, true); + ASSERT_EQ(new_db_opt.db_log_dir, "/db_log_dir"); + ASSERT_EQ(new_db_opt.wal_dir, "/wal_dir"); + ASSERT_EQ(new_db_opt.delete_obsolete_files_period_micros, + static_cast(34)); + ASSERT_EQ(new_db_opt.max_background_compactions, 35); + ASSERT_EQ(new_db_opt.max_background_flushes, 36); + ASSERT_EQ(new_db_opt.max_log_file_size, 37U); + ASSERT_EQ(new_db_opt.log_file_time_to_roll, 38U); + ASSERT_EQ(new_db_opt.keep_log_file_num, 39U); + ASSERT_EQ(new_db_opt.max_manifest_file_size, static_cast(40)); + ASSERT_EQ(new_db_opt.table_cache_numshardbits, 41); + ASSERT_EQ(new_db_opt.table_cache_remove_scan_count_limit, 42); + ASSERT_EQ(new_db_opt.WAL_ttl_seconds, static_cast(43)); + ASSERT_EQ(new_db_opt.WAL_size_limit_MB, static_cast(44)); + ASSERT_EQ(new_db_opt.manifest_preallocation_size, 45U); + ASSERT_EQ(new_db_opt.allow_os_buffer, false); + ASSERT_EQ(new_db_opt.allow_mmap_reads, true); + ASSERT_EQ(new_db_opt.allow_mmap_writes, false); + ASSERT_EQ(new_db_opt.is_fd_close_on_exec, true); + ASSERT_EQ(new_db_opt.skip_log_error_on_recovery, false); + ASSERT_EQ(new_db_opt.stats_dump_period_sec, 46U); + ASSERT_EQ(new_db_opt.advise_random_on_open, true); + ASSERT_EQ(new_db_opt.use_adaptive_mutex, false); + ASSERT_EQ(new_db_opt.bytes_per_sync, static_cast(47)); +} + +TEST(OptionsTest, GetOptionsFromStringTest) { + ColumnFamilyOptions base_cf_opt; + ColumnFamilyOptions new_cf_opt; + ASSERT_TRUE(GetColumnFamilyOptionsFromString(base_cf_opt, "", &new_cf_opt)); + ASSERT_TRUE(GetColumnFamilyOptionsFromString(base_cf_opt, + "write_buffer_size=5", &new_cf_opt)); + ASSERT_EQ(new_cf_opt.write_buffer_size, 5); + ASSERT_TRUE(GetColumnFamilyOptionsFromString(base_cf_opt, + "write_buffer_size=6;", &new_cf_opt)); + ASSERT_EQ(new_cf_opt.write_buffer_size, 6); + ASSERT_TRUE(GetColumnFamilyOptionsFromString(base_cf_opt, + " write_buffer_size = 7 ", &new_cf_opt)); + ASSERT_EQ(new_cf_opt.write_buffer_size, 7); + ASSERT_TRUE(GetColumnFamilyOptionsFromString(base_cf_opt, + " write_buffer_size = 8 ; ", &new_cf_opt)); + ASSERT_EQ(new_cf_opt.write_buffer_size, 8); + ASSERT_TRUE(GetColumnFamilyOptionsFromString(base_cf_opt, + "write_buffer_size=9;max_write_buffer_number=10", &new_cf_opt)); + ASSERT_EQ(new_cf_opt.write_buffer_size, 9); + ASSERT_EQ(new_cf_opt.max_write_buffer_number, 10); + ASSERT_TRUE(GetColumnFamilyOptionsFromString(base_cf_opt, + "write_buffer_size=11; max_write_buffer_number = 12 ;", + &new_cf_opt)); + ASSERT_EQ(new_cf_opt.write_buffer_size, 11); + ASSERT_EQ(new_cf_opt.max_write_buffer_number, 12); + // Wrong name "max_write_buffer_number_" + ASSERT_TRUE(!GetColumnFamilyOptionsFromString(base_cf_opt, + "write_buffer_size=13;max_write_buffer_number_=14;", + &new_cf_opt)); + // Wrong key/value pair + ASSERT_TRUE(!GetColumnFamilyOptionsFromString(base_cf_opt, + "write_buffer_size=13;max_write_buffer_number;", &new_cf_opt)); + // Error Paring value + ASSERT_TRUE(!GetColumnFamilyOptionsFromString(base_cf_opt, + "write_buffer_size=13;max_write_buffer_number=;", &new_cf_opt)); + // Missing option name + ASSERT_TRUE(!GetColumnFamilyOptionsFromString(base_cf_opt, + "write_buffer_size=13; =100;", &new_cf_opt)); } } // namespace rocksdb diff --git a/utilities/options/convenience.h b/utilities/options/convenience.h new file mode 100644 index 0000000000..5d7b6d1161 --- /dev/null +++ b/utilities/options/convenience.h @@ -0,0 +1,40 @@ +// 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. + +#pragma once + +#include +#include +#include "rocksdb/options.h" + +namespace rocksdb { + +// Take a map of option name and option value, apply them into the +// base_options, and return the new options as a result +bool GetColumnFamilyOptionsFromMap( + const ColumnFamilyOptions& base_options, + const std::unordered_map& opts_map, + ColumnFamilyOptions* new_options); + +bool GetDBOptionsFromMap( + const DBOptions& base_options, + const std::unordered_map& opts_map, + DBOptions* new_options); + +// Take a string representation of option names and values, apply them into the +// base_options, and return the new options as a result. The string has the +// following format: +// "write_buffer_size=1024;max_write_buffer_number=2" +bool GetColumnFamilyOptionsFromString( + const ColumnFamilyOptions& base_options, + const std::string& opts_str, + ColumnFamilyOptions* new_options); + +bool GetDBOptionsFromString( + const DBOptions& base_options, + const std::string& opts_str, + DBOptions* new_options); + +} // namespace rocksdb