mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-02 09:46:52 -05:00
kernel: Pass interrupt reference to chainman
This and the following commit seek to decouple the libbitcoinkernel library from the shutdown code. As a library, it should it should have its own flexible interrupt infrastructure without relying on node-wide globals. The commit takes the first step towards this goal by de-globalising `ShutdownRequested` calls in kernel code. Co-authored-by: Russell Yanofsky <russ@yanofsky.org> Co-authored-by: TheCharlatan <seb.kung@gmail.com>
This commit is contained in:
parent
e2d680a32d
commit
edb55e2777
12 changed files with 55 additions and 40 deletions
|
@ -113,7 +113,7 @@ int main(int argc, char* argv[])
|
|||
.chainparams = chainman_opts.chainparams,
|
||||
.blocks_dir = abs_datadir / "blocks",
|
||||
};
|
||||
ChainstateManager chainman{chainman_opts, blockman_opts};
|
||||
ChainstateManager chainman{kernel_context.interrupt, chainman_opts, blockman_opts};
|
||||
|
||||
node::CacheSizes cache_sizes;
|
||||
cache_sizes.block_tree_db = 2 << 20;
|
||||
|
|
|
@ -1462,7 +1462,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
|||
for (bool fLoaded = false; !fLoaded && !ShutdownRequested();) {
|
||||
node.mempool = std::make_unique<CTxMemPool>(mempool_opts);
|
||||
|
||||
node.chainman = std::make_unique<ChainstateManager>(chainman_opts, blockman_opts);
|
||||
node.chainman = std::make_unique<ChainstateManager>(node.kernel->interrupt, chainman_opts, blockman_opts);
|
||||
ChainstateManager& chainman = *node.chainman;
|
||||
|
||||
node::ChainstateLoadOptions options;
|
||||
|
|
|
@ -9,13 +9,13 @@
|
|||
#include <logging.h>
|
||||
#include <primitives/transaction.h>
|
||||
#include <serialize.h>
|
||||
#include <shutdown.h>
|
||||
#include <streams.h>
|
||||
#include <sync.h>
|
||||
#include <txmempool.h>
|
||||
#include <uint256.h>
|
||||
#include <util/fs.h>
|
||||
#include <util/fs_helpers.h>
|
||||
#include <util/signalinterrupt.h>
|
||||
#include <util/time.h>
|
||||
#include <validation.h>
|
||||
|
||||
|
@ -95,7 +95,7 @@ bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, Chainstate& active
|
|||
} else {
|
||||
++expired;
|
||||
}
|
||||
if (ShutdownRequested())
|
||||
if (active_chainstate.m_chainman.m_interrupt)
|
||||
return false;
|
||||
}
|
||||
std::map<uint256, CAmount> mapDeltas;
|
||||
|
|
|
@ -13,12 +13,12 @@
|
|||
#include <logging.h>
|
||||
#include <pow.h>
|
||||
#include <reverse_iterator.h>
|
||||
#include <shutdown.h>
|
||||
#include <signet.h>
|
||||
#include <streams.h>
|
||||
#include <undo.h>
|
||||
#include <util/batchpriority.h>
|
||||
#include <util/fs.h>
|
||||
#include <util/signalinterrupt.h>
|
||||
#include <validation.h>
|
||||
|
||||
#include <map>
|
||||
|
@ -250,7 +250,8 @@ CBlockIndex* BlockManager::InsertBlockIndex(const uint256& hash)
|
|||
|
||||
bool BlockManager::LoadBlockIndex()
|
||||
{
|
||||
if (!m_block_tree_db->LoadBlockIndexGuts(GetConsensus(), [this](const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return this->InsertBlockIndex(hash); })) {
|
||||
if (!m_block_tree_db->LoadBlockIndexGuts(
|
||||
GetConsensus(), [this](const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return this->InsertBlockIndex(hash); }, m_interrupt)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -260,7 +261,7 @@ bool BlockManager::LoadBlockIndex()
|
|||
CBlockIndexHeightOnlyComparator());
|
||||
|
||||
for (CBlockIndex* pindex : vSortedByHeight) {
|
||||
if (ShutdownRequested()) return false;
|
||||
if (m_interrupt) return false;
|
||||
pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex);
|
||||
pindex->nTimeMax = (pindex->pprev ? std::max(pindex->pprev->nTimeMax, pindex->nTime) : pindex->nTime);
|
||||
|
||||
|
@ -890,8 +891,8 @@ void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFile
|
|||
}
|
||||
LogPrintf("Reindexing block file blk%05u.dat...\n", (unsigned int)nFile);
|
||||
chainman.ActiveChainstate().LoadExternalBlockFile(file, &pos, &blocks_with_unknown_parent);
|
||||
if (ShutdownRequested()) {
|
||||
LogPrintf("Shutdown requested. Exit %s\n", __func__);
|
||||
if (chainman.m_interrupt) {
|
||||
LogPrintf("Interrupt requested. Exit %s\n", __func__);
|
||||
return;
|
||||
}
|
||||
nFile++;
|
||||
|
@ -909,8 +910,8 @@ void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFile
|
|||
if (file) {
|
||||
LogPrintf("Importing blocks file %s...\n", fs::PathToString(path));
|
||||
chainman.ActiveChainstate().LoadExternalBlockFile(file);
|
||||
if (ShutdownRequested()) {
|
||||
LogPrintf("Shutdown requested. Exit %s\n", __func__);
|
||||
if (chainman.m_interrupt) {
|
||||
LogPrintf("Interrupt requested. Exit %s\n", __func__);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -33,6 +33,9 @@ struct FlatFilePos;
|
|||
namespace Consensus {
|
||||
struct Params;
|
||||
}
|
||||
namespace util {
|
||||
class SignalInterrupt;
|
||||
} // namespace util
|
||||
|
||||
namespace node {
|
||||
|
||||
|
@ -153,10 +156,12 @@ private:
|
|||
public:
|
||||
using Options = kernel::BlockManagerOpts;
|
||||
|
||||
explicit BlockManager(Options opts)
|
||||
explicit BlockManager(const util::SignalInterrupt& interrupt, Options opts)
|
||||
: m_prune_mode{opts.prune_target > 0},
|
||||
m_opts{std::move(opts)} {};
|
||||
m_opts{std::move(opts)},
|
||||
m_interrupt{interrupt} {};
|
||||
|
||||
const util::SignalInterrupt& m_interrupt;
|
||||
std::atomic<bool> m_importing{false};
|
||||
|
||||
BlockMap m_block_index GUARDED_BY(cs_main);
|
||||
|
|
|
@ -25,7 +25,7 @@ BOOST_AUTO_TEST_CASE(blockmanager_find_block_pos)
|
|||
.chainparams = *params,
|
||||
.blocks_dir = m_args.GetBlocksDirPath(),
|
||||
};
|
||||
BlockManager blockman{blockman_opts};
|
||||
BlockManager blockman{m_node.kernel->interrupt, blockman_opts};
|
||||
CChain chain {};
|
||||
// simulate adding a genesis block normally
|
||||
BOOST_CHECK_EQUAL(blockman.SaveBlockToDisk(params->GenesisBlock(), 0, chain, nullptr).nPos, BLOCK_SERIALIZATION_HEADER_SIZE);
|
||||
|
|
|
@ -197,7 +197,7 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, const std::vecto
|
|||
.chainparams = chainman_opts.chainparams,
|
||||
.blocks_dir = m_args.GetBlocksDirPath(),
|
||||
};
|
||||
m_node.chainman = std::make_unique<ChainstateManager>(chainman_opts, blockman_opts);
|
||||
m_node.chainman = std::make_unique<ChainstateManager>(m_node.kernel->interrupt, chainman_opts, blockman_opts);
|
||||
m_node.chainman->m_blockman.m_block_tree_db = std::make_unique<CBlockTreeDB>(DBParams{
|
||||
.path = m_args.GetDataDirNet() / "blocks" / "index",
|
||||
.cache_bytes = static_cast<size_t>(m_cache_sizes.block_tree_db),
|
||||
|
|
|
@ -393,7 +393,7 @@ struct SnapshotTestSetup : TestChain100Setup {
|
|||
// For robustness, ensure the old manager is destroyed before creating a
|
||||
// new one.
|
||||
m_node.chainman.reset();
|
||||
m_node.chainman = std::make_unique<ChainstateManager>(chainman_opts, blockman_opts);
|
||||
m_node.chainman = std::make_unique<ChainstateManager>(m_node.kernel->interrupt, chainman_opts, blockman_opts);
|
||||
}
|
||||
return *Assert(m_node.chainman);
|
||||
}
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
#include <logging.h>
|
||||
#include <pow.h>
|
||||
#include <random.h>
|
||||
#include <shutdown.h>
|
||||
#include <uint256.h>
|
||||
#include <util/signalinterrupt.h>
|
||||
#include <util/translation.h>
|
||||
#include <util/vector.h>
|
||||
|
||||
|
@ -291,7 +291,7 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex)
|
||||
bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex, const util::SignalInterrupt& interrupt)
|
||||
{
|
||||
AssertLockHeld(::cs_main);
|
||||
std::unique_ptr<CDBIterator> pcursor(NewIterator());
|
||||
|
@ -299,7 +299,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams,
|
|||
|
||||
// Load m_block_index
|
||||
while (pcursor->Valid()) {
|
||||
if (ShutdownRequested()) return false;
|
||||
if (interrupt) return false;
|
||||
std::pair<uint8_t, uint256> key;
|
||||
if (pcursor->GetKey(key) && key.first == DB_BLOCK_INDEX) {
|
||||
CDiskBlockIndex diskindex;
|
||||
|
|
|
@ -29,6 +29,9 @@ class uint256;
|
|||
namespace Consensus {
|
||||
struct Params;
|
||||
};
|
||||
namespace util {
|
||||
class SignalInterrupt;
|
||||
} // namespace util
|
||||
|
||||
//! -dbcache default (MiB)
|
||||
static const int64_t nDefaultDbCache = 450;
|
||||
|
@ -98,7 +101,7 @@ public:
|
|||
void ReadReindexing(bool &fReindexing);
|
||||
bool WriteFlag(const std::string &name, bool fValue);
|
||||
bool ReadFlag(const std::string &name, bool &fValue);
|
||||
bool LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex)
|
||||
bool LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex, const util::SignalInterrupt& interrupt)
|
||||
EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
||||
};
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include <util/hasher.h>
|
||||
#include <util/moneystr.h>
|
||||
#include <util/rbf.h>
|
||||
#include <util/signalinterrupt.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <util/time.h>
|
||||
#include <util/trace.h>
|
||||
|
@ -3183,11 +3184,11 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<
|
|||
break;
|
||||
}
|
||||
|
||||
// We check shutdown only after giving ActivateBestChainStep a chance to run once so that we
|
||||
// never shutdown before connecting the genesis block during LoadChainTip(). Previously this
|
||||
// caused an assert() failure during shutdown in such cases as the UTXO DB flushing checks
|
||||
// We check interrupt only after giving ActivateBestChainStep a chance to run once so that we
|
||||
// never interrupt before connecting the genesis block during LoadChainTip(). Previously this
|
||||
// caused an assert() failure during interrupt in such cases as the UTXO DB flushing checks
|
||||
// that the best block hash is non-null.
|
||||
if (ShutdownRequested()) break;
|
||||
if (m_chainman.m_interrupt) break;
|
||||
} while (pindexNewTip != pindexMostWork);
|
||||
CheckBlockIndex();
|
||||
|
||||
|
@ -3277,7 +3278,7 @@ bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* pinde
|
|||
|
||||
// Disconnect (descendants of) pindex, and mark them invalid.
|
||||
while (true) {
|
||||
if (ShutdownRequested()) break;
|
||||
if (m_chainman.m_interrupt) break;
|
||||
|
||||
// Make sure the queue of validation callbacks doesn't grow unboundedly.
|
||||
LimitValidationInterfaceQueue();
|
||||
|
@ -4079,7 +4080,7 @@ void Chainstate::LoadMempool(const fs::path& load_path, FopenFn mockable_fopen_f
|
|||
{
|
||||
if (!m_mempool) return;
|
||||
::LoadMempool(*m_mempool, load_path, *this, mockable_fopen_function);
|
||||
m_mempool->SetLoadTried(!ShutdownRequested());
|
||||
m_mempool->SetLoadTried(!m_chainman.m_interrupt);
|
||||
}
|
||||
|
||||
bool Chainstate::LoadChainTip()
|
||||
|
@ -4212,7 +4213,7 @@ VerifyDBResult CVerifyDB::VerifyDB(
|
|||
skipped_l3_checks = true;
|
||||
}
|
||||
}
|
||||
if (ShutdownRequested()) return VerifyDBResult::INTERRUPTED;
|
||||
if (chainstate.m_chainman.m_interrupt) return VerifyDBResult::INTERRUPTED;
|
||||
}
|
||||
if (pindexFailure) {
|
||||
LogPrintf("Verification error: coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", chainstate.m_chain.Height() - pindexFailure->nHeight + 1, nGoodTransactions);
|
||||
|
@ -4245,7 +4246,7 @@ VerifyDBResult CVerifyDB::VerifyDB(
|
|||
LogPrintf("Verification error: found unconnectable block at %d, hash=%s (%s)\n", pindex->nHeight, pindex->GetBlockHash().ToString(), state.ToString());
|
||||
return VerifyDBResult::CORRUPTED_BLOCK_DB;
|
||||
}
|
||||
if (ShutdownRequested()) return VerifyDBResult::INTERRUPTED;
|
||||
if (chainstate.m_chainman.m_interrupt) return VerifyDBResult::INTERRUPTED;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4413,7 +4414,7 @@ bool ChainstateManager::LoadBlockIndex()
|
|||
}
|
||||
|
||||
for (CBlockIndex* pindex : vSortedByHeight) {
|
||||
if (ShutdownRequested()) return false;
|
||||
if (m_interrupt) return false;
|
||||
if (pindex->IsAssumedValid() ||
|
||||
(pindex->IsValid(BLOCK_VALID_TRANSACTIONS) &&
|
||||
(pindex->HaveTxsDownloaded() || pindex->pprev == nullptr))) {
|
||||
|
@ -4519,7 +4520,7 @@ void Chainstate::LoadExternalBlockFile(
|
|||
// such as a block fails to deserialize.
|
||||
uint64_t nRewind = blkdat.GetPos();
|
||||
while (!blkdat.eof()) {
|
||||
if (ShutdownRequested()) return;
|
||||
if (m_chainman.m_interrupt) return;
|
||||
|
||||
blkdat.SetPos(nRewind);
|
||||
nRewind++; // start one byte further next time, in case of failure
|
||||
|
@ -5152,13 +5153,13 @@ struct StopHashingException : public std::exception
|
|||
{
|
||||
const char* what() const throw() override
|
||||
{
|
||||
return "ComputeUTXOStats interrupted by shutdown.";
|
||||
return "ComputeUTXOStats interrupted.";
|
||||
}
|
||||
};
|
||||
|
||||
static void SnapshotUTXOHashBreakpoint()
|
||||
static void SnapshotUTXOHashBreakpoint(const util::SignalInterrupt& interrupt)
|
||||
{
|
||||
if (ShutdownRequested()) throw StopHashingException();
|
||||
if (interrupt) throw StopHashingException();
|
||||
}
|
||||
|
||||
bool ChainstateManager::PopulateAndValidateSnapshot(
|
||||
|
@ -5235,7 +5236,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
|
|||
// If our average Coin size is roughly 41 bytes, checking every 120,000 coins
|
||||
// means <5MB of memory imprecision.
|
||||
if (coins_processed % 120000 == 0) {
|
||||
if (ShutdownRequested()) {
|
||||
if (m_interrupt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -5292,7 +5293,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
|
|||
|
||||
try {
|
||||
maybe_stats = ComputeUTXOStats(
|
||||
CoinStatsHashType::HASH_SERIALIZED, snapshot_coinsdb, m_blockman, SnapshotUTXOHashBreakpoint);
|
||||
CoinStatsHashType::HASH_SERIALIZED, snapshot_coinsdb, m_blockman, [&interrupt = m_interrupt] { SnapshotUTXOHashBreakpoint(interrupt); });
|
||||
} catch (StopHashingException const&) {
|
||||
return false;
|
||||
}
|
||||
|
@ -5470,7 +5471,7 @@ SnapshotCompletionResult ChainstateManager::MaybeCompleteSnapshotValidation(
|
|||
CoinStatsHashType::HASH_SERIALIZED,
|
||||
&ibd_coins_db,
|
||||
m_blockman,
|
||||
SnapshotUTXOHashBreakpoint);
|
||||
[&interrupt = m_interrupt] { SnapshotUTXOHashBreakpoint(interrupt); });
|
||||
} catch (StopHashingException const&) {
|
||||
return SnapshotCompletionResult::STATS_FAILED;
|
||||
}
|
||||
|
@ -5579,9 +5580,10 @@ static ChainstateManager::Options&& Flatten(ChainstateManager::Options&& opts)
|
|||
return std::move(opts);
|
||||
}
|
||||
|
||||
ChainstateManager::ChainstateManager(Options options, node::BlockManager::Options blockman_options)
|
||||
: m_options{Flatten(std::move(options))},
|
||||
m_blockman{std::move(blockman_options)} {}
|
||||
ChainstateManager::ChainstateManager(const util::SignalInterrupt& interrupt, Options options, node::BlockManager::Options blockman_options)
|
||||
: m_interrupt{interrupt},
|
||||
m_options{Flatten(std::move(options))},
|
||||
m_blockman{interrupt, std::move(blockman_options)} {}
|
||||
|
||||
ChainstateManager::~ChainstateManager()
|
||||
{
|
||||
|
|
|
@ -62,6 +62,9 @@ class SnapshotMetadata;
|
|||
namespace Consensus {
|
||||
struct Params;
|
||||
} // namespace Consensus
|
||||
namespace util {
|
||||
class SignalInterrupt;
|
||||
} // namespace util
|
||||
|
||||
/** Maximum number of dedicated script-checking threads allowed */
|
||||
static const int MAX_SCRIPTCHECK_THREADS = 15;
|
||||
|
@ -959,7 +962,7 @@ private:
|
|||
public:
|
||||
using Options = kernel::ChainstateManagerOpts;
|
||||
|
||||
explicit ChainstateManager(Options options, node::BlockManager::Options blockman_options);
|
||||
explicit ChainstateManager(const util::SignalInterrupt& interrupt, Options options, node::BlockManager::Options blockman_options);
|
||||
|
||||
const CChainParams& GetParams() const { return m_options.chainparams; }
|
||||
const Consensus::Params& GetConsensus() const { return m_options.chainparams.GetConsensus(); }
|
||||
|
@ -982,6 +985,7 @@ public:
|
|||
*/
|
||||
RecursiveMutex& GetMutex() const LOCK_RETURNED(::cs_main) { return ::cs_main; }
|
||||
|
||||
const util::SignalInterrupt& m_interrupt;
|
||||
const Options m_options;
|
||||
std::thread m_load_block;
|
||||
//! A single BlockManager instance is shared across each constructed
|
||||
|
|
Loading…
Add table
Reference in a new issue