Skip to content

Commit 601a6a6

Browse files
committed
Merge bitcoin#30965: kernel: Move block tree db open to block manager
0cdddeb kernel: Move block tree db open to BlockManager constructor (TheCharlatan) 7fbb1bc kernel: Move block tree db open to block manager (TheCharlatan) 57ba59c refactor: Remove redundant reindex check (TheCharlatan) Pull request description: 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. ACKs for top commit: maflcko: re-ACK 0cdddeb 🏪 achow101: ACK 0cdddeb mzumsande: re-ACK 0cdddeb Tree-SHA512: fe3d557a725367e549e6a0659f64259cfef6aaa565ec867d9a177be0143ff18a2c4a20dd57e35e15f97cf870df476d88c05b03b6a7d9e8d51c568d9eda8947ef
2 parents eaf4b92 + 0cdddeb commit 601a6a6

12 files changed

+70
-58
lines changed

src/bitcoin-chainstate.cpp

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

109+
kernel::CacheSizes cache_sizes{DEFAULT_KERNEL_CACHE};
109110

110111
// SETUP: Chainstate
111112
auto chainparams = CChainParams::Main();
@@ -119,11 +120,14 @@ int main(int argc, char* argv[])
119120
.chainparams = chainman_opts.chainparams,
120121
.blocks_dir = abs_datadir / "blocks",
121122
.notifications = chainman_opts.notifications,
123+
.block_tree_db_params = DBParams{
124+
.path = abs_datadir / "blocks" / "index",
125+
.cache_bytes = cache_sizes.block_tree_db,
126+
},
122127
};
123128
util::SignalInterrupt interrupt;
124129
ChainstateManager chainman{interrupt, chainman_opts, blockman_opts};
125130

126-
kernel::CacheSizes cache_sizes{DEFAULT_KERNEL_CACHE};
127131
node::ChainstateLoadOptions options;
128132
auto [status, error] = node::LoadChainstate(chainman, cache_sizes, options);
129133
if (status != node::ChainstateLoadStatus::SUCCESS) {

src/init.cpp

+19-1
Original file line numberDiff line numberDiff line change
@@ -1057,6 +1057,10 @@ bool AppInitParameterInteraction(const ArgsManager& args)
10571057
.chainparams = chainman_opts_dummy.chainparams,
10581058
.blocks_dir = args.GetBlocksDirPath(),
10591059
.notifications = chainman_opts_dummy.notifications,
1060+
.block_tree_db_params = DBParams{
1061+
.path = args.GetDataDirNet() / "blocks" / "index",
1062+
.cache_bytes = 0,
1063+
},
10601064
};
10611065
auto blockman_result{ApplyArgsManOptions(args, blockman_opts_dummy)};
10621066
if (!blockman_result) {
@@ -1203,18 +1207,33 @@ static ChainstateLoadResult InitAndLoadChainstate(
12031207
.signals = node.validation_signals.get(),
12041208
};
12051209
Assert(ApplyArgsManOptions(args, chainman_opts)); // no error can happen, already checked in AppInitParameterInteraction
1210+
12061211
BlockManager::Options blockman_opts{
12071212
.chainparams = chainman_opts.chainparams,
12081213
.blocks_dir = args.GetBlocksDirPath(),
12091214
.notifications = chainman_opts.notifications,
1215+
.block_tree_db_params = DBParams{
1216+
.path = args.GetDataDirNet() / "blocks" / "index",
1217+
.cache_bytes = cache_sizes.block_tree_db,
1218+
.wipe_data = do_reindex,
1219+
},
12101220
};
12111221
Assert(ApplyArgsManOptions(args, blockman_opts)); // no error can happen, already checked in AppInitParameterInteraction
1222+
1223+
// Creating the chainstate manager internally creates a BlockManager, opens
1224+
// the blocks tree db, and wipes existing block files in case of a reindex.
1225+
// The coinsdb is opened at a later point on LoadChainstate.
12121226
try {
12131227
node.chainman = std::make_unique<ChainstateManager>(*Assert(node.shutdown_signal), chainman_opts, blockman_opts);
1228+
} catch (dbwrapper_error& e) {
1229+
LogError("%s", e.what());
1230+
return {ChainstateLoadStatus::FAILURE, _("Error opening block database")};
12141231
} catch (std::exception& e) {
12151232
return {ChainstateLoadStatus::FAILURE_FATAL, Untranslated(strprintf("Failed to initialize ChainstateManager: %s", e.what()))};
12161233
}
12171234
ChainstateManager& chainman = *node.chainman;
1235+
if (chainman.m_interrupt) return {ChainstateLoadStatus::INTERRUPTED, {}};
1236+
12181237
// This is defined and set here instead of inline in validation.h to avoid a hard
12191238
// dependency between validation and index/base, since the latter is not in
12201239
// libbitcoinkernel.
@@ -1237,7 +1256,6 @@ static ChainstateLoadResult InitAndLoadChainstate(
12371256
};
12381257
node::ChainstateLoadOptions options;
12391258
options.mempool = Assert(node.mempool.get());
1240-
options.wipe_block_tree_db = do_reindex;
12411259
options.wipe_chainstate_db = do_reindex || do_reindex_chainstate;
12421260
options.prune = chainman.m_blockman.IsPruneMode();
12431261
options.check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);

