Skip to content

Commit 85895b8

Browse files
TheCharlatanjosibake
authored andcommitted
kernel: Move block tree db open to block manager
Before this change the block tree db was needlessly re-opened during startup when loading a completed snapshot. Improve this by letting the block manager open it on construction. This also simplifies the test code a bit. The change was initially motivated to make it easier for users of the kernel library to instantiate a BlockManager that may be used to read data from disk without loading the block index into a cache.
1 parent e9d60af commit 85895b8

14 files changed

+60
-48
lines changed

src/bitcoin-chainstate.cpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ int main(int argc, char* argv[])
106106
};
107107
auto notifications = std::make_unique<KernelNotifications>();
108108

109+
node::CacheSizes cache_sizes;
110+
cache_sizes.block_tree_db = 2 << 20;
111+
cache_sizes.coins_db = 2 << 22;
112+
cache_sizes.coins = (450 << 20) - (2 << 20) - (2 << 22);
109113

110114
// SETUP: Chainstate
111115
auto chainparams = CChainParams::Main();
@@ -119,14 +123,12 @@ int main(int argc, char* argv[])
119123
.chainparams = chainman_opts.chainparams,
120124
.blocks_dir = abs_datadir / "blocks",
121125
.notifications = chainman_opts.notifications,
126+
.block_tree_db_dir = abs_datadir / "blocks" / "index",
127+
.block_tree_db_cache_size = 2 << 20,
122128
};
123129
util::SignalInterrupt interrupt;
124130
ChainstateManager chainman{interrupt, chainman_opts, blockman_opts};
125131

126-
node::CacheSizes cache_sizes;
127-
cache_sizes.block_tree_db = 2 << 20;
128-
cache_sizes.coins_db = 2 << 22;
129-
cache_sizes.coins = (450 << 20) - (2 << 20) - (2 << 22);
130132
node::ChainstateLoadOptions options;
131133
auto [status, error] = node::LoadChainstate(chainman, cache_sizes, options);
132134
if (status != node::ChainstateLoadStatus::SUCCESS) {

src/init.cpp

+8-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// Distributed under the MIT software license, see the accompanying
44
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
55

6+
#include "dbwrapper.h"
67
#include <config/bitcoin-config.h> // IWYU pragma: keep
78

89
#include <init.h>
@@ -1069,6 +1070,8 @@ bool AppInitParameterInteraction(const ArgsManager& args)
10691070
.chainparams = chainman_opts_dummy.chainparams,
10701071
.blocks_dir = args.GetBlocksDirPath(),
10711072
.notifications = chainman_opts_dummy.notifications,
1073+
.block_tree_db_dir = args.GetDataDirNet() / "blocks" / "index",
1074+
.block_tree_db_cache_size = 0,
10721075
};
10731076
auto blockman_result{ApplyArgsManOptions(args, blockman_opts_dummy)};
10741077
if (!blockman_result) {
@@ -1217,10 +1220,15 @@ static ChainstateLoadResult InitAndLoadChainstate(
12171220
.chainparams = chainman_opts.chainparams,
12181221
.blocks_dir = args.GetBlocksDirPath(),
12191222
.notifications = chainman_opts.notifications,
1223+
.block_tree_db_dir = args.GetDataDirNet() / "blocks" / "index",
1224+
.wipe_block_tree_db = do_reindex,
1225+
.block_tree_db_cache_size = cache_sizes.block_tree_db,
12201226
};
12211227
Assert(ApplyArgsManOptions(args, blockman_opts)); // no error can happen, already checked in AppInitParameterInteraction
12221228
try {
12231229
node.chainman = std::make_unique<ChainstateManager>(*Assert(node.shutdown), chainman_opts, blockman_opts);
1230+
} catch (dbwrapper_error&) {
1231+
return {ChainstateLoadStatus::FAILURE, strprintf(Untranslated("Error opening block database."))};
12241232
} catch (std::exception& e) {
12251233
return {ChainstateLoadStatus::FAILURE_FATAL, strprintf(Untranslated("Failed to initialize ChainstateManager: %s"), e.what())};
12261234
}
@@ -1247,7 +1255,6 @@ static ChainstateLoadResult InitAndLoadChainstate(
12471255
};
12481256
node::ChainstateLoadOptions options;
12491257
options.mempool = Assert(node.mempool.get());
1250-
options.wipe_block_tree_db = do_reindex;
12511258
options.wipe_chainstate_db = do_reindex || do_reindex_chainstate;
12521259
options.prune = chainman.m_blockman.IsPruneMode();
12531260
options.check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);

