mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-09 11:27:28 -03:00
init: Use size_t consistently for cache sizes
This avoids having to rely on implicit casts when passing them to the various functions allocating the caches. This also fixes a bug where an incorrect amount of memory was allocated on 32bit platforms. If the db cache size exceeded the maximum size of a 32 bit unsigned integer, it would overflow and allocate much less memory than instructed to. Fix this by returning an error to the user if the passed in dbcache size exceeeds the size of a size_t on that platform. Add a release note for the change in behaviour on 32-bit systems. Also take this opportunity to make the total amounts of cache in the chainstate manager a size_t too.
This commit is contained in:
parent
1f81be60f5
commit
578654c686
8 changed files with 42 additions and 21 deletions
6
doc/release-notes-31483.md
Normal file
6
doc/release-notes-31483.md
Normal file
|
@ -0,0 +1,6 @@
|
|||
Updated settings
|
||||
------
|
||||
|
||||
- On 32-bit systems an error is returned on startup if the user passes a
|
||||
`-dbcache` value exceeding 4GiB.
|
||||
|
|
@ -1605,7 +1605,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
|||
ReadNotificationArgs(args, kernel_notifications);
|
||||
|
||||
// cache size calculations
|
||||
auto [index_cache_sizes, kernel_cache_sizes] = CalculateCacheSizes(args, g_enabled_filter_types.size());
|
||||
const auto cache_sizes = CalculateCacheSizes(args, g_enabled_filter_types.size());
|
||||
if (!cache_sizes) {
|
||||
return InitError(_("Failed to calculate cache sizes. Try lowering the -dbcache value."));
|
||||
}
|
||||
auto [index_cache_sizes, kernel_cache_sizes] = *cache_sizes;
|
||||
|
||||
LogInfo("Cache configuration:");
|
||||
LogInfo("* Using %.1f MiB for block index database", kernel_cache_sizes.block_tree_db * (1.0 / 1024 / 1024));
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
#include <common/args.h>
|
||||
#include <index/txindex.h>
|
||||
#include <kernel/caches.h>
|
||||
#include <logging.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
// Unlike for the UTXO database, for the txindex scenario the leveldb cache make
|
||||
|
@ -19,19 +21,27 @@ static constexpr int64_t MAX_TX_INDEX_CACHE{1024};
|
|||
static constexpr int64_t MAX_FILTER_INDEX_CACHE{1024};
|
||||
|
||||
namespace node {
|
||||
CacheSizes CalculateCacheSizes(const ArgsManager& args, size_t n_indexes)
|
||||
std::optional<CacheSizes> CalculateCacheSizes(const ArgsManager& args, size_t n_indexes)
|
||||
{
|
||||
int64_t nTotalCache = (args.GetIntArg("-dbcache", DEFAULT_DB_CACHE) << 20);
|
||||
nTotalCache = std::max(nTotalCache, MIN_DB_CACHE << 20);
|
||||
IndexCacheSizes sizes;
|
||||
sizes.tx_index = std::min(nTotalCache / 8, args.GetBoolArg("-txindex", DEFAULT_TXINDEX) ? MAX_TX_INDEX_CACHE << 20 : 0);
|
||||
nTotalCache -= sizes.tx_index;
|
||||
sizes.filter_index = 0;
|
||||
if (n_indexes > 0) {
|
||||
int64_t max_cache = std::min(nTotalCache / 8, MAX_FILTER_INDEX_CACHE << 20);
|
||||
sizes.filter_index = max_cache / n_indexes;
|
||||
nTotalCache -= sizes.filter_index * n_indexes;
|
||||
int64_t db_cache = args.GetIntArg("-dbcache", DEFAULT_DB_CACHE);
|
||||
if (static_cast<uint64_t>(db_cache << 20) > std::numeric_limits<size_t>::max()) {
|
||||
LogWarning("Cannot allocate more than %d MiB in total for db caches.", static_cast<double>(std::numeric_limits<size_t>::max()) * (1.0 / 1024 / 1024));
|
||||
return std::nullopt;
|
||||
}
|
||||
return {sizes, kernel::CacheSizes{static_cast<size_t>(nTotalCache)}};
|
||||
|
||||
// negative values are permitted, but interpreted as zero.
|
||||
db_cache = std::max(int64_t{0}, db_cache);
|
||||
size_t total_cache = std::max(MiBToBytes(db_cache), MiBToBytes(MIN_DB_CACHE));
|
||||
|
||||
IndexCacheSizes index_sizes;
|
||||
index_sizes.tx_index = std::min(total_cache / 8, args.GetBoolArg("-txindex", DEFAULT_TXINDEX) ? MiBToBytes(MAX_TX_INDEX_CACHE) : 0);
|
||||
total_cache -= index_sizes.tx_index;
|
||||
index_sizes.filter_index = 0;
|
||||
if (n_indexes > 0) {
|
||||
int64_t max_cache = std::min(total_cache / 8, MiBToBytes(MAX_FILTER_INDEX_CACHE));
|
||||
index_sizes.filter_index = max_cache / n_indexes;
|
||||
total_cache -= index_sizes.filter_index * n_indexes;
|
||||
}
|
||||
return {{index_sizes, kernel::CacheSizes{total_cache}}};
|
||||
}
|
||||
} // namespace node
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
class ArgsManager;
|
||||
|
||||
|
@ -19,14 +20,14 @@ static constexpr int64_t DEFAULT_DB_CACHE{DEFAULT_KERNEL_CACHE};
|
|||
|
||||
namespace node {
|
||||
struct IndexCacheSizes {
|
||||
int64_t tx_index;
|
||||
int64_t filter_index;
|
||||
size_t tx_index;
|
||||
size_t filter_index;
|
||||
};
|
||||
struct CacheSizes {
|
||||
IndexCacheSizes index;
|
||||
kernel::CacheSizes kernel;
|
||||
};
|
||||
CacheSizes CalculateCacheSizes(const ArgsManager& args, size_t n_indexes = 0);
|
||||
std::optional<CacheSizes> CalculateCacheSizes(const ArgsManager& args, size_t n_indexes = 0);
|
||||
} // namespace node
|
||||
|
||||
#endif // BITCOIN_NODE_CACHES_H
|
||||
|
|
|
@ -46,7 +46,7 @@ static ChainstateLoadResult CompleteChainstateInitialization(
|
|||
try {
|
||||
pblocktree = std::make_unique<BlockTreeDB>(DBParams{
|
||||
.path = chainman.m_options.datadir / "blocks" / "index",
|
||||
.cache_bytes = static_cast<size_t>(cache_sizes.block_tree_db),
|
||||
.cache_bytes = cache_sizes.block_tree_db,
|
||||
.memory_only = options.block_tree_db_in_memory,
|
||||
.wipe_data = options.wipe_block_tree_db,
|
||||
.options = chainman.m_options.block_tree_db});
|
||||
|
|
|
@ -252,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<BlockTreeDB>(DBParams{
|
||||
.path = m_args.GetDataDirNet() / "blocks" / "index",
|
||||
.cache_bytes = static_cast<size_t>(m_kernel_cache_sizes.block_tree_db),
|
||||
.cache_bytes = m_kernel_cache_sizes.block_tree_db,
|
||||
.memory_only = true,
|
||||
});
|
||||
};
|
||||
|
|
|
@ -104,7 +104,7 @@ struct BasicTestingSetup {
|
|||
* initialization behaviour.
|
||||
*/
|
||||
struct ChainTestingSetup : public BasicTestingSetup {
|
||||
kernel::CacheSizes m_kernel_cache_sizes{node::CalculateCacheSizes(m_args).kernel};
|
||||
kernel::CacheSizes m_kernel_cache_sizes{node::CalculateCacheSizes(m_args).value().kernel};
|
||||
bool m_coins_db_in_memory{true};
|
||||
bool m_block_tree_db_in_memory{true};
|
||||
std::function<void()> m_make_chainman{};
|
||||
|
|
|
@ -1067,11 +1067,11 @@ public:
|
|||
|
||||
//! The total number of bytes available for us to use across all in-memory
|
||||
//! coins caches. This will be split somehow across chainstates.
|
||||
int64_t m_total_coinstip_cache{0};
|
||||
size_t m_total_coinstip_cache{0};
|
||||
//
|
||||
//! The total number of bytes available for us to use across all leveldb
|
||||
//! coins databases. This will be split somehow across chainstates.
|
||||
int64_t m_total_coinsdb_cache{0};
|
||||
size_t m_total_coinsdb_cache{0};
|
||||
|
||||
//! Instantiate a new chainstate.
|
||||
//!
|
||||
|
|
Loading…
Reference in a new issue