src/kernel/blockmanager_opts.h

+2
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,7 @@ struct BlockManagerOpts {
2728
bool fast_prune{false};
2829
const fs::path blocks_dir;
2930
Notifications& notifications;
31+
DBParams block_tree_db_params;
3032
};
3133

3234
} // 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_params.options);
39+
3740
return {};
3841
}
3942
} // namespace node

src/node/blockstorage.cpp

+14-1
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>
@@ -1169,7 +1170,19 @@ BlockManager::BlockManager(const util::SignalInterrupt& interrupt, Options opts)
11691170
m_opts{std::move(opts)},
11701171
m_block_file_seq{FlatFileSeq{m_opts.blocks_dir, "blk", m_opts.fast_prune ? 0x4000 /* 16kB */ : BLOCKFILE_CHUNK_SIZE}},
11711172
m_undo_file_seq{FlatFileSeq{m_opts.blocks_dir, "rev", UNDOFILE_CHUNK_SIZE}},
1172-
m_interrupt{interrupt} {}
1173+
m_interrupt{interrupt}
1174+
{
1175+
m_block_tree_db = std::make_unique<BlockTreeDB>(m_opts.block_tree_db_params);
1176+
1177+
if (m_opts.block_tree_db_params.wipe_data) {
1178+
m_block_tree_db->WriteReindexing(true);
1179+
m_blockfiles_indexed = false;
1180+
// If we're reindexing in prune mode, wipe away unusable block files and all undo data files
1181+
if (m_prune_mode) {
1182+
CleanupBlockRevFiles();
1183+
}
1184+
}
1185+
}
11731186

