diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp index bab09f13d9..c9e82eed3c 100644 --- a/src/bitcoin-chainstate.cpp +++ b/src/bitcoin-chainstate.cpp @@ -123,10 +123,7 @@ int main(int argc, char* argv[]) util::SignalInterrupt interrupt; ChainstateManager chainman{interrupt, chainman_opts, blockman_opts}; - node::CacheSizes cache_sizes; - cache_sizes.block_tree_db = 2 << 20; - cache_sizes.coins_db = 2 << 22; - cache_sizes.coins = (450 << 20) - (2 << 20) - (2 << 22); + kernel::CacheSizes cache_sizes{MiBToBytes(nDefaultDbCache)}; node::ChainstateLoadOptions options; auto [status, error] = node::LoadChainstate(chainman, cache_sizes, options); if (status != node::ChainstateLoadStatus::SUCCESS) { diff --git a/src/init.cpp b/src/init.cpp index a4ad2771cc..612b04a98e 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -119,9 +120,10 @@ using common::AmountErrMsg; using common::InvalidPortErrMsg; using common::ResolveErrMsg; +using kernel::CacheSizes; + using node::ApplyArgsManOptions; using node::BlockManager; -using node::CacheSizes; using node::CalculateCacheSizes; using node::ChainstateLoadResult; using node::ChainstateLoadStatus; @@ -1603,18 +1605,18 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) ReadNotificationArgs(args, kernel_notifications); // cache size calculations - CacheSizes cache_sizes = CalculateCacheSizes(args, g_enabled_filter_types.size()); + auto [index_cache_sizes, kernel_cache_sizes] = CalculateCacheSizes(args, g_enabled_filter_types.size()); - LogPrintf("Cache configuration:\n"); - LogPrintf("* Using %.1f MiB for block index database\n", cache_sizes.block_tree_db * (1.0 / 1024 / 1024)); + LogInfo("Cache configuration:"); + LogInfo("* Using %.1f MiB for block index database", kernel_cache_sizes.block_tree_db * (1.0 / 1024 / 1024)); if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { - LogPrintf("* Using %.1f MiB for transaction index database\n", cache_sizes.tx_index * (1.0 / 1024 / 1024)); + LogInfo("* Using %.1f MiB for transaction index database", index_cache_sizes.tx_index * (1.0 / 1024 / 1024)); } for (BlockFilterType filter_type : g_enabled_filter_types) { - LogPrintf("* Using %.1f MiB for %s block filter index database\n", - cache_sizes.filter_index * (1.0 / 1024 / 1024), BlockFilterTypeName(filter_type)); + LogInfo("* Using %.1f MiB for %s block filter index database", + index_cache_sizes.filter_index * (1.0 / 1024 / 1024), BlockFilterTypeName(filter_type)); } - LogPrintf("* Using %.1f MiB for chain state database\n", cache_sizes.coins_db * (1.0 / 1024 / 1024)); + LogInfo("* Using %.1f MiB for chain state database", kernel_cache_sizes.coins_db * (1.0 / 1024 / 1024)); assert(!node.mempool); assert(!node.chainman); @@ -1627,7 +1629,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) node, do_reindex, do_reindex_chainstate, - cache_sizes, + kernel_cache_sizes, args); if (status == ChainstateLoadStatus::FAILURE && !do_reindex && !ShutdownRequested(node)) { // suggest a reindex @@ -1646,7 +1648,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) node, do_reindex, do_reindex_chainstate, - cache_sizes, + kernel_cache_sizes, args); } if (status != ChainstateLoadStatus::SUCCESS && status != ChainstateLoadStatus::INTERRUPTED) { @@ -1672,12 +1674,12 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // ********************************************************* Step 8: start indexers if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { - g_txindex = std::make_unique(interfaces::MakeChain(node), cache_sizes.tx_index, false, do_reindex); + g_txindex = std::make_unique(interfaces::MakeChain(node), index_cache_sizes.tx_index, false, do_reindex); node.indexes.emplace_back(g_txindex.get()); } for (const auto& filter_type : g_enabled_filter_types) { - InitBlockFilterIndex([&]{ return interfaces::MakeChain(node); }, filter_type, cache_sizes.filter_index, false, do_reindex); + InitBlockFilterIndex([&]{ return interfaces::MakeChain(node); }, filter_type, index_cache_sizes.filter_index, false, do_reindex); node.indexes.emplace_back(GetBlockFilterIndex(filter_type)); } diff --git a/src/kernel/caches.h b/src/kernel/caches.h new file mode 100644 index 0000000000..3f1e20474d --- /dev/null +++ b/src/kernel/caches.h @@ -0,0 +1,42 @@ +// Copyright (c) 2024-present The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_KERNEL_CACHES_H +#define BITCOIN_KERNEL_CACHES_H + +#include +#include + +#include +#include +#include +#include + +//! Guard against truncation of values before converting. +constexpr size_t MiBToBytes(int64_t mib) +{ + Assert(std::countl_zero(static_cast(mib)) >= 21); // Ensure sign bit is unset + enough zeros to shift. + const int64_t bytes{mib << 20}; + Assert(static_cast(bytes) <= std::numeric_limits::max()); + return static_cast(bytes); +} + +namespace kernel { +struct CacheSizes { + size_t block_tree_db; + size_t coins_db; + size_t coins; + + CacheSizes(size_t total_cache) + { + block_tree_db = std::min(total_cache / 8, MiBToBytes(nMaxBlockDBCache)); + total_cache -= block_tree_db; + coins_db = std::min(total_cache / 2, MiBToBytes(nMaxCoinsDBCache)); + total_cache -= coins_db; + coins = total_cache; // the rest goes to the coins cache + } +}; +} // namespace kernel + +#endif // BITCOIN_KERNEL_CACHES_H diff --git a/src/node/caches.cpp b/src/node/caches.cpp index 01b08e320d..d930f38605 100644 --- a/src/node/caches.cpp +++ b/src/node/caches.cpp @@ -6,16 +6,18 @@ #include #include +#include #include +#include +#include + namespace node { CacheSizes CalculateCacheSizes(const ArgsManager& args, size_t n_indexes) { int64_t nTotalCache = (args.GetIntArg("-dbcache", nDefaultDbCache) << 20); nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache - CacheSizes sizes; - sizes.block_tree_db = std::min(nTotalCache / 8, nMaxBlockDBCache << 20); - nTotalCache -= sizes.block_tree_db; + IndexCacheSizes sizes; sizes.tx_index = std::min(nTotalCache / 8, args.GetBoolArg("-txindex", DEFAULT_TXINDEX) ? nMaxTxIndexCache << 20 : 0); nTotalCache -= sizes.tx_index; sizes.filter_index = 0; @@ -24,9 +26,6 @@ CacheSizes CalculateCacheSizes(const ArgsManager& args, size_t n_indexes) sizes.filter_index = max_cache / n_indexes; nTotalCache -= sizes.filter_index * n_indexes; } - sizes.coins_db = std::min(nTotalCache / 2, nMaxCoinsDBCache << 20); - nTotalCache -= sizes.coins_db; - sizes.coins = nTotalCache; // the rest goes to in-memory cache - return sizes; + return {sizes, kernel::CacheSizes{static_cast(nTotalCache)}}; } } // namespace node diff --git a/src/node/caches.h b/src/node/caches.h index 67388b91fd..3d8679553a 100644 --- a/src/node/caches.h +++ b/src/node/caches.h @@ -5,19 +5,22 @@ #ifndef BITCOIN_NODE_CACHES_H #define BITCOIN_NODE_CACHES_H +#include + #include #include class ArgsManager; namespace node { -struct CacheSizes { - int64_t block_tree_db; - int64_t coins_db; - int64_t coins; +struct IndexCacheSizes { int64_t tx_index; int64_t filter_index; }; +struct CacheSizes { + IndexCacheSizes index; + kernel::CacheSizes kernel; +}; CacheSizes CalculateCacheSizes(const ArgsManager& args, size_t n_indexes = 0); } // namespace node diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp index e56896fb22..660d2c3289 100644 --- a/src/node/chainstate.cpp +++ b/src/node/chainstate.cpp @@ -8,9 +8,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -29,6 +29,8 @@ #include #include +using kernel::CacheSizes; + namespace node { // Complete initialization of chainstates after the initial call has been made // to ChainstateManager::InitializeChainstate(). diff --git a/src/node/chainstate.h b/src/node/chainstate.h index bb0c4f2b87..ce414fa043 100644 --- a/src/node/chainstate.h +++ b/src/node/chainstate.h @@ -14,9 +14,11 @@ class CTxMemPool; -namespace node { - +namespace kernel { struct CacheSizes; +} // namespace kernel + +namespace node { struct ChainstateLoadOptions { CTxMemPool* mempool{nullptr}; @@ -69,7 +71,7 @@ using ChainstateLoadResult = std::tuple; * * LoadChainstate returns a (status code, error string) tuple. */ -ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSizes& cache_sizes, +ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const kernel::CacheSizes& cache_sizes, const ChainstateLoadOptions& options); ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager& chainman, const ChainstateLoadOptions& options); } // namespace node diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 12feba09a5..5ede59b82a 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -66,7 +66,6 @@ using kernel::BlockTreeDB; using node::ApplyArgsManOptions; using node::BlockAssembler; using node::BlockManager; -using node::CalculateCacheSizes; using node::KernelNotifications; using node::LoadChainstate; using node::RegenerateCommitments; @@ -228,8 +227,6 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, TestOpts opts) Assert(error.empty()); m_node.warnings = std::make_unique(); - m_cache_sizes = CalculateCacheSizes(m_args); - m_node.notifications = std::make_unique(Assert(m_node.shutdown_request), m_node.exit_status, *Assert(m_node.warnings)); m_make_chainman = [this, &chainparams, opts] { @@ -255,7 +252,7 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, TestOpts opts) LOCK(m_node.chainman->GetMutex()); m_node.chainman->m_blockman.m_block_tree_db = std::make_unique(DBParams{ .path = m_args.GetDataDirNet() / "blocks" / "index", - .cache_bytes = static_cast(m_cache_sizes.block_tree_db), + .cache_bytes = static_cast(m_kernel_cache_sizes.block_tree_db), .memory_only = true, }); }; @@ -291,7 +288,7 @@ void ChainTestingSetup::LoadVerifyActivateChainstate() options.check_blocks = m_args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS); options.check_level = m_args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL); options.require_full_verification = m_args.IsArgSet("-checkblocks") || m_args.IsArgSet("-checklevel"); - auto [status, error] = LoadChainstate(chainman, m_cache_sizes, options); + auto [status, error] = LoadChainstate(chainman, m_kernel_cache_sizes, options); assert(status == node::ChainstateLoadStatus::SUCCESS); std::tie(status, error) = VerifyLoadedChainstate(chainman, options); diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h index b0f7bdade2..33ad258457 100644 --- a/src/test/util/setup_common.h +++ b/src/test/util/setup_common.h @@ -6,6 +6,7 @@ #define BITCOIN_TEST_UTIL_SETUP_COMMON_H #include // IWYU pragma: export +#include #include #include #include @@ -103,7 +104,7 @@ struct BasicTestingSetup { * initialization behaviour. */ struct ChainTestingSetup : public BasicTestingSetup { - node::CacheSizes m_cache_sizes{}; + kernel::CacheSizes m_kernel_cache_sizes{node::CalculateCacheSizes(m_args).kernel}; bool m_coins_db_in_memory{true}; bool m_block_tree_db_in_memory{true}; std::function m_make_chainman{};