From 8c683048a314f508e4c001242bda12667b14fac0 Mon Sep 17 00:00:00 2001 From: udi-speedb <106253580+udi-speedb@users.noreply.github.com> Date: Thu, 19 Oct 2023 19:37:49 +0300 Subject: [PATCH] db bench: usability of the pinning policy parameter (#720) --- HISTORY.md | 1 + db_stress_tool/db_stress_gflags.cc | 8 +- db_stress_tool/db_stress_test_base.cc | 9 +- .../pinning_policy/scoped_pinning_policy.h | 12 +- table/block_based/default_pinning_policy.h | 2 + table/block_based/table_pinning_policy.cc | 2 + tools/db_bench_tool.cc | 107 ++++++++++++++++-- tools/db_crashtest.py | 6 +- 8 files changed, 132 insertions(+), 15 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index a72d8caec7..b91be9c684 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -15,6 +15,7 @@ * LOG Reporting: add reporting capabilities to the WriteController and the WriteBufferManager by saving the Loggers of the dbs which are using them internally and issuing WARN msgs to these Loggers whenever the state of the WC and WBM changes in regards to delaying (#556). * Enable speedb features: Use Scoped Pinning Policy in Enable speedb feature (#459). * sst_dump: display metaindex_handle and the index_handle's offset and size in footer information (#404). +* db_bench: Add support for individual scoped pinning policy parameters (#687). ### Bug Fixes * db_bench: Fix SeekRandomWriteRandom valid check. Use key and value only after checking iterator is valid. diff --git a/db_stress_tool/db_stress_gflags.cc b/db_stress_tool/db_stress_gflags.cc index 2e49ab86bf..f876e39b08 100644 --- a/db_stress_tool/db_stress_gflags.cc +++ b/db_stress_tool/db_stress_gflags.cc @@ -23,6 +23,7 @@ #ifdef GFLAGS #include "db_stress_tool/db_stress_common.h" +#include "table/block_based/default_pinning_policy.h" static bool ValidateUint32Range(const char* flagname, uint64_t value) { if (value > std::numeric_limits::max()) { @@ -890,7 +891,12 @@ DEFINE_string(fs_uri, "", " with --env_uri." " Creates a default environment with the specified filesystem."); -DEFINE_string(pinning_policy, "", "URI for registry TablePinningPolicy"); +DEFINE_string(pinning_policy, + ROCKSDB_NAMESPACE::DefaultPinningPolicy::kNickName(), + "The pinning policy to use. " + "The options are: " + "'DefaultPinning': Default RocksDB's pinning polcy. " + "'ScopedPinning': Speedb's Scoped pinning policy."); DEFINE_uint64(ops_per_thread, 1200000, "Number of operations per thread."); static const bool FLAGS_ops_per_thread_dummy __attribute__((__unused__)) = diff --git a/db_stress_tool/db_stress_test_base.cc b/db_stress_tool/db_stress_test_base.cc index c9953f9fc7..6d0a2dc66f 100644 --- a/db_stress_tool/db_stress_test_base.cc +++ b/db_stress_tool/db_stress_test_base.cc @@ -33,6 +33,7 @@ #include "db_stress_tool/db_stress_compaction_filter.h" #include "db_stress_tool/db_stress_driver.h" #include "db_stress_tool/db_stress_table_properties_collector.h" +#include "plugin/speedb/pinning_policy/scoped_pinning_policy.h" #include "rocksdb/convenience.h" #include "rocksdb/filter_policy.h" #include "rocksdb/options.h" @@ -43,6 +44,7 @@ #include "rocksdb/utilities/object_registry.h" #include "rocksdb/utilities/write_batch_with_index.h" #include "speedb/version.h" +#include "table/block_based/default_pinning_policy.h" #include "test_util/testutil.h" #include "util/cast_util.h" #include "utilities/backup/backup_engine_impl.h" @@ -3167,11 +3169,16 @@ void InitializeOptionsFromFlags( block_based_options.num_file_reads_for_auto_readahead = FLAGS_num_file_reads_for_auto_readahead; if (!FLAGS_pinning_policy.empty()) { + auto pinning_policy_uri = DefaultPinningPolicy::kClassName(); + if (FLAGS_pinning_policy == DefaultPinningPolicy::kNickName()) { + pinning_policy_uri = ScopedPinningPolicy::kClassName(); + } + ConfigOptions config_options; config_options.ignore_unknown_options = false; config_options.ignore_unsupported_options = false; Status s = TablePinningPolicy::CreateFromString( - config_options, FLAGS_pinning_policy, + config_options, pinning_policy_uri, &block_based_options.pinning_policy); if (!s.ok()) { fprintf(stderr, "Failed to create PinningPolicy: %s\n", diff --git a/plugin/speedb/pinning_policy/scoped_pinning_policy.h b/plugin/speedb/pinning_policy/scoped_pinning_policy.h index 431aebc763..10f839bcf6 100644 --- a/plugin/speedb/pinning_policy/scoped_pinning_policy.h +++ b/plugin/speedb/pinning_policy/scoped_pinning_policy.h @@ -22,16 +22,20 @@ namespace ROCKSDB_NAMESPACE { struct TablePinningOptions; struct ScopedPinningOptions { static const char* kName() { return "ScopedPinningOptions"; } + + static constexpr uint32_t kDefaultLastLevelWithDataPercent = 10; + static constexpr uint32_t kDefaultMidPercent = 80; + // Limit to how much data should be pinned size_t capacity = 1024 * 1024 * 1024; // 1GB // Percent of capacity at which not to pin last-leve-with-data data - uint32_t last_level_with_data_percent = 10; + uint32_t last_level_with_data_percent = kDefaultLastLevelWithDataPercent; + // Percent of capacity at which not to pin non-L0 data - uint32_t mid_percent = 80; + uint32_t mid_percent = kDefaultMidPercent; }; -// A table policy that limits the size of the data to be pinned // class ScopedPinningPolicy : public RecordingPinningPolicy { public: @@ -39,7 +43,7 @@ class ScopedPinningPolicy : public RecordingPinningPolicy { ScopedPinningPolicy(const ScopedPinningOptions& options); static const char* kClassName() { return "speedb_scoped_pinning_policy"; } - static const char* kNickName() { return "speedb.ScopedPinningPolicy"; } + static const char* kNickName() { return "scoped"; } const char* Name() const override { return kClassName(); } const char* NickName() const override { return kNickName(); } std::string GetId() const override; diff --git a/table/block_based/default_pinning_policy.h b/table/block_based/default_pinning_policy.h index 23e5f2c96b..292b39b809 100644 --- a/table/block_based/default_pinning_policy.h +++ b/table/block_based/default_pinning_policy.h @@ -37,7 +37,9 @@ class DefaultPinningPolicy : public RecordingPinningPolicy { bool pin_l0); static const char* kClassName() { return "DefaultPinningPolicy"; } + static const char* kNickName() { return "default"; } const char* Name() const override { return kClassName(); } + const char* NickName() const override { return kNickName(); } protected: bool CheckPin(const TablePinningOptions& tpo, uint8_t type, size_t /*size*/, diff --git a/table/block_based/table_pinning_policy.cc b/table/block_based/table_pinning_policy.cc index f2f028e5ff..7155d44336 100644 --- a/table/block_based/table_pinning_policy.cc +++ b/table/block_based/table_pinning_policy.cc @@ -51,7 +51,9 @@ class DefaultPinningPolicy : public RecordingPinningPolicy { //**TODO: Register options? } static const char* kClassName() { return "DefaultPinningPolicy"; } + static const char* kNickName() { return "DefaultPinning"; } const char* Name() const override { return kClassName(); } + const char* NickName() const override { return kNickName(); } protected: bool CheckPin(const TablePinningOptions& tpo, uint8_t type, size_t /*size*/, diff --git a/tools/db_bench_tool.cc b/tools/db_bench_tool.cc index 27860bdded..0f05701b1c 100644 --- a/tools/db_bench_tool.cc +++ b/tools/db_bench_tool.cc @@ -61,6 +61,7 @@ #include "monitoring/histogram.h" #include "monitoring/statistics.h" #include "options/cf_options.h" +#include "plugin/speedb/pinning_policy/scoped_pinning_policy.h" #include "port/port.h" #include "port/stack_trace.h" #include "rocksdb/cache.h" @@ -92,6 +93,7 @@ #include "rocksdb/write_batch.h" #include "rocksdb/write_buffer_manager.h" #include "speedb/version.h" +#include "table/block_based/default_pinning_policy.h" #include "test_util/testutil.h" #include "test_util/transaction_test_util.h" #include "tools/simulated_hybrid_file_system.h" @@ -818,7 +820,32 @@ DEFINE_bool( " Note `cache_index_and_filter_blocks` must be true for this option to have" " any effect."); -DEFINE_string(pinning_policy, "", "URI for registry TablePinningPolicy"); +DEFINE_string(pinning_policy, + ROCKSDB_NAMESPACE::DefaultPinningPolicy::kNickName(), + "The pinning policy to use. " + "The options are: " + "'default': Default RocksDB's pinning polcy. " + "'scoped': Speedb's Scoped pinning policy."); + +DEFINE_int32(scoped_pinning_capacity, -1, + "Pinning policy capacity. The default (-1) results in the " + "capacity being calculated " + "automatically. If the capacity is >= 0, the specified value will " + "be the capacity. Applicable only when pinning_policy=='Scoped'."); + +DEFINE_int32( + scoped_pinning_last_level_with_data_percent, + ROCKSDB_NAMESPACE::ScopedPinningOptions::kDefaultLastLevelWithDataPercent, + "Max percent of the pinning capacity to pin entites that are at " + "the bottom-most possible level." + "Applicable only when pinning_policy=='Scoped'."); + +DEFINE_int32(scoped_pinning_mid_percent, + ROCKSDB_NAMESPACE::ScopedPinningOptions::kDefaultMidPercent, + "Max percent of the pinning capacity to pin entites that are " + "above the bottom-most level,but at a >0 level. " + "Must be >= scoped_pinning_last_level_with_data_percent. " + "Applicable only when pinning_policy=='Scoped'."); DEFINE_int32(block_size, static_cast( @@ -4817,14 +4844,28 @@ class Benchmark { } else { fprintf(stdout, "Integrated BlobDB: blob cache disabled\n"); } - if (!FLAGS_pinning_policy.empty()) { - s = TablePinningPolicy::CreateFromString( - config_options, FLAGS_pinning_policy, - &block_based_options.pinning_policy); - if (!s.ok()) { - ErrorExit("Could not create pinning policy: %s", - s.ToString().c_str()); + + if (FLAGS_pinning_policy == + ROCKSDB_NAMESPACE::ScopedPinningPolicy::kNickName()) { + ScopedPinningOptions pinning_options; + + size_t pinning_capacity = 0U; + if (FLAGS_scoped_pinning_capacity >= 0) { + pinning_capacity = FLAGS_scoped_pinning_capacity; + } else { + auto cache_capacity = FLAGS_cache_size; + if (FLAGS_cost_write_buffer_to_cache) { + assert(cache_capacity >= FLAGS_db_write_buffer_size); + cache_capacity -= FLAGS_db_write_buffer_size; + } + pinning_capacity = (80 * cache_capacity) / 100; } + pinning_options.capacity = pinning_capacity; + pinning_options.last_level_with_data_percent = + FLAGS_scoped_pinning_last_level_with_data_percent; + pinning_options.mid_percent = FLAGS_scoped_pinning_mid_percent; + block_based_options.pinning_policy = + std::make_shared(pinning_options); } options.table_factory.reset( @@ -9279,6 +9320,55 @@ void ValidateMetadataCacheOptions() { } } +void ValidatePinningRelatedOptions() { + if (FLAGS_pinning_policy == + ROCKSDB_NAMESPACE::DefaultPinningPolicy::kNickName()) { + return; + } else if (FLAGS_pinning_policy == + ROCKSDB_NAMESPACE::ScopedPinningPolicy::kNickName()) { + if (FLAGS_cache_index_and_filter_blocks == false) { + ErrorExit( + "--cache_index_and_filter_blocks must be set when " + "--pinning_policy=='%s' to have any affect.", + ROCKSDB_NAMESPACE::ScopedPinningPolicy::kNickName()); + } + + if (FLAGS_scoped_pinning_capacity < -1) { + ErrorExit( + "--scoped_pinning_capacity must be either -1 (auto-calc) or >= 0"); + } + + if ((FLAGS_scoped_pinning_last_level_with_data_percent < 0) || + (FLAGS_scoped_pinning_last_level_with_data_percent > 100)) { + ErrorExit( + "--scoped_pinning_last_level_with_data_percent must be between 0 and " + "100"); + } + + if ((FLAGS_scoped_pinning_mid_percent < 0) || + (FLAGS_scoped_pinning_mid_percent > 100)) { + ErrorExit("--scoped_pinning_mid_percent must be between 0 and 100"); + } + + if (FLAGS_scoped_pinning_last_level_with_data_percent >= + FLAGS_scoped_pinning_mid_percent) { + ErrorExit( + "--scoped_pinning_last_level_with_data_percent must be <= " + "--scoped_pinning_mid_percent must be between 0 and 100"); + } + + if (FLAGS_cost_write_buffer_to_cache) { + if (FLAGS_db_write_buffer_size > FLAGS_cache_size) { + ErrorExit("--cache_size must be >= --db_write_buffer_size"); + } + } + } else { + ErrorExit("--pinning_policy must be either %s or %s", + ROCKSDB_NAMESPACE::DefaultPinningPolicy::kNickName(), + ROCKSDB_NAMESPACE::ScopedPinningPolicy::kNickName()); + } +} + namespace { // Records the values of applicable flags during the invocation of the first // group The user may not modify any of these in subsequent groups @@ -9605,6 +9695,7 @@ int db_bench_tool_run_group(int group_num, int num_groups, int argc, } ValidateMetadataCacheOptions(); + ValidatePinningRelatedOptions(); ParseSanitizeAndValidateMultipleDBsFlags(first_group); if (first_group) { diff --git a/tools/db_crashtest.py b/tools/db_crashtest.py index 7bb4b34a50..37f5ac7f93 100644 --- a/tools/db_crashtest.py +++ b/tools/db_crashtest.py @@ -223,7 +223,7 @@ "customopspercent": 0, # "filter_uri": lambda: random.choice(["speedb.PairedBloomFilter", ""]), "memtablerep": lambda: random.choice(["skip_list", "hash_spdb"]), - "pinning_policy": lambda: random.choice(["", "speedb_scoped_pinning_policy"]), + "pinning_policy": lambda: random.choice(["DefaultPinning", "ScopedPinning"]), "use_dynamic_delay": lambda: random.choice([0, 1, 1, 1]), "allow_wbm_stalls": lambda: random.randint(0, 1), "start_delay_percent": lambda: random.randint(0, 99), @@ -767,6 +767,10 @@ def finalize_and_sanitize(src_params, counter): dest_params["bloom_bits"] = random.choice([random.randint(1,19), random.lognormvariate(2.3, 1.3)]) + # db_bench will abort if using ScopedPinningPolicy and not setting cache_index_and_filter_blocks + if dest_params.get("pinning_policy") == "ScopedPinning": + dest_params["cache_index_and_filter_blocks"] + return dest_params