src/kernel/blockmanager_opts.h

+9
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#ifndef BITCOIN_KERNEL_BLOCKMANAGER_OPTS_H
66
#define BITCOIN_KERNEL_BLOCKMANAGER_OPTS_H
77

8+
#include <dbwrapper.h>
89
#include <kernel/notifications_interface.h>
910
#include <util/fs.h>
1011

@@ -27,6 +28,14 @@ struct BlockManagerOpts {
2728
bool fast_prune{false};
2829
const fs::path blocks_dir;
2930
Notifications& notifications;
31+
const fs::path block_tree_db_dir;
32+
// Whether to wipe the block tree database when loading it. If set, this
33+
// will also set a reindexing flag so any existing block data files will be
34+
// scanned and added to the database.
35+
bool wipe_block_tree_db{false};
36+
bool block_tree_db_in_memory{false};
37+
DBOptions block_tree_db_options{};
38+
int64_t block_tree_db_cache_size;
3039
};
3140

3241
} // namespace kernel

src/kernel/chainstatemanager_opts.h

-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ struct ChainstateManagerOpts {
4242
std::optional<uint256> assumed_valid_block{};
4343
//! If the tip is older than this, the node is considered to be in initial block download.
4444
std::chrono::seconds max_tip_age{DEFAULT_MAX_TIP_AGE};
45-
DBOptions block_tree_db{};
4645
DBOptions coins_db{};
4746
CoinsViewOptions coins_view{};
4847
Notifications& notifications;

src/node/blockmanager_args.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <common/args.h>
88
#include <node/blockstorage.h>
9+
#include <node/database_args.h>
910
#include <tinyformat.h>
1011
#include <util/result.h>
1112
#include <util/translation.h>
@@ -34,6 +35,8 @@ util::Result<void> ApplyArgsManOptions(const ArgsManager& args, BlockManager::Op
3435

3536
if (auto value{args.GetBoolArg("-fastprune")}) opts.fast_prune = *value;
3637

38+
ReadDatabaseArgs(args, opts.block_tree_db_options);
39+
3740
return {};
3841
}
3942
} // namespace node

src/node/blockstorage.cpp

+21-3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include <util/translation.h>
3737
#include <validation.h>
3838

39+
#include <cstddef>
3940
#include <map>
4041
#include <ranges>
4142
#include <unordered_map>
@@ -1180,10 +1181,27 @@ static auto InitBlocksdirXorKey(const BlockManager::Options& opts)
11801181
BlockManager::BlockManager(const util::SignalInterrupt& interrupt, Options opts)
11811182
: m_prune_mode{opts.prune_target > 0},
11821183
m_xor_key{InitBlocksdirXorKey(opts)},
1184+
m_block_file_seq{FlatFileSeq{opts.blocks_dir, "blk", opts.fast_prune ? 0x4000 /* 16kB */ : BLOCKFILE_CHUNK_SIZE}},
1185+
m_undo_file_seq{FlatFileSeq{opts.blocks_dir, "rev", UNDOFILE_CHUNK_SIZE}},
11831186
m_opts{std::move(opts)},
1184-
m_block_file_seq{FlatFileSeq{m_opts.blocks_dir, "blk", m_opts.fast_prune ? 0x4000 /* 16kB */ : BLOCKFILE_CHUNK_SIZE}},
1185-
m_undo_file_seq{FlatFileSeq{m_opts.blocks_dir, "rev", UNDOFILE_CHUNK_SIZE}},
1186-
m_interrupt{interrupt} {}
1187+
m_interrupt{interrupt}
1188+
{
1189+
m_block_tree_db = std::make_unique<BlockTreeDB>(DBParams{
1190+
.path = m_opts.block_tree_db_dir,
1191+
.cache_bytes = static_cast<size_t>(m_opts.block_tree_db_cache_size),
1192+
.memory_only = m_opts.block_tree_db_in_memory,
1193+
.wipe_data = m_opts.wipe_block_tree_db,
1194+
.options = m_opts.block_tree_db_options});
1195+
1196+
if (m_opts.wipe_block_tree_db) {
1197+
m_block_tree_db->WriteReindexing(true);
1198+
m_blockfiles_indexed = false;
1199+
// If we're reindexing in prune mode, wipe away unusable block files and all undo data files
1200+
if (m_prune_mode) {
1201+
CleanupBlockRevFiles();
1202+
}
1203+
}
1204+
}
11871205