11741187
class ImportingNow
11751188
{

src/node/chainstate.cpp

+8-39
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,7 @@
2323
#include <validation.h>
2424

2525
#include <algorithm>
26-
#include <atomic>
2726
#include <cassert>
28-
#include <limits>
29-
#include <memory>
3027
#include <vector>
3128

3229
using kernel::CacheSizes;
@@ -36,34 +33,8 @@ namespace node {
3633
// to ChainstateManager::InitializeChainstate().
3734
static ChainstateLoadResult CompleteChainstateInitialization(
3835
ChainstateManager& chainman,
39-
const CacheSizes& cache_sizes,
4036
const ChainstateLoadOptions& options) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
4137
{
42-
auto& pblocktree{chainman.m_blockman.m_block_tree_db};
43-
// new BlockTreeDB tries to delete the existing file, which
44-
// fails if it's still open from the previous loop. Close it first:
45-
pblocktree.reset();
46-
try {
47-
pblocktree = std::make_unique<BlockTreeDB>(DBParams{
48-
.path = chainman.m_options.datadir / "blocks" / "index",
49-
.cache_bytes = cache_sizes.block_tree_db,
50-
.memory_only = options.block_tree_db_in_memory,
51-
.wipe_data = options.wipe_block_tree_db,
52-
.options = chainman.m_options.block_tree_db});
53-
} catch (dbwrapper_error& err) {
54-
LogError("%s\n", err.what());
55-
return {ChainstateLoadStatus::FAILURE, _("Error opening block database")};
56-
}
57-
58-
if (options.wipe_block_tree_db) {
59-
pblocktree->WriteReindexing(true);
60-
chainman.m_blockman.m_blockfiles_indexed = false;
61-
//If we're reindexing in prune mode, wipe away unusable block files and all undo data files
62-
if (options.prune) {
63-
chainman.m_blockman.CleanupBlockRevFiles();
64-
}
65-
}
66-
6738
if (chainman.m_interrupt) return {ChainstateLoadStatus::INTERRUPTED, {}};
6839

6940
// LoadBlockIndex will load m_have_pruned if we've ever removed a
@@ -155,14 +126,12 @@ static ChainstateLoadResult CompleteChainstateInitialization(
155126
}
156127
}
157128

158-
if (!options.wipe_block_tree_db) {
159-
auto chainstates{chainman.GetAll()};
160-
if (std::any_of(chainstates.begin(), chainstates.end(),
161-
[](const Chainstate* cs) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return cs->NeedsRedownload(); })) {
162-
return {ChainstateLoadStatus::FAILURE, strprintf(_("Witness data for blocks after height %d requires validation. Please restart with -reindex."),
163-
chainman.GetConsensus().SegwitHeight)};
164-
};
165-
}
129+
auto chainstates{chainman.GetAll()};
130+
if (std::any_of(chainstates.begin(), chainstates.end(),
131+
[](const Chainstate* cs) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return cs->NeedsRedownload(); })) {
132+
return {ChainstateLoadStatus::FAILURE, strprintf(_("Witness data for blocks after height %d requires validation. Please restart with -reindex."),
133+
chainman.GetConsensus().SegwitHeight)};
134+
};
166135

167136
// Now that chainstates are loaded and we're able to flush to
168137
// disk, rebalance the coins caches to desired levels based
@@ -208,7 +177,7 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize
208177
}
209178
}
210179

211-
auto [init_status, init_error] = CompleteChainstateInitialization(chainman, cache_sizes, options);
180+
auto [init_status, init_error] = CompleteChainstateInitialization(chainman, options);
212181
if (init_status != ChainstateLoadStatus::SUCCESS) {
213182
return {init_status, init_error};
214183
}
@@ -244,7 +213,7 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize
244213
// for the fully validated chainstate.
245214
chainman.ActiveChainstate().ClearBlockIndexCandidates();
246215

247-
auto [init_status, init_error] = CompleteChainstateInitialization(chainman, cache_sizes, options);
216+
auto [init_status, init_error] = CompleteChainstateInitialization(chainman, options);
248217
if (init_status != ChainstateLoadStatus::SUCCESS) {
249218
return {init_status, init_error};
250219
}

src/node/chainstate.h

