From 6e11a3f1a368d8c1456bbbd26b937e8085844182 Mon Sep 17 00:00:00 2001 From: Valon Mamudi Date: Tue, 3 Jun 2025 17:45:35 +0200 Subject: [PATCH] Add configurable NuDB block size feature - Implement parseBlockSize() function with validation - Add nudb_block_size configuration parameter - Support block sizes from 4K to 64K (power of 2) - Add comprehensive logging and error handling - Maintain backward compatibility with 4K default --- cfg/rippled-example.cfg | 35 ++++++++++++++++ src/xrpld/nodestore/backend/NuDBFactory.cpp | 46 ++++++++++++++++++++- 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/cfg/rippled-example.cfg b/cfg/rippled-example.cfg index 8fb7d00875..a884e01a0a 100644 --- a/cfg/rippled-example.cfg +++ b/cfg/rippled-example.cfg @@ -975,6 +975,40 @@ # number of ledger records online. Must be greater # than or equal to ledger_history. # +# Optional keys for NuDB only: +# +# nudb_block_size Block size in bytes for NuDB storage. +# Must be a power of 2 between 4096 and 65536. +# Default is 4096. +# +# This parameter controls the fundamental storage unit +# size for NuDB's internal data structures. The choice +# of block size can significantly impact performance +# depending on your storage hardware and filesystem: +# +# - 4096 bytes: Optimal for most standard SSDs and +# traditional filesystems (ext4, NTFS, HFS+). +# Provides good balance of performance and storage +# efficiency. Recommended for most deployments. +# +# - 8192-16384 bytes: May improve performance on +# high-end NVMe SSDs and copy-on-write filesystems +# like ZFS or Btrfs that benefit from larger block +# alignment. Can reduce metadata overhead for large +# databases. +# +# - 32768-65536 bytes: Suitable for specialized +# high-throughput scenarios with very fast storage. +# May increase memory usage and reduce efficiency +# for smaller databases. +# +# Note: This setting cannot be changed after database +# creation without rebuilding the entire database. +# Choose carefully based on your hardware and expected +# database size. +# +# Example: nudb_block_size=4096 +# # These keys modify the behavior of online_delete, and thus are only # relevant if online_delete is defined and non-zero: # @@ -1471,6 +1505,7 @@ secure_gateway = 127.0.0.1 [node_db] type=NuDB path=/var/lib/rippled/db/nudb +nudb_block_size=4096 online_delete=512 advisory_delete=0 diff --git a/src/xrpld/nodestore/backend/NuDBFactory.cpp b/src/xrpld/nodestore/backend/NuDBFactory.cpp index 2f4e9d502e..b0f2a26141 100644 --- a/src/xrpld/nodestore/backend/NuDBFactory.cpp +++ b/src/xrpld/nodestore/backend/NuDBFactory.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -52,6 +53,7 @@ public: size_t const keyBytes_; std::size_t const burstSize_; std::string const name_; + std::size_t const blockSize_; nudb::store db_; std::atomic deletePath_; Scheduler& scheduler_; @@ -66,6 +68,7 @@ public: , keyBytes_(keyBytes) , burstSize_(burstSize) , name_(get(keyValues, "path")) + , blockSize_(parseBlockSize(keyValues, journal)) , deletePath_(false) , scheduler_(scheduler) { @@ -85,6 +88,7 @@ public: , keyBytes_(keyBytes) , burstSize_(burstSize) , name_(get(keyValues, "path")) + , blockSize_(parseBlockSize(keyValues, journal)) , db_(context) , deletePath_(false) , scheduler_(scheduler) @@ -143,7 +147,7 @@ public: uid, salt, keyBytes_, - nudb::block_size(kp), + blockSize_, 0.50, ec); if (ec == nudb::errc::file_exists) @@ -359,6 +363,46 @@ public: { return 3; } + +private: + static std::size_t + parseBlockSize(Section const& keyValues, beast::Journal journal) + { + std::size_t blockSize = 4096; // Default 4K + std::string blockSizeStr; + + if (get_if_exists(keyValues, "nudb_block_size", blockSizeStr)) + { + try + { + blockSize = beast::lexicalCastThrow(blockSizeStr); + + // Validate: must be power of 2 between 4K and 64K + if (blockSize < 4096 || blockSize > 65536 || + (blockSize & (blockSize - 1)) != 0) + { + JLOG(journal.warn()) + << "Invalid nudb_block_size: " << blockSize + << ". Must be power of 2 between 4096 and 65536. Using default 4096."; + blockSize = 4096; + } + else + { + JLOG(journal.info()) + << "Using custom NuDB block size: " << blockSize << " bytes"; + } + } + catch (std::exception const& e) + { + JLOG(journal.warn()) + << "Invalid nudb_block_size value: " << blockSizeStr + << ". Using default 4096. Error: " << e.what(); + blockSize = 4096; + } + } + + return blockSize; + } }; //------------------------------------------------------------------------------