Skip to content

Commit

Permalink
kernel: Move block tree db open to BlockManager constructor
Browse files Browse the repository at this point in the history
Make the block db open RAII style by calling it in the BlockManager
constructor.

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.
  • Loading branch information
TheCharlatan committed Jan 20, 2025
1 parent 7fbb1bc commit 0cdddeb
Show file tree
Hide file tree
Showing 5 changed files with 23 additions and 28 deletions.
9 changes: 9 additions & 0 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1215,12 +1215,21 @@ static ChainstateLoadResult InitAndLoadChainstate(
},
};
Assert(ApplyArgsManOptions(args, blockman_opts)); // no error can happen, already checked in AppInitParameterInteraction

// Creating the chainstate manager internally creates a BlockManager, opens
// the blocks tree db, and wipes existing block files in case of a reindex.
// The coinsdb is opened at a later point on LoadChainstate.
try {
node.chainman = std::make_unique<ChainstateManager>(*Assert(node.shutdown_signal), chainman_opts, blockman_opts);
} catch (dbwrapper_error& e) {
LogError("%s", e.what());
return {ChainstateLoadStatus::FAILURE, _("Error opening block database")};
} catch (std::exception& e) {
return {ChainstateLoadStatus::FAILURE_FATAL, Untranslated(strprintf("Failed to initialize ChainstateManager: %s", e.what()))};
}
ChainstateManager& chainman = *node.chainman;
if (chainman.m_interrupt) return {ChainstateLoadStatus::INTERRUPTED, {}};

// This is defined and set here instead of inline in validation.h to avoid a hard
// dependency between validation and index/base, since the latter is not in
// libbitcoinkernel.
Expand Down
15 changes: 14 additions & 1 deletion src/node/blockstorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <util/translation.h>
#include <validation.h>

#include <cstddef>
#include <map>
#include <ranges>
#include <unordered_map>
Expand Down Expand Up @@ -1183,7 +1184,19 @@ BlockManager::BlockManager(const util::SignalInterrupt& interrupt, Options opts)
m_opts{std::move(opts)},
m_block_file_seq{FlatFileSeq{m_opts.blocks_dir, "blk", m_opts.fast_prune ? 0x4000 /* 16kB */ : BLOCKFILE_CHUNK_SIZE}},
m_undo_file_seq{FlatFileSeq{m_opts.blocks_dir, "rev", UNDOFILE_CHUNK_SIZE}},
m_interrupt{interrupt} {}
m_interrupt{interrupt}
{
m_block_tree_db = std::make_unique<BlockTreeDB>(m_opts.block_tree_db_params);

if (m_opts.block_tree_db_params.wipe_data) {
m_block_tree_db->WriteReindexing(true);
m_blockfiles_indexed = false;
// If we're reindexing in prune mode, wipe away unusable block files and all undo data files
if (m_prune_mode) {
CleanupBlockRevFiles();
}
}
}

class ImportingNow
{
Expand Down
2 changes: 0 additions & 2 deletions src/node/blockstorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,8 +268,6 @@ class BlockManager
using Options = kernel::BlockManagerOpts;

explicit BlockManager(const util::SignalInterrupt& interrupt, Options opts);
auto MakeBlockTreeDb() { return std::make_unique<BlockTreeDB>(m_opts.block_tree_db_params); }
auto OptsWipeBlockTreeDb() { return m_opts.block_tree_db_params.wipe_data; }

const util::SignalInterrupt& m_interrupt;
std::atomic<bool> m_importing{false};
Expand Down
23 changes: 0 additions & 23 deletions src/node/chainstate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@
#include <validation.h>

#include <algorithm>
#include <atomic>
#include <cassert>
#include <limits>
#include <memory>
#include <vector>

using kernel::CacheSizes;
Expand All @@ -38,26 +35,6 @@ static ChainstateLoadResult CompleteChainstateInitialization(
ChainstateManager& chainman,
const ChainstateLoadOptions& options) EXCLUSIVE_LOCKS_REQUIRED(::cs_main)
{
auto& pblocktree{chainman.m_blockman.m_block_tree_db};
// new BlockTreeDB tries to delete the existing file, which
// fails if it's still open from the previous loop. Close it first:
pblocktree.reset();
try {
pblocktree = chainman.m_blockman.MakeBlockTreeDb();
} catch (dbwrapper_error& err) {
LogError("%s\n", err.what());
return {ChainstateLoadStatus::FAILURE, _("Error opening block database")};
}

if (chainman.m_blockman.OptsWipeBlockTreeDb()) {
pblocktree->WriteReindexing(true);
chainman.m_blockman.m_blockfiles_indexed = false;
//If we're reindexing in prune mode, wipe away unusable block files and all undo data files
if (options.prune) {
chainman.m_blockman.CleanupBlockRevFiles();
}
}

if (chainman.m_interrupt) return {ChainstateLoadStatus::INTERRUPTED, {}};

// LoadBlockIndex will load m_have_pruned if we've ever removed a
Expand Down
2 changes: 0 additions & 2 deletions src/test/util/setup_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,6 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, TestOpts opts)
},
};
m_node.chainman = std::make_unique<ChainstateManager>(*Assert(m_node.shutdown_signal), chainman_opts, blockman_opts);
LOCK(m_node.chainman->GetMutex());
m_node.chainman->m_blockman.m_block_tree_db = m_node.chainman->m_blockman.MakeBlockTreeDb();
};
m_make_chainman();
}
Expand Down

0 comments on commit 0cdddeb

Please sign in to comment.