diff --git a/nano/core_test/toml.cpp b/nano/core_test/toml.cpp index 59017599..b15c2f36 100644 --- a/nano/core_test/toml.cpp +++ b/nano/core_test/toml.cpp @@ -255,15 +255,8 @@ TEST (toml, daemon_config_deserialize_defaults) ASSERT_EQ (conf.node.lmdb_config.map_size, defaults.node.lmdb_config.map_size); ASSERT_EQ (conf.node.rocksdb_config.enable, defaults.node.rocksdb_config.enable); - ASSERT_EQ (conf.node.rocksdb_config.bloom_filter_bits, defaults.node.rocksdb_config.bloom_filter_bits); - ASSERT_EQ (conf.node.rocksdb_config.block_cache, defaults.node.rocksdb_config.block_cache); + ASSERT_EQ (conf.node.rocksdb_config.memory_multiplier, defaults.node.rocksdb_config.memory_multiplier); ASSERT_EQ (conf.node.rocksdb_config.io_threads, defaults.node.rocksdb_config.io_threads); - ASSERT_EQ (conf.node.rocksdb_config.enable_pipelined_write, defaults.node.rocksdb_config.enable_pipelined_write); - ASSERT_EQ (conf.node.rocksdb_config.cache_index_and_filter_blocks, defaults.node.rocksdb_config.cache_index_and_filter_blocks); - ASSERT_EQ (conf.node.rocksdb_config.block_size, defaults.node.rocksdb_config.block_size); - ASSERT_EQ (conf.node.rocksdb_config.memtable_size, defaults.node.rocksdb_config.memtable_size); - ASSERT_EQ (conf.node.rocksdb_config.num_memtables, defaults.node.rocksdb_config.num_memtables); - ASSERT_EQ (conf.node.rocksdb_config.total_memtable_size, defaults.node.rocksdb_config.total_memtable_size); } TEST (toml, optional_child) @@ -513,15 +506,8 @@ TEST (toml, daemon_config_deserialize_no_defaults) [node.rocksdb] enable = true - bloom_filter_bits = 10 - block_cache = 512 + memory_multiplier = 3 io_threads = 99 - enable_pipelined_write = true - cache_index_and_filter_blocks = true - block_size = 16 - memtable_size = 128 - num_memtables = 3 - total_memtable_size = 0 [node.experimental] secondary_work_peers = ["test.org:998"] @@ -668,15 +654,8 @@ TEST (toml, daemon_config_deserialize_no_defaults) ASSERT_NE (conf.node.lmdb_config.map_size, defaults.node.lmdb_config.map_size); ASSERT_NE (conf.node.rocksdb_config.enable, defaults.node.rocksdb_config.enable); - ASSERT_NE (conf.node.rocksdb_config.bloom_filter_bits, defaults.node.rocksdb_config.bloom_filter_bits); - ASSERT_NE (conf.node.rocksdb_config.block_cache, defaults.node.rocksdb_config.block_cache); + ASSERT_NE (conf.node.rocksdb_config.memory_multiplier, defaults.node.rocksdb_config.memory_multiplier); ASSERT_NE (conf.node.rocksdb_config.io_threads, defaults.node.rocksdb_config.io_threads); - ASSERT_NE (conf.node.rocksdb_config.enable_pipelined_write, defaults.node.rocksdb_config.enable_pipelined_write); - ASSERT_NE (conf.node.rocksdb_config.cache_index_and_filter_blocks, defaults.node.rocksdb_config.cache_index_and_filter_blocks); - ASSERT_NE (conf.node.rocksdb_config.block_size, defaults.node.rocksdb_config.block_size); - ASSERT_NE (conf.node.rocksdb_config.memtable_size, defaults.node.rocksdb_config.memtable_size); - ASSERT_NE (conf.node.rocksdb_config.num_memtables, defaults.node.rocksdb_config.num_memtables); - ASSERT_NE (conf.node.rocksdb_config.total_memtable_size, defaults.node.rocksdb_config.total_memtable_size); } /** There should be no required values **/ diff --git a/nano/lib/rocksdbconfig.cpp b/nano/lib/rocksdbconfig.cpp index c0f50955..fb090ca4 100644 --- a/nano/lib/rocksdbconfig.cpp +++ b/nano/lib/rocksdbconfig.cpp @@ -4,55 +4,25 @@ nano::error nano::rocksdb_config::serialize_toml (nano::tomlconfig & toml) const { toml.put ("enable", enable, "Whether to use the RocksDB backend for the ledger database.\ntype:bool"); - toml.put ("enable_pipelined_write", enable_pipelined_write, "Whether to use 2 separate write queues for memtable/WAL, true is recommended.\ntype:bool"); - toml.put ("cache_index_and_filter_blocks", cache_index_and_filter_blocks, "Whether index and filter blocks are stored in block_cache, true is recommended.\ntype:bool"); - toml.put ("bloom_filter_bits", bloom_filter_bits, "Number of bits to use with a bloom filter. Helps with point reads but uses more memory. 0 disables the bloom filter, 10 is recommended.\ntype:uint32"); - toml.put ("block_cache", block_cache, "Size (MB) of the block cache; A larger number will increase performance of read operations. At least 512MB is recommended.\ntype:uint64"); + toml.put ("memory_multiplier", memory_multiplier, "This will modify how much memory is used represented by 1 (low), 2 (medium), 3 (high). Default is 2.\ntype:uint8"); toml.put ("io_threads", io_threads, "Number of threads to use with the background compaction and flushing. Number of hardware threads is recommended.\ntype:uint32"); - toml.put ("block_size", block_size, "Uncompressed data (KBs) per block. Increasing block size decreases memory usage and space amplification, but increases read amplification. 16 is recommended.\ntype:uint32"); - toml.put ("num_memtables", num_memtables, "Number of memtables to keep in memory per column family. 2 is the minimum, 3 is recommended.\ntype:uint32"); - toml.put ("memtable_size", memtable_size, "Amount of memory (MB) to build up before flushing to disk for an individual column family. Large values increase performance. 64 or 128 is recommended.\ntype:uint32"); - toml.put ("total_memtable_size", total_memtable_size, "Total memory (MB) which can be used across all memtables, set to 0 for unconstrained.\ntype:uint32"); return toml.get_error (); } nano::error nano::rocksdb_config::deserialize_toml (nano::tomlconfig & toml) { toml.get_optional ("enable", enable); - toml.get_optional ("enable_pipelined_write", enable_pipelined_write); - toml.get_optional ("cache_index_and_filter_blocks", cache_index_and_filter_blocks); - toml.get_optional ("bloom_filter_bits", bloom_filter_bits); - toml.get_optional ("block_cache", block_cache); + toml.get_optional ("memory_multiplier", memory_multiplier); toml.get_optional ("io_threads", io_threads); - toml.get_optional ("block_size", block_size); - toml.get_optional ("num_memtables", num_memtables); - toml.get_optional ("memtable_size", memtable_size); - toml.get_optional ("total_memtable_size", total_memtable_size); // Validate ranges - if (bloom_filter_bits > 100) - { - toml.get_error ().set ("bloom_filter_bits is too high"); - } - if (num_memtables < 2) - { - toml.get_error ().set ("num_memtables must be at least 2"); - } - if (memtable_size == 0) - { - toml.get_error ().set ("memtable_size must be non-zero"); - } - if ((total_memtable_size < memtable_size * 8) && (total_memtable_size != 0)) - { - toml.get_error ().set ("total_memtable_size should be at least 8 times greater than memtable_size or be set to 0"); - } if (io_threads == 0) { toml.get_error ().set ("io_threads must be non-zero"); } - if (block_size == 0) + if (memory_multiplier < 1 || memory_multiplier > 3) { - toml.get_error ().set ("block_size must be non-zero"); + toml.get_error ().set ("memory_multiplier must be either 1, 2 or 3"); } return toml.get_error (); diff --git a/nano/lib/rocksdbconfig.hpp b/nano/lib/rocksdbconfig.hpp index e47873b3..750eab9d 100644 --- a/nano/lib/rocksdbconfig.hpp +++ b/nano/lib/rocksdbconfig.hpp @@ -16,14 +16,7 @@ public: nano::error deserialize_toml (nano::tomlconfig & toml_a); bool enable{ false }; - unsigned bloom_filter_bits{ 0 }; - uint64_t block_cache{ 64 }; // MB + uint8_t memory_multiplier{ 2 }; unsigned io_threads{ std::thread::hardware_concurrency () }; - bool enable_pipelined_write{ false }; - bool cache_index_and_filter_blocks{ false }; - unsigned block_size{ 4 }; // KB - unsigned memtable_size{ 32 }; // MB - unsigned num_memtables{ 2 }; // Need a minimum of 2 - unsigned total_memtable_size{ 512 }; // MB }; } diff --git a/nano/node/rocksdb/rocksdb.cpp b/nano/node/rocksdb/rocksdb.cpp index 2d77da30..735e981f 100644 --- a/nano/node/rocksdb/rocksdb.cpp +++ b/nano/node/rocksdb/rocksdb.cpp @@ -473,10 +473,7 @@ rocksdb::Options nano::rocksdb_store::get_db_options () const db_options.OptimizeLevelStyleCompaction (); // Adds a separate write queue for memtable/WAL - db_options.enable_pipelined_write = rocksdb_config.enable_pipelined_write; - - // Total size of memtables across column families. This can be used to manage the total memory used by memtables. - db_options.db_write_buffer_size = rocksdb_config.total_memtable_size * 1024 * 1024ULL; + db_options.enable_pipelined_write = true; return db_options; } @@ -486,21 +483,17 @@ rocksdb::BlockBasedTableOptions nano::rocksdb_store::get_table_options () const rocksdb::BlockBasedTableOptions table_options; // Block cache for reads - table_options.block_cache = rocksdb::NewLRUCache (rocksdb_config.block_cache * 1024 * 1024ULL); + table_options.block_cache = rocksdb::NewLRUCache (1024ULL * 1024 * base_block_cache_size * rocksdb_config.memory_multiplier); // Bloom filter to help with point reads - auto bloom_filter_bits = rocksdb_config.bloom_filter_bits; - if (bloom_filter_bits > 0) - { - table_options.filter_policy.reset (rocksdb::NewBloomFilterPolicy (bloom_filter_bits, false)); - } + auto bloom_filter_bits = 10; + table_options.filter_policy.reset (rocksdb::NewBloomFilterPolicy (bloom_filter_bits, false)); // Increasing block_size decreases memory usage and space amplification, but increases read amplification. - table_options.block_size = rocksdb_config.block_size * 1024ULL; + table_options.block_size = 16 * 1024ULL; - // Whether index and filter blocks are stored in block_cache. These settings should be synced - table_options.cache_index_and_filter_blocks = rocksdb_config.cache_index_and_filter_blocks; - table_options.pin_l0_filter_and_index_blocks_in_cache = rocksdb_config.cache_index_and_filter_blocks; + // Whether index and filter blocks are stored in block_cache + table_options.pin_l0_filter_and_index_blocks_in_cache = true; return table_options; } @@ -514,7 +507,7 @@ rocksdb::ColumnFamilyOptions nano::rocksdb_store::get_cf_options () const cf_options.level0_file_num_compaction_trigger = 4; // L1 size, compaction is triggered for L0 at this size (4 SST files in L1) - cf_options.max_bytes_for_level_base = 1024ULL * 1024 * 4 * rocksdb_config.memtable_size; + cf_options.max_bytes_for_level_base = 1024ULL * 1024 * 4 * rocksdb_config.memory_multiplier * base_memtable_size; // Each level is a multiple of the above. If L1 is 512MB. L2 will be 512 * 8 = 2GB. L3 will be 2GB * 8 = 16GB, and so on... cf_options.max_bytes_for_level_multiplier = 8; @@ -523,16 +516,16 @@ rocksdb::ColumnFamilyOptions nano::rocksdb_store::get_cf_options () const cf_options.ttl = 1 * 24 * 60 * 60; // Size of level 1 sst files - cf_options.target_file_size_base = 1024ULL * 1024 * rocksdb_config.memtable_size; + cf_options.target_file_size_base = 1024ULL * 1024 * rocksdb_config.memory_multiplier * base_memtable_size; // Size of each memtable - cf_options.write_buffer_size = 1024ULL * 1024 * rocksdb_config.memtable_size; + cf_options.write_buffer_size = 1024ULL * 1024 * rocksdb_config.memory_multiplier * base_memtable_size; // Size target of levels are changed dynamically based on size of the last level cf_options.level_compaction_dynamic_level_bytes = true; - // Number of memtables to keep in memory (1 active, rest inactive/immutable) - cf_options.max_write_buffer_number = rocksdb_config.num_memtables; + // Number of memtables to keep in memory (1 active, 1 inactive) + cf_options.max_write_buffer_number = 2; return cf_options; } diff --git a/nano/node/rocksdb/rocksdb.hpp b/nano/node/rocksdb/rocksdb.hpp index 723bfd54..2de51d0f 100644 --- a/nano/node/rocksdb/rocksdb.hpp +++ b/nano/node/rocksdb/rocksdb.hpp @@ -102,6 +102,9 @@ private: rocksdb::Options get_db_options () const; rocksdb::BlockBasedTableOptions get_table_options () const; nano::rocksdb_config rocksdb_config; + + constexpr static int base_memtable_size = 16; + constexpr static int base_block_cache_size = 16; }; extern template class block_store_partial;