-5
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,7 @@ namespace node {
2222

2323
struct ChainstateLoadOptions {
2424
CTxMemPool* mempool{nullptr};
25-
bool block_tree_db_in_memory{false};
2625
bool coins_db_in_memory{false};
27-
// Whether to wipe the block tree database when loading it. If set, this
28-
// will also set a reindexing flag so any existing block data files will be
29-
// scanned and added to the database.
30-
bool wipe_block_tree_db{false};
3126
// Whether to wipe the chainstate database when loading it. If set, this
3227
// will cause the chainstate database to be rebuilt starting from genesis.
3328
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

+8
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ BOOST_AUTO_TEST_CASE(blockmanager_find_block_pos)
3333
.chainparams = *params,
3434
.blocks_dir = m_args.GetBlocksDirPath(),
3535
.notifications = notifications,
36+
.block_tree_db_params = DBParams{
37+
.path = m_args.GetDataDirNet() / "blocks" / "index",
38+
.cache_bytes = 0,
39+
},
3640
};
3741
BlockManager blockman{*Assert(m_node.shutdown_signal), blockman_opts};
3842
// simulate adding a genesis block normally
@@ -140,6 +144,10 @@ BOOST_AUTO_TEST_CASE(blockmanager_flush_block_file)
140144
.chainparams = Params(),
141145
.blocks_dir = m_args.GetBlocksDirPath(),
142146
.notifications = notifications,
147+
.block_tree_db_params = DBParams{
148+
.path = m_args.GetDataDirNet() / "blocks" / "index",
149+
.cache_bytes = 0,
150+
},
143151
};
144152
BlockManager blockman{*Assert(m_node.shutdown_signal), blockman_opts};
145153

src/test/util/setup_common.cpp

+6-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;
@@ -252,14 +251,14 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, TestOpts opts)
252251
.chainparams = chainman_opts.chainparams,
253252
.blocks_dir = m_args.GetBlocksDirPath(),
254253
.notifications = chainman_opts.notifications,
254+
.block_tree_db_params = DBParams{
255+
.path = m_args.GetDataDirNet() / "blocks" / "index",
256+
.cache_bytes = m_kernel_cache_sizes.block_tree_db,
257+
.memory_only = opts.block_tree_db_in_memory,
258+
.wipe_data = m_args.GetBoolArg("-reindex", false),
259+
},
255260
};
256261
m_node.chainman = std::make_unique<ChainstateManager>(*Assert(m_node.shutdown_signal), chainman_opts, blockman_opts);
257-
LOCK(m_node.chainman->GetMutex());
258-
m_node.chainman->m_blockman.m_block_tree_db = std::make_unique<BlockTreeDB>(DBParams{
259-
.path = m_args.GetDataDirNet() / "blocks" / "index",
260-
.cache_bytes = m_kernel_cache_sizes.block_tree_db,
261-
.memory_only = true,
262-
});
263262
};
264263
m_make_chainman();
265264
}
@@ -285,9 +284,7 @@ void ChainTestingSetup::LoadVerifyActivateChainstate()
285284
auto& chainman{*Assert(m_node.chainman)};
286285
node::ChainstateLoadOptions options;
287286
options.mempool = Assert(m_node.mempool.get());
288-
options.block_tree_db_in_memory = m_block_tree_db_in_memory;
289287
options.coins_db_in_memory = m_coins_db_in_memory;
290-
options.wipe_block_tree_db = m_args.GetBoolArg("-reindex", false);
291288
options.wipe_chainstate_db = m_args.GetBoolArg("-reindex", false) || m_args.GetBoolArg("-reindex-chainstate", false);
292289
options.prune = chainman.m_blockman.IsPruneMode();
293290
options.check_blocks = m_args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);

src/test/validation_chainstatemanager_tests.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,11 @@ struct SnapshotTestSetup : TestChain100Setup {
393393
.chainparams = chainman_opts.chainparams,
394394
.blocks_dir = m_args.GetBlocksDirPath(),
395395
.notifications = chainman_opts.notifications,
396+
.block_tree_db_params = DBParams{
397+
.path = chainman.m_options.datadir / "blocks" / "index",
398+
.cache_bytes = m_kernel_cache_sizes.block_tree_db,
399+
.memory_only = m_block_tree_db_in_memory,
400+
},
396401
};
397402
// For robustness, ensure the old manager is destroyed before creating a
398403
// new one.

0 commit comments

Comments
 (0)