11881206
class ImportingNow
11891207
{

src/node/blockstorage.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -259,8 +259,6 @@ class BlockManager
259259

260260
BlockfileType BlockfileTypeForHeight(int height);
261261

262-
const kernel::BlockManagerOpts m_opts;
263-
264262
const FlatFileSeq m_block_file_seq;
265263
const FlatFileSeq m_undo_file_seq;
266264

@@ -269,6 +267,7 @@ class BlockManager
269267

270268
explicit BlockManager(const util::SignalInterrupt& interrupt, Options opts);
271269

270+
const kernel::BlockManagerOpts m_opts;
272271
const util::SignalInterrupt& m_interrupt;
273272
std::atomic<bool> m_importing{false};
274273

src/node/chainstate.cpp

+1-21
Original file line numberDiff line numberDiff line change
@@ -37,26 +37,6 @@ static ChainstateLoadResult CompleteChainstateInitialization(
3737
const CacheSizes& cache_sizes,
3838
const ChainstateLoadOptions& options) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
3939
{
40-
auto& pblocktree{chainman.m_blockman.m_block_tree_db};
41-
// new BlockTreeDB tries to delete the existing file, which
42-
// fails if it's still open from the previous loop. Close it first:
43-
pblocktree.reset();
44-
pblocktree = std::make_unique<BlockTreeDB>(DBParams{
45-
.path = chainman.m_options.datadir / "blocks" / "index",
46-
.cache_bytes = static_cast<size_t>(cache_sizes.block_tree_db),
47-
.memory_only = options.block_tree_db_in_memory,
48-
.wipe_data = options.wipe_block_tree_db,
49-
.options = chainman.m_options.block_tree_db});
50-
51-
if (options.wipe_block_tree_db) {
52-
pblocktree->WriteReindexing(true);
53-
chainman.m_blockman.m_blockfiles_indexed = false;
54-
//If we're reindexing in prune mode, wipe away unusable block files and all undo data files
55-
if (options.prune) {
56-
chainman.m_blockman.CleanupBlockRevFiles();
57-
}
58-
}
59-
6040
if (chainman.m_interrupt) return {ChainstateLoadStatus::INTERRUPTED, {}};
6141

6242
// LoadBlockIndex will load m_have_pruned if we've ever removed a
@@ -142,7 +122,7 @@ static ChainstateLoadResult CompleteChainstateInitialization(
142122
}
143123
}
144124

145-
if (!options.wipe_block_tree_db) {
125+
if (!chainman.m_blockman.m_opts.wipe_block_tree_db) {
146126
auto chainstates{chainman.GetAll()};
147127
if (std::any_of(chainstates.begin(), chainstates.end(),
148128
[](const Chainstate* cs) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return cs->NeedsRedownload(); })) {

src/node/chainstate.h

-5
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,7 @@ struct CacheSizes;
2020

2121
struct ChainstateLoadOptions {
2222
CTxMemPool* mempool{nullptr};
23-
bool block_tree_db_in_memory{false};
2423
bool coins_db_in_memory{false};
25-
// Whether to wipe the block tree database when loading it. If set, this
26-
// will also set a reindexing flag so any existing block data files will be
27-
// scanned and added to the database.
28-
bool wipe_block_tree_db{false};
2924
// Whether to wipe the chainstate database when loading it. If set, this
3025
// will cause the chainstate database to be rebuilt starting from genesis.
3126
bool wipe_chainstate_db{false};

src/node/chainstatemanager_args.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ util::Result<void> ApplyArgsManOptions(const ArgsManager& args, ChainstateManage
4949

5050
if (auto value{args.GetIntArg("-maxtipage")}) opts.max_tip_age = std::chrono::seconds{*value};
5151

52-
ReadDatabaseArgs(args, opts.block_tree_db);
5352
ReadDatabaseArgs(args, opts.coins_db);
5453
ReadCoinsViewArgs(args, opts.coins_view);
5554

src/test/blockmanager_tests.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ BOOST_AUTO_TEST_CASE(blockmanager_find_block_pos)
3333
.chainparams = *params,
3434
.blocks_dir = m_args.GetBlocksDirPath(),
3535
.notifications = notifications,
36+
.block_tree_db_dir = m_args.GetDataDirNet() / "blocks" / "index",
37+
.block_tree_db_cache_size = 0,
3638
};
3739
BlockManager blockman{*Assert(m_node.shutdown), blockman_opts};
3840
// simulate adding a genesis block normally
@@ -140,6 +142,8 @@ BOOST_AUTO_TEST_CASE(blockmanager_flush_block_file)
140142
.chainparams = Params(),
141143
.blocks_dir = m_args.GetBlocksDirPath(),
142144
.notifications = notifications,
145+
.block_tree_db_dir = m_args.GetDataDirNet() / "blocks" / "index",
146+
.block_tree_db_cache_size = 0,
143147
};
144148
BlockManager blockman{*Assert(m_node.shutdown), blockman_opts};
145149

src/test/util/setup_common.cpp

+4-9
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@
6262
#include <stdexcept>
6363

6464
using namespace util::hex_literals;
65-
using kernel::BlockTreeDB;
6665
using node::ApplyArgsManOptions;
6766
using node::BlockAssembler;
6867
using node::BlockManager;
@@ -244,14 +243,13 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, TestOpts opts)
244243
.chainparams = chainman_opts.chainparams,
245244
.blocks_dir = m_args.GetBlocksDirPath(),
246245
.notifications = chainman_opts.notifications,
246+
.block_tree_db_dir = m_args.GetDataDirNet() / "blocks" / "index",
247+
.wipe_block_tree_db = m_args.GetBoolArg("-reindex", false),
248+
.block_tree_db_in_memory = opts.block_tree_db_in_memory,
249+
.block_tree_db_cache_size = m_cache_sizes.block_tree_db,
247250
};
248251
m_node.chainman = std::make_unique<ChainstateManager>(*Assert(m_node.shutdown), chainman_opts, blockman_opts);
249252
LOCK(m_node.chainman->GetMutex());
250-
m_node.chainman->m_blockman.m_block_tree_db = std::make_unique<BlockTreeDB>(DBParams{
251-
.path = m_args.GetDataDirNet() / "blocks" / "index",
252-
.cache_bytes = static_cast<size_t>(m_cache_sizes.block_tree_db),
253-
.memory_only = true,
254-
});
255253
};
256254
m_make_chainman();
257255
}
@@ -277,9 +275,7 @@ void ChainTestingSetup::LoadVerifyActivateChainstate()
277275
auto& chainman{*Assert(m_node.chainman)};
278276
node::ChainstateLoadOptions options;
279277
options.mempool = Assert(m_node.mempool.get());
280-
options.block_tree_db_in_memory = m_block_tree_db_in_memory;
281278
options.coins_db_in_memory = m_coins_db_in_memory;
282-
options.wipe_block_tree_db = m_args.GetBoolArg("-reindex", false);
283279
options.wipe_chainstate_db = m_args.GetBoolArg("-reindex", false) || m_args.GetBoolArg("-reindex-chainstate", false);
284280
options.prune = chainman.m_blockman.IsPruneMode();
285281
options.check_blocks = m_args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);
@@ -303,7 +299,6 @@ TestingSetup::TestingSetup(
303299
: ChainTestingSetup(chainType, opts)
304300
{
305301
m_coins_db_in_memory = opts.coins_db_in_memory;
306-
m_block_tree_db_in_memory = opts.block_tree_db_in_memory;
307302
// Ideally we'd move all the RPC tests to the functional testing framework
308303
// instead of unit tests, but for now we need these here.
309304
RegisterAllCoreRPCCommands(tableRPC);

src/test/util/setup_common.h

-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ struct BasicTestingSetup {
8585
struct ChainTestingSetup : public BasicTestingSetup {
8686
node::CacheSizes m_cache_sizes{};
8787
bool m_coins_db_in_memory{true};
88-
bool m_block_tree_db_in_memory{true};
8988
std::function<void()> m_make_chainman{};
9089

9190
explicit ChainTestingSetup(const ChainType chainType = ChainType::MAIN, TestOpts = {});

src/test/validation_chainstatemanager_tests.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,9 @@ struct SnapshotTestSetup : TestChain100Setup {
393393
.chainparams = chainman_opts.chainparams,
394394
.blocks_dir = m_args.GetBlocksDirPath(),
395395
.notifications = chainman_opts.notifications,
396+
.block_tree_db_dir = chainman.m_blockman.m_opts.block_tree_db_dir,
397+
.block_tree_db_in_memory = chainman.m_blockman.m_opts.block_tree_db_in_memory,
398+
.block_tree_db_cache_size = chainman.m_blockman.m_opts.block_tree_db_cache_size,
396399
};
397400
// For robustness, ensure the old manager is destroyed before creating a
398401
// new one.

0 commit comments

Comments
 (0)