diff --git a/src/kernel/bitcoinkernel.cpp b/src/kernel/bitcoinkernel.cpp index 52090c4408d..d27e7e9d4f3 100644 --- a/src/kernel/bitcoinkernel.cpp +++ b/src/kernel/bitcoinkernel.cpp @@ -455,6 +455,7 @@ struct ChainstateManagerOptions { node::BlockManager::Options m_blockman_options GUARDED_BY(m_mutex); std::shared_ptr m_context; node::ChainstateLoadOptions m_chainstate_load_options GUARDED_BY(m_mutex); + uint64_t m_db_cache_bytes GUARDED_BY(m_mutex){DEFAULT_KERNEL_CACHE}; ChainstateManagerOptions(const std::shared_ptr& context, const fs::path& data_dir, const fs::path& blocks_dir) : m_chainman_options{ChainstateManager::Options{ @@ -1031,6 +1032,20 @@ void btck_chainstate_manager_options_set_worker_threads_num(btck_ChainstateManag btck_ChainstateManagerOptions::get(opts).m_chainman_options.worker_threads_num = worker_threads; } +int btck_chainstate_manager_options_set_database_cache_bytes(btck_ChainstateManagerOptions* chainman_opts, uint64_t database_cache_bytes) +{ + if (database_cache_bytes < MIN_DBCACHE_BYTES || database_cache_bytes > MAX_DBCACHE_BYTES) { + LogError("Failed to set database cache: size is outside the supported range."); + return -1; + } + + auto& opts{btck_ChainstateManagerOptions::get(chainman_opts)}; + LOCK(opts.m_mutex); + opts.m_db_cache_bytes = database_cache_bytes; + opts.m_blockman_options.block_tree_db_params.cache_bytes = kernel::CacheSizes{database_cache_bytes}.block_tree_db; + return 0; +} + void btck_chainstate_manager_options_destroy(btck_ChainstateManagerOptions* options) { delete options; @@ -1083,7 +1098,7 @@ btck_ChainstateManager* btck_chainstate_manager_create( try { const auto chainstate_load_opts{WITH_LOCK(opts.m_mutex, return opts.m_chainstate_load_options)}; - kernel::CacheSizes cache_sizes{DEFAULT_KERNEL_CACHE}; + const kernel::CacheSizes cache_sizes{WITH_LOCK(opts.m_mutex, return opts.m_db_cache_bytes)}; auto [status, chainstate_err]{node::LoadChainstate(*chainman, cache_sizes, chainstate_load_opts)}; if (status != node::ChainstateLoadStatus::SUCCESS) { LogError("Failed to load chain state from your data directory: %s", chainstate_err.original); diff --git a/src/kernel/bitcoinkernel.h b/src/kernel/bitcoinkernel.h index 86ef2e2c398..f474a7ca8d8 100644 --- a/src/kernel/bitcoinkernel.h +++ b/src/kernel/bitcoinkernel.h @@ -1195,6 +1195,22 @@ BITCOINKERNEL_API void btck_chainstate_manager_options_set_worker_threads_num( btck_ChainstateManagerOptions* chainstate_manager_options, int worker_threads) BITCOINKERNEL_ARG_NONNULL(1); +/** + * @brief Set the total database cache used by the chainstate manager. + * + * The total cache is split internally between the block tree database, + * chainstate database, and in-memory coins cache. If this function is not + * called, the total cache defaults to 450 MiB. + * + * @param[in] chainstate_manager_options Non-null, options to be set. + * @param[in] database_cache_bytes The total database cache size in bytes. Values below 4 MiB are rejected. + * On 32-bit systems, values above 1 GiB are also rejected. + * @return 0 if the set was successful, non-zero if the set failed. + */ +BITCOINKERNEL_API int BITCOINKERNEL_WARN_UNUSED_RESULT btck_chainstate_manager_options_set_database_cache_bytes( + btck_ChainstateManagerOptions* chainstate_manager_options, + uint64_t database_cache_bytes) BITCOINKERNEL_ARG_NONNULL(1); + /** * @brief Sets wipe db in the options. In combination with calling * @ref btck_chainstate_manager_import_blocks this triggers either a full reindex, diff --git a/src/kernel/bitcoinkernel_wrapper.h b/src/kernel/bitcoinkernel_wrapper.h index 5f251d309c5..5dc203b474e 100644 --- a/src/kernel/bitcoinkernel_wrapper.h +++ b/src/kernel/bitcoinkernel_wrapper.h @@ -1200,6 +1200,11 @@ public: btck_chainstate_manager_options_set_worker_threads_num(get(), worker_threads); } + bool SetDatabaseCacheBytes(uint64_t database_cache_bytes) + { + return btck_chainstate_manager_options_set_database_cache_bytes(get(), database_cache_bytes) == 0; + } + bool SetWipeDbs(bool wipe_block_tree, bool wipe_chainstate) { return btck_chainstate_manager_options_set_wipe_dbs(get(), wipe_block_tree, wipe_chainstate) == 0; diff --git a/src/test/kernel/test_kernel.cpp b/src/test/kernel/test_kernel.cpp index 927d2b16e8a..83613dbbbbb 100644 --- a/src/test/kernel/test_kernel.cpp +++ b/src/test/kernel/test_kernel.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #define BOOST_TEST_MODULE Bitcoin Kernel Test Suite @@ -800,6 +801,9 @@ BOOST_AUTO_TEST_CASE(btck_chainman_tests) ChainstateManagerOptions chainman_opts{context, PathToString(test_directory.m_directory), PathToString(test_directory.m_directory / "blocks")}; chainman_opts.SetWorkerThreads(4); + BOOST_CHECK(!chainman_opts.SetDatabaseCacheBytes(4_MiB - 1)); + if constexpr (sizeof(void*) == 4) BOOST_CHECK(!chainman_opts.SetDatabaseCacheBytes(2_GiB)); + BOOST_CHECK(chainman_opts.SetDatabaseCacheBytes(4_MiB)); BOOST_CHECK(!chainman_opts.SetWipeDbs(/*wipe_block_tree=*/true, /*wipe_chainstate=*/false)); BOOST_CHECK(chainman_opts.SetWipeDbs(/*wipe_block_tree=*/true, /*wipe_chainstate=*/true)); BOOST_CHECK(chainman_opts.SetWipeDbs(/*wipe_block_tree=*/false, /*wipe_chainstate=*/true));