Skip to content

Commit b1ba1b1

Browse files
committed
Merge bitcoin/bitcoin#30132: indexes: Don't wipe indexes again when continuing a prior reindex
f68cba2 blockman: Replace m_reindexing with m_blockfiles_indexed (Ryan Ofsky) 1b1c6dc test: Add functional test for continuing a reindex (TheCharlatan) 201c1a9 indexes: Don't wipe indexes again when already reindexing (TheCharlatan) 804f09d kernel: Add less confusing reindex options (Ryan Ofsky) e172553 validation: Remove needs_init from LoadBlockIndex (TheCharlatan) 533eab7 bugfix: Streamline setting reindex option (TheCharlatan) Pull request description: When restarting `bitcoind` during an ongoing reindex without setting the `-reindex` flag again, the block and coins db is left intact, but any data from the optional indexes is discarded. While not a bug per se, wiping the data again is wasteful, both in terms of having to write it again, as well as potentially leading to longer startup times. So keep the index data instead when continuing a prior reindex. Also includes a bugfix and smaller code cleanups around the reindexing code. The bug was introduced in b47bd95: "kernel: De-globalize fReindex". ACKs for top commit: stickies-v: ACK f68cba2 fjahr: Code review ACK f68cba2 furszy: Code review ACK f68cba2 ryanofsky: Code review ACK f68cba2. Only changes since last review were cherry-picking suggested commits that rename variables, improving comments, and making some tweaks to test code. Tree-SHA512: b252228cc76e9f1eaac56d5bd9e4eac23408e0fc04aeffd97a85417f046229364673ee1ca7410b9b6e7b692b03f13ece17c42a10176da0d7e975a8915deb98ca
2 parents cad1272 + f68cba2 commit b1ba1b1

File tree

12 files changed

+73
-62
lines changed

12 files changed

+73
-62
lines changed

src/bitcoin-chainstate.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ int main(int argc, char* argv[])
151151
{
152152
LOCK(chainman.GetMutex());
153153
std::cout
154-
<< "\t" << "Reindexing: " << std::boolalpha << chainman.m_blockman.m_reindexing.load() << std::noboolalpha << std::endl
154+
<< "\t" << "Blockfiles Indexed: " << std::boolalpha << chainman.m_blockman.m_blockfiles_indexed.load() << std::noboolalpha << std::endl
155155
<< "\t" << "Snapshot Active: " << std::boolalpha << chainman.IsSnapshotActive() << std::noboolalpha << std::endl
156156
<< "\t" << "Active Height: " << chainman.ActiveHeight() << std::endl
157157
<< "\t" << "Active IBD: " << std::boolalpha << chainman.IsInitialBlockDownload() << std::noboolalpha << std::endl;

src/init.cpp

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1482,7 +1482,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
14821482

14831483
node.notifications = std::make_unique<KernelNotifications>(*Assert(node.shutdown), node.exit_status);
14841484
ReadNotificationArgs(args, *node.notifications);
1485-
bool fReindexChainState = args.GetBoolArg("-reindex-chainstate", false);
14861485
ChainstateManager::Options chainman_opts{
14871486
.chainparams = chainparams,
14881487
.datadir = args.GetDataDirNet(),
@@ -1531,6 +1530,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
15311530
}
15321531
LogPrintf("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)\n", cache_sizes.coins * (1.0 / 1024 / 1024), mempool_opts.max_size_bytes * (1.0 / 1024 / 1024));
15331532

1533+
bool do_reindex{args.GetBoolArg("-reindex", false)};
1534+
const bool do_reindex_chainstate{args.GetBoolArg("-reindex-chainstate", false)};
1535+
15341536
for (bool fLoaded = false; !fLoaded && !ShutdownRequested(node);) {
15351537
node.mempool = std::make_unique<CTxMemPool>(mempool_opts);
15361538

@@ -1558,8 +1560,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
15581560

15591561
node::ChainstateLoadOptions options;
15601562
options.mempool = Assert(node.mempool.get());
1561-
options.reindex = chainman.m_blockman.m_reindexing;
1562-
options.reindex_chainstate = fReindexChainState;
1563+
options.wipe_block_tree_db = do_reindex;
1564+
options.wipe_chainstate_db = do_reindex || do_reindex_chainstate;
15631565
options.prune = chainman.m_blockman.IsPruneMode();
15641566
options.check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);
15651567
options.check_level = args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL);
@@ -1600,13 +1602,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
16001602

16011603
if (!fLoaded && !ShutdownRequested(node)) {
16021604
// first suggest a reindex
1603-
if (!options.reindex) {
1605+
if (!do_reindex) {
16041606
bool fRet = uiInterface.ThreadSafeQuestion(
16051607
error + Untranslated(".\n\n") + _("Do you want to rebuild the block database now?"),
16061608
error.original + ".\nPlease restart with -reindex or -reindex-chainstate to recover.",
16071609
"", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT);
16081610
if (fRet) {
1609-
chainman.m_blockman.m_reindexing = true;
1611+
do_reindex = true;
16101612
if (!Assert(node.shutdown)->reset()) {
16111613
LogPrintf("Internal error: failed to reset shutdown signal.\n");
16121614
}
@@ -1639,17 +1641,17 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
16391641
// ********************************************************* Step 8: start indexers
16401642

16411643
if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
1642-
g_txindex = std::make_unique<TxIndex>(interfaces::MakeChain(node), cache_sizes.tx_index, false, chainman.m_blockman.m_reindexing);
1644+
g_txindex = std::make_unique<TxIndex>(interfaces::MakeChain(node), cache_sizes.tx_index, false, do_reindex);
16431645
node.indexes.emplace_back(g_txindex.get());
16441646
}
16451647

16461648
for (const auto& filter_type : g_enabled_filter_types) {
1647-
InitBlockFilterIndex([&]{ return interfaces::MakeChain(node); }, filter_type, cache_sizes.filter_index, false, chainman.m_blockman.m_reindexing);
1649+
InitBlockFilterIndex([&]{ return interfaces::MakeChain(node); }, filter_type, cache_sizes.filter_index, false, do_reindex);
16481650
node.indexes.emplace_back(GetBlockFilterIndex(filter_type));
16491651
}
16501652

16511653
if (args.GetBoolArg("-coinstatsindex", DEFAULT_COINSTATSINDEX)) {
1652-
g_coin_stats_index = std::make_unique<CoinStatsIndex>(interfaces::MakeChain(node), /*cache_size=*/0, false, chainman.m_blockman.m_reindexing);
1654+
g_coin_stats_index = std::make_unique<CoinStatsIndex>(interfaces::MakeChain(node), /*cache_size=*/0, false, do_reindex);
16531655
node.indexes.emplace_back(g_coin_stats_index.get());
16541656
}
16551657

@@ -1668,7 +1670,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
16681670
// if pruning, perform the initial blockstore prune
16691671
// after any wallet rescanning has taken place.
16701672
if (chainman.m_blockman.IsPruneMode()) {
1671-
if (!chainman.m_blockman.m_reindexing) {
1673+
if (chainman.m_blockman.m_blockfiles_indexed) {
16721674
LOCK(cs_main);
16731675
for (Chainstate* chainstate : chainman.GetAll()) {
16741676
uiInterface.InitMessage(_("Pruning blockstore…").translated);
@@ -1694,7 +1696,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
16941696
int chain_active_height = WITH_LOCK(cs_main, return chainman.ActiveChain().Height());
16951697

16961698
// On first startup, warn on low block storage space
1697-
if (!chainman.m_blockman.m_reindexing && !fReindexChainState && chain_active_height <= 1) {
1699+
if (!do_reindex && !do_reindex_chainstate && chain_active_height <= 1) {
16981700
uint64_t assumed_chain_bytes{chainparams.AssumedBlockchainSize() * 1024 * 1024 * 1024};
16991701
uint64_t additional_bytes_needed{
17001702
chainman.m_blockman.IsPruneMode() ?

src/kernel/blockmanager_opts.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ struct BlockManagerOpts {
2424
bool fast_prune{false};
2525
const fs::path blocks_dir;
2626
Notifications& notifications;
27-
bool reindex{false};
2827
};
2928

3029
} // namespace kernel

src/node/blockmanager_args.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ util::Result<void> ApplyArgsManOptions(const ArgsManager& args, BlockManager::Op
3333

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

36-
if (auto value{args.GetBoolArg("-reindex")}) opts.reindex = *value;
37-
3836
return {};
3937
}
4038
} // namespace node

src/node/blockstorage.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -551,7 +551,7 @@ bool BlockManager::LoadBlockIndexDB(const std::optional<uint256>& snapshot_block
551551
// Check whether we need to continue reindexing
552552
bool fReindexing = false;
553553
m_block_tree_db->ReadReindexing(fReindexing);
554-
if (fReindexing) m_reindexing = true;
554+
if (fReindexing) m_blockfiles_indexed = false;
555555

556556
return true;
557557
}
@@ -1182,7 +1182,7 @@ void ImportBlocks(ChainstateManager& chainman, std::vector<fs::path> vImportFile
11821182
ImportingNow imp{chainman.m_blockman.m_importing};
11831183

11841184
// -reindex
1185-
if (chainman.m_blockman.m_reindexing) {
1185+
if (!chainman.m_blockman.m_blockfiles_indexed) {
11861186
int nFile = 0;
11871187
// Map of disk positions for blocks with unknown parent (only used for reindex);
11881188
// parent hash -> child disk position, multiple children can have the same parent.
@@ -1205,7 +1205,7 @@ void ImportBlocks(ChainstateManager& chainman, std::vector<fs::path> vImportFile
12051205
nFile++;
12061206
}
12071207
WITH_LOCK(::cs_main, chainman.m_blockman.m_block_tree_db->WriteReindexing(false));
1208-
chainman.m_blockman.m_reindexing = false;
1208+
chainman.m_blockman.m_blockfiles_indexed = true;
12091209
LogPrintf("Reindexing finished\n");
12101210
// To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked):
12111211
chainman.ActiveChainstate().LoadGenesisBlock();

src/node/blockstorage.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -267,18 +267,18 @@ class BlockManager
267267
explicit BlockManager(const util::SignalInterrupt& interrupt, Options opts)
268268
: m_prune_mode{opts.prune_target > 0},
269269
m_opts{std::move(opts)},
270-
m_interrupt{interrupt},
271-
m_reindexing{m_opts.reindex} {};
270+
m_interrupt{interrupt} {}
272271

273272
const util::SignalInterrupt& m_interrupt;
274273
std::atomic<bool> m_importing{false};
275274

276275
/**
277-
* Tracks if a reindex is currently in progress. Set to true when a reindex
278-
* is requested and false when reindexing completes. Its value is persisted
279-
* in the BlockTreeDB across restarts.
276+
* Whether all blockfiles have been added to the block tree database.
277+
* Normally true, but set to false when a reindex is requested and the
278+
* database is wiped. The value is persisted in the database across restarts
279+
* and will be false until reindexing completes.
280280
*/
281-
std::atomic_bool m_reindexing;
281+
std::atomic_bool m_blockfiles_indexed{true};
282282

283283
BlockMap m_block_index GUARDED_BY(cs_main);
284284

@@ -359,7 +359,7 @@ class BlockManager
359359
[[nodiscard]] uint64_t GetPruneTarget() const { return m_opts.prune_target; }
360360
static constexpr auto PRUNE_TARGET_MANUAL{std::numeric_limits<uint64_t>::max()};
361361

362-
[[nodiscard]] bool LoadingBlocks() const { return m_importing || m_reindexing; }
362+
[[nodiscard]] bool LoadingBlocks() const { return m_importing || !m_blockfiles_indexed; }
363363

364364
/** Calculate the amount of disk space the block & undo files currently use */
365365
uint64_t CalculateCurrentUsage();

src/node/chainstate.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,12 @@ static ChainstateLoadResult CompleteChainstateInitialization(
4545
.path = chainman.m_options.datadir / "blocks" / "index",
4646
.cache_bytes = static_cast<size_t>(cache_sizes.block_tree_db),
4747
.memory_only = options.block_tree_db_in_memory,
48-
.wipe_data = options.reindex,
48+
.wipe_data = options.wipe_block_tree_db,
4949
.options = chainman.m_options.block_tree_db});
5050

51-
if (options.reindex) {
51+
if (options.wipe_block_tree_db) {
5252
pblocktree->WriteReindexing(true);
53+
chainman.m_blockman.m_blockfiles_indexed = false;
5354
//If we're reindexing in prune mode, wipe away unusable block files and all undo data files
5455
if (options.prune) {
5556
chainman.m_blockman.CleanupBlockRevFiles();
@@ -60,8 +61,7 @@ static ChainstateLoadResult CompleteChainstateInitialization(
6061

6162
// LoadBlockIndex will load m_have_pruned if we've ever removed a
6263
// block file from disk.
63-
// Note that it also sets m_reindexing based on the disk flag!
64-
// From here on, m_reindexing and options.reindex values may be different!
64+
// Note that it also sets m_blockfiles_indexed based on the disk flag!
6565
if (!chainman.LoadBlockIndex()) {
6666
if (chainman.m_interrupt) return {ChainstateLoadStatus::INTERRUPTED, {}};
6767
return {ChainstateLoadStatus::FAILURE, _("Error loading block database")};
@@ -84,12 +84,12 @@ static ChainstateLoadResult CompleteChainstateInitialization(
8484
// If we're not mid-reindex (based on disk + args), add a genesis block on disk
8585
// (otherwise we use the one already on disk).
8686
// This is called again in ImportBlocks after the reindex completes.
87-
if (!chainman.m_blockman.m_reindexing && !chainman.ActiveChainstate().LoadGenesisBlock()) {
87+
if (chainman.m_blockman.m_blockfiles_indexed && !chainman.ActiveChainstate().LoadGenesisBlock()) {
8888
return {ChainstateLoadStatus::FAILURE, _("Error initializing block database")};
8989
}
9090

9191
auto is_coinsview_empty = [&](Chainstate* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
92-
return options.reindex || options.reindex_chainstate || chainstate->CoinsTip().GetBestBlock().IsNull();
92+
return options.wipe_chainstate_db || chainstate->CoinsTip().GetBestBlock().IsNull();
9393
};
9494

9595
assert(chainman.m_total_coinstip_cache > 0);
@@ -110,7 +110,7 @@ static ChainstateLoadResult CompleteChainstateInitialization(
110110
chainstate->InitCoinsDB(
111111
/*cache_size_bytes=*/chainman.m_total_coinsdb_cache * init_cache_fraction,
112112
/*in_memory=*/options.coins_db_in_memory,
113-
/*should_wipe=*/options.reindex || options.reindex_chainstate);
113+
/*should_wipe=*/options.wipe_chainstate_db);
114114

115115
if (options.coins_error_cb) {
116116
chainstate->CoinsErrorCatcher().AddReadErrCallback(options.coins_error_cb);
@@ -142,7 +142,7 @@ static ChainstateLoadResult CompleteChainstateInitialization(
142142
}
143143
}
144144

145-
if (!options.reindex) {
145+
if (!options.wipe_block_tree_db) {
146146
auto chainstates{chainman.GetAll()};
147147
if (std::any_of(chainstates.begin(), chainstates.end(),
148148
[](const Chainstate* cs) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return cs->NeedsRedownload(); })) {
@@ -188,7 +188,7 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize
188188
// Load a chain created from a UTXO snapshot, if any exist.
189189
bool has_snapshot = chainman.DetectSnapshotChainstate();
190190

191-
if (has_snapshot && (options.reindex || options.reindex_chainstate)) {
191+
if (has_snapshot && options.wipe_chainstate_db) {
192192
LogPrintf("[snapshot] deleting snapshot chainstate due to reindexing\n");
193193
if (!chainman.DeleteSnapshotChainstate()) {
194194
return {ChainstateLoadStatus::FAILURE_FATAL, Untranslated("Couldn't remove snapshot chainstate.")};
@@ -247,7 +247,7 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize
247247
ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager& chainman, const ChainstateLoadOptions& options)
248248
{
249249
auto is_coinsview_empty = [&](Chainstate* chainstate) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) {
250-
return options.reindex || options.reindex_chainstate || chainstate->CoinsTip().GetBestBlock().IsNull();
250+
return options.wipe_chainstate_db || chainstate->CoinsTip().GetBestBlock().IsNull();
251251
};
252252

253253
LOCK(cs_main);

src/node/chainstate.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,13 @@ struct ChainstateLoadOptions {
2222
CTxMemPool* mempool{nullptr};
2323
bool block_tree_db_in_memory{false};
2424
bool coins_db_in_memory{false};
25-
bool reindex{false};
26-
bool reindex_chainstate{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};
29+
// Whether to wipe the chainstate database when loading it. If set, this
30+
// will cause the chainstate database to be rebuilt starting from genesis.
31+
bool wipe_chainstate_db{false};
2732
bool prune{false};
2833
//! Setting require_full_verification to true will require all checks at
2934
//! check_level (below) to succeed for loading to succeed. Setting it to

src/test/util/setup_common.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,8 @@ void ChainTestingSetup::LoadVerifyActivateChainstate()
276276
options.mempool = Assert(m_node.mempool.get());
277277
options.block_tree_db_in_memory = m_block_tree_db_in_memory;
278278
options.coins_db_in_memory = m_coins_db_in_memory;
279-
options.reindex = chainman.m_blockman.m_reindexing;
280-
options.reindex_chainstate = m_args.GetBoolArg("-reindex-chainstate", false);
279+
options.wipe_block_tree_db = m_args.GetBoolArg("-reindex", false);
280+
options.wipe_chainstate_db = m_args.GetBoolArg("-reindex", false) || m_args.GetBoolArg("-reindex-chainstate", false);
281281
options.prune = chainman.m_blockman.IsPruneMode();
282282
options.check_blocks = m_args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);
283283
options.check_level = m_args.GetIntArg("-checklevel", DEFAULT_CHECKLEVEL);

0 commit comments

Comments
 (0)