mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-29 14:59:39 -04:00
Merge bitcoin/bitcoin#22564: refactor: Move mutable globals cleared in ::UnloadBlockIndex
to BlockManager
7ab07e0332
validation: Prune UnloadBlockIndex and callees (Carl Dong)7d99d725cd
validation: No mempool clearing in UnloadBlockIndex (Carl Dong)572d831927
Clear {versionbits,warning}cache in ~Chainstatemanager (Carl Dong)eca4ca4d60
style-only: Use std::clamp for check_ratio, rename (Carl Dong)fe96a2e4bd
style-only: Use for instead of when loading Chainstate (Carl Dong)5921b863e3
init: Reset mempool and chainman via reconstruction (Carl Dong)6e747e80e7
validation: default initialize and guard chainman members (Anthony Towns)98f4bdae81
refactor: Convert warningcache to std::array (Carl Dong) Pull request description: Fixes #22964 ----- This is a small part of the work to accomplish what I described in972c5166ee
: ``` Over time, we should probably move these mutable global state variables into ChainstateManager or CChainState so it's easier to reason about their lifecycles. ``` `::UnloadBlockIndex` manually resets a subset of our mutable globals in addition to unloading the `ChainstateManager` and clearing the mempool. The need for this manual reset (AFAICT) arises out of the fact that many of these globals are closely related to the block index (hence `::UnloadBlockIndex`), and need to be reset with it. I've shot this "manual reset" gun at my foot several times while doing the de-globalize chainman work. Thankfully, now that we have a `BlockManager` class that owns the block index, these globals should be moved under that class so that they can live and die with the block index. These moves, along with making the block index non-heap-based, eliminates: 1.3585b52139
The need to reason about when we need to manually call `::UnloadBlockIndex` (this decision can at times seem almost arbitrary) 2.f741623c25
The need to have an `::UnloadBlockIndex` or explicit `~ChainstateManager` at all ACKs for top commit: MarcoFalke: ACK7ab07e0332
👘 ajtowns: ACK7ab07e0332
ryanofsky: Code review ACK7ab07e0332
. This all looks good and simplifies things nicely. I left some minor suggestions below but feel free to ignore. Tree-SHA512: a36ee3fc122ce0b4e8d1c432662d7009df06264b724b793252978a1e409dde7a7ef1f78b9ade3f8bfb5388213f10ae2d058d57a7a46ae563e9034d7d33a52b69
This commit is contained in:
commit
b51e60f914
10 changed files with 39 additions and 87 deletions
|
@ -256,7 +256,5 @@ epilogue:
|
||||||
}
|
}
|
||||||
GetMainSignals().UnregisterBackgroundSignalScheduler();
|
GetMainSignals().UnregisterBackgroundSignalScheduler();
|
||||||
|
|
||||||
WITH_LOCK(::cs_main, UnloadBlockIndex(nullptr, chainman));
|
|
||||||
|
|
||||||
init::UnsetGlobals();
|
init::UnsetGlobals();
|
||||||
}
|
}
|
||||||
|
|
33
src/init.cpp
33
src/init.cpp
|
@ -73,6 +73,7 @@
|
||||||
#include <validationinterface.h>
|
#include <validationinterface.h>
|
||||||
#include <walletinitinterface.h>
|
#include <walletinitinterface.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
@ -1288,19 +1289,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
||||||
// as they would never get updated.
|
// as they would never get updated.
|
||||||
if (!ignores_incoming_txs) node.fee_estimator = std::make_unique<CBlockPolicyEstimator>();
|
if (!ignores_incoming_txs) node.fee_estimator = std::make_unique<CBlockPolicyEstimator>();
|
||||||
|
|
||||||
assert(!node.mempool);
|
|
||||||
int check_ratio = std::min<int>(std::max<int>(args.GetIntArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);
|
|
||||||
node.mempool = std::make_unique<CTxMemPool>(node.fee_estimator.get(), check_ratio);
|
|
||||||
|
|
||||||
assert(!node.chainman);
|
|
||||||
node.chainman = std::make_unique<ChainstateManager>();
|
|
||||||
ChainstateManager& chainman = *node.chainman;
|
|
||||||
|
|
||||||
assert(!node.peerman);
|
|
||||||
node.peerman = PeerManager::make(chainparams, *node.connman, *node.addrman, node.banman.get(),
|
|
||||||
chainman, *node.mempool, ignores_incoming_txs);
|
|
||||||
RegisterValidationInterface(node.peerman.get());
|
|
||||||
|
|
||||||
// sanitize comments per BIP-0014, format user agent and check total size
|
// sanitize comments per BIP-0014, format user agent and check total size
|
||||||
std::vector<std::string> uacomments;
|
std::vector<std::string> uacomments;
|
||||||
for (const std::string& cmt : args.GetArgs("-uacomment")) {
|
for (const std::string& cmt : args.GetArgs("-uacomment")) {
|
||||||
|
@ -1429,8 +1417,16 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
||||||
LogPrintf("* Using %.1f MiB for chain state database\n", cache_sizes.coins_db * (1.0 / 1024 / 1024));
|
LogPrintf("* Using %.1f MiB for chain state database\n", cache_sizes.coins_db * (1.0 / 1024 / 1024));
|
||||||
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), nMempoolSizeMax * (1.0 / 1024 / 1024));
|
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), nMempoolSizeMax * (1.0 / 1024 / 1024));
|
||||||
|
|
||||||
bool fLoaded = false;
|
assert(!node.mempool);
|
||||||
while (!fLoaded && !ShutdownRequested()) {
|
assert(!node.chainman);
|
||||||
|
const int mempool_check_ratio = std::clamp<int>(args.GetIntArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0, 1000000);
|
||||||
|
|
||||||
|
for (bool fLoaded = false; !fLoaded && !ShutdownRequested();) {
|
||||||
|
node.mempool = std::make_unique<CTxMemPool>(node.fee_estimator.get(), mempool_check_ratio);
|
||||||
|
|
||||||
|
node.chainman = std::make_unique<ChainstateManager>();
|
||||||
|
ChainstateManager& chainman = *node.chainman;
|
||||||
|
|
||||||
const bool fReset = fReindex;
|
const bool fReset = fReindex;
|
||||||
bilingual_str strLoadError;
|
bilingual_str strLoadError;
|
||||||
|
|
||||||
|
@ -1562,6 +1558,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChainstateManager& chainman = *Assert(node.chainman);
|
||||||
|
|
||||||
|
assert(!node.peerman);
|
||||||
|
node.peerman = PeerManager::make(chainparams, *node.connman, *node.addrman, node.banman.get(),
|
||||||
|
chainman, *node.mempool, ignores_incoming_txs);
|
||||||
|
RegisterValidationInterface(node.peerman.get());
|
||||||
|
|
||||||
// ********************************************************* Step 8: start indexers
|
// ********************************************************* Step 8: start indexers
|
||||||
if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
|
if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
|
||||||
if (const auto error{WITH_LOCK(cs_main, return CheckLegacyTxindex(*Assert(chainman.m_blockman.m_block_tree_db)))}) {
|
if (const auto error{WITH_LOCK(cs_main, return CheckLegacyTxindex(*Assert(chainman.m_blockman.m_block_tree_db)))}) {
|
||||||
|
|
|
@ -297,20 +297,6 @@ bool BlockManager::LoadBlockIndex(const Consensus::Params& consensus_params)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BlockManager::Unload()
|
|
||||||
{
|
|
||||||
m_blocks_unlinked.clear();
|
|
||||||
|
|
||||||
m_block_index.clear();
|
|
||||||
|
|
||||||
m_blockfile_info.clear();
|
|
||||||
m_last_blockfile = 0;
|
|
||||||
m_dirty_blockindex.clear();
|
|
||||||
m_dirty_fileinfo.clear();
|
|
||||||
|
|
||||||
m_have_pruned = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BlockManager::WriteBlockIndexDB()
|
bool BlockManager::WriteBlockIndexDB()
|
||||||
{
|
{
|
||||||
AssertLockHeld(::cs_main);
|
AssertLockHeld(::cs_main);
|
||||||
|
|
|
@ -154,9 +154,6 @@ public:
|
||||||
bool WriteBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
bool WriteBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
||||||
bool LoadBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
bool LoadBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
||||||
|
|
||||||
/** Clear all data members. */
|
|
||||||
void Unload() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
|
||||||
|
|
||||||
CBlockIndex* AddToBlockIndex(const CBlockHeader& block, CBlockIndex*& best_header) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
CBlockIndex* AddToBlockIndex(const CBlockHeader& block, CBlockIndex*& best_header) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
/** Create a new block index entry for a given block hash */
|
/** Create a new block index entry for a given block hash */
|
||||||
CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
@ -189,11 +186,6 @@ public:
|
||||||
|
|
||||||
//! Create or update a prune lock identified by its name
|
//! Create or update a prune lock identified by its name
|
||||||
void UpdatePruneLock(const std::string& name, const PruneLockInfo& lock_info) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
void UpdatePruneLock(const std::string& name, const PruneLockInfo& lock_info) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
||||||
|
|
||||||
~BlockManager()
|
|
||||||
{
|
|
||||||
Unload();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Find the first block that is not pruned
|
//! Find the first block that is not pruned
|
||||||
|
|
|
@ -32,8 +32,6 @@ std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
|
||||||
chainman.m_total_coinstip_cache = nCoinCacheUsage;
|
chainman.m_total_coinstip_cache = nCoinCacheUsage;
|
||||||
chainman.m_total_coinsdb_cache = nCoinDBCache;
|
chainman.m_total_coinsdb_cache = nCoinDBCache;
|
||||||
|
|
||||||
UnloadBlockIndex(mempool, chainman);
|
|
||||||
|
|
||||||
auto& pblocktree{chainman.m_blockman.m_block_tree_db};
|
auto& pblocktree{chainman.m_blockman.m_block_tree_db};
|
||||||
// new CBlockTreeDB tries to delete the existing file, which
|
// new CBlockTreeDB tries to delete the existing file, which
|
||||||
// fails if it's still open from the previous loop. Close it first:
|
// fails if it's still open from the previous loop. Close it first:
|
||||||
|
|
|
@ -182,7 +182,6 @@ ChainTestingSetup::~ChainTestingSetup()
|
||||||
m_node.addrman.reset();
|
m_node.addrman.reset();
|
||||||
m_node.netgroupman.reset();
|
m_node.netgroupman.reset();
|
||||||
m_node.args = nullptr;
|
m_node.args = nullptr;
|
||||||
WITH_LOCK(::cs_main, UnloadBlockIndex(m_node.mempool.get(), *m_node.chainman));
|
|
||||||
m_node.mempool.reset();
|
m_node.mempool.reset();
|
||||||
m_node.scheduler.reset();
|
m_node.scheduler.reset();
|
||||||
m_node.chainman.reset();
|
m_node.chainman.reset();
|
||||||
|
|
|
@ -93,7 +93,7 @@ BOOST_FIXTURE_TEST_CASE(chainstate_update_tip, TestChain100Setup)
|
||||||
BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(m_node, m_path_root));
|
BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(m_node, m_path_root));
|
||||||
|
|
||||||
// Ensure our active chain is the snapshot chainstate.
|
// Ensure our active chain is the snapshot chainstate.
|
||||||
BOOST_CHECK(chainman.IsSnapshotActive());
|
BOOST_CHECK(WITH_LOCK(::cs_main, return chainman.IsSnapshotActive()));
|
||||||
|
|
||||||
curr_tip = ::g_best_block;
|
curr_tip = ::g_best_block;
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
|
||||||
WITH_LOCK(::cs_main, c1.InitCoinsCache(1 << 23));
|
WITH_LOCK(::cs_main, c1.InitCoinsCache(1 << 23));
|
||||||
|
|
||||||
BOOST_CHECK(!manager.IsSnapshotActive());
|
BOOST_CHECK(!manager.IsSnapshotActive());
|
||||||
BOOST_CHECK(!manager.IsSnapshotValidated());
|
BOOST_CHECK(WITH_LOCK(::cs_main, return !manager.IsSnapshotValidated()));
|
||||||
auto all = manager.GetAll();
|
auto all = manager.GetAll();
|
||||||
BOOST_CHECK_EQUAL_COLLECTIONS(all.begin(), all.end(), chainstates.begin(), chainstates.end());
|
BOOST_CHECK_EQUAL_COLLECTIONS(all.begin(), all.end(), chainstates.begin(), chainstates.end());
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ BOOST_AUTO_TEST_CASE(chainstatemanager)
|
||||||
BOOST_CHECK(c2.ActivateBestChain(_, nullptr));
|
BOOST_CHECK(c2.ActivateBestChain(_, nullptr));
|
||||||
|
|
||||||
BOOST_CHECK(manager.IsSnapshotActive());
|
BOOST_CHECK(manager.IsSnapshotActive());
|
||||||
BOOST_CHECK(!manager.IsSnapshotValidated());
|
BOOST_CHECK(WITH_LOCK(::cs_main, return !manager.IsSnapshotValidated()));
|
||||||
BOOST_CHECK_EQUAL(&c2, &manager.ActiveChainstate());
|
BOOST_CHECK_EQUAL(&c2, &manager.ActiveChainstate());
|
||||||
BOOST_CHECK(&c1 != &manager.ActiveChainstate());
|
BOOST_CHECK(&c1 != &manager.ActiveChainstate());
|
||||||
auto all2 = manager.GetAll();
|
auto all2 = manager.GetAll();
|
||||||
|
|
|
@ -1921,7 +1921,7 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS] GUARDED_BY(cs_main);
|
static std::array<ThresholdConditionCache, VERSIONBITS_NUM_BITS> warningcache GUARDED_BY(cs_main);
|
||||||
|
|
||||||
static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const Consensus::Params& consensusparams)
|
static unsigned int GetBlockScriptFlags(const CBlockIndex& block_index, const Consensus::Params& consensusparams)
|
||||||
{
|
{
|
||||||
|
@ -2550,7 +2550,7 @@ void CChainState::UpdateTip(const CBlockIndex* pindexNew)
|
||||||
const CBlockIndex* pindex = pindexNew;
|
const CBlockIndex* pindex = pindexNew;
|
||||||
for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) {
|
for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) {
|
||||||
WarningBitsConditionChecker checker(bit);
|
WarningBitsConditionChecker checker(bit);
|
||||||
ThresholdState state = checker.GetStateFor(pindex, m_params.GetConsensus(), warningcache[bit]);
|
ThresholdState state = checker.GetStateFor(pindex, m_params.GetConsensus(), warningcache.at(bit));
|
||||||
if (state == ThresholdState::ACTIVE || state == ThresholdState::LOCKED_IN) {
|
if (state == ThresholdState::ACTIVE || state == ThresholdState::LOCKED_IN) {
|
||||||
const bilingual_str warning = strprintf(_("Unknown new rules activated (versionbit %i)"), bit);
|
const bilingual_str warning = strprintf(_("Unknown new rules activated (versionbit %i)"), bit);
|
||||||
if (state == ThresholdState::ACTIVE) {
|
if (state == ThresholdState::ACTIVE) {
|
||||||
|
@ -4143,20 +4143,6 @@ void CChainState::UnloadBlockIndex()
|
||||||
setBlockIndexCandidates.clear();
|
setBlockIndexCandidates.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// May NOT be used after any connections are up as much
|
|
||||||
// of the peer-processing logic assumes a consistent
|
|
||||||
// block index state
|
|
||||||
void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman)
|
|
||||||
{
|
|
||||||
AssertLockHeld(::cs_main);
|
|
||||||
chainman.Unload();
|
|
||||||
if (mempool) mempool->clear();
|
|
||||||
g_versionbitscache.Clear();
|
|
||||||
for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) {
|
|
||||||
warningcache[b].clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ChainstateManager::LoadBlockIndex()
|
bool ChainstateManager::LoadBlockIndex()
|
||||||
{
|
{
|
||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
|
@ -5187,20 +5173,6 @@ bool ChainstateManager::IsSnapshotActive() const
|
||||||
return m_snapshot_chainstate && m_active_chainstate == m_snapshot_chainstate.get();
|
return m_snapshot_chainstate && m_active_chainstate == m_snapshot_chainstate.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChainstateManager::Unload()
|
|
||||||
{
|
|
||||||
AssertLockHeld(::cs_main);
|
|
||||||
for (CChainState* chainstate : this->GetAll()) {
|
|
||||||
chainstate->m_chain.SetTip(nullptr);
|
|
||||||
chainstate->UnloadBlockIndex();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_failed_blocks.clear();
|
|
||||||
m_blockman.Unload();
|
|
||||||
m_best_header = nullptr;
|
|
||||||
m_best_invalid = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChainstateManager::MaybeRebalanceCaches()
|
void ChainstateManager::MaybeRebalanceCaches()
|
||||||
{
|
{
|
||||||
AssertLockHeld(::cs_main);
|
AssertLockHeld(::cs_main);
|
||||||
|
@ -5231,3 +5203,15 @@ void ChainstateManager::MaybeRebalanceCaches()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChainstateManager::~ChainstateManager()
|
||||||
|
{
|
||||||
|
LOCK(::cs_main);
|
||||||
|
|
||||||
|
// TODO: The version bits cache and warning cache should probably become
|
||||||
|
// non-globals
|
||||||
|
g_versionbitscache.Clear();
|
||||||
|
for (auto& i : warningcache) {
|
||||||
|
i.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -134,8 +134,6 @@ extern arith_uint256 nMinimumChainWork;
|
||||||
/** Documentation for argument 'checklevel'. */
|
/** Documentation for argument 'checklevel'. */
|
||||||
extern const std::vector<std::string> CHECKLEVEL_DOC;
|
extern const std::vector<std::string> CHECKLEVEL_DOC;
|
||||||
|
|
||||||
/** Unload database information */
|
|
||||||
void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
|
||||||
/** Run instances of script checking worker threads */
|
/** Run instances of script checking worker threads */
|
||||||
void StartScriptCheckWorkerThreads(int threads_num);
|
void StartScriptCheckWorkerThreads(int threads_num);
|
||||||
/** Stop all of the script checking worker threads */
|
/** Stop all of the script checking worker threads */
|
||||||
|
@ -831,9 +829,9 @@ private:
|
||||||
|
|
||||||
//! If true, the assumed-valid chainstate has been fully validated
|
//! If true, the assumed-valid chainstate has been fully validated
|
||||||
//! by the background validation chainstate.
|
//! by the background validation chainstate.
|
||||||
bool m_snapshot_validated{false};
|
bool m_snapshot_validated GUARDED_BY(::cs_main){false};
|
||||||
|
|
||||||
CBlockIndex* m_best_invalid;
|
CBlockIndex* m_best_invalid GUARDED_BY(::cs_main){nullptr};
|
||||||
|
|
||||||
//! Internal helper for ActivateSnapshot().
|
//! Internal helper for ActivateSnapshot().
|
||||||
[[nodiscard]] bool PopulateAndValidateSnapshot(
|
[[nodiscard]] bool PopulateAndValidateSnapshot(
|
||||||
|
@ -940,7 +938,7 @@ public:
|
||||||
std::optional<uint256> SnapshotBlockhash() const;
|
std::optional<uint256> SnapshotBlockhash() const;
|
||||||
|
|
||||||
//! Is there a snapshot in use and has it been fully validated?
|
//! Is there a snapshot in use and has it been fully validated?
|
||||||
bool IsSnapshotValidated() const { return m_snapshot_validated; }
|
bool IsSnapshotValidated() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { return m_snapshot_validated; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process an incoming block. This only returns after the best known valid
|
* Process an incoming block. This only returns after the best known valid
|
||||||
|
@ -988,17 +986,11 @@ public:
|
||||||
//! Load the block tree and coins database from disk, initializing state if we're running with -reindex
|
//! Load the block tree and coins database from disk, initializing state if we're running with -reindex
|
||||||
bool LoadBlockIndex() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
bool LoadBlockIndex() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
||||||
|
|
||||||
//! Unload block index and chain data before shutdown.
|
|
||||||
void Unload() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
|
||||||
|
|
||||||
//! Check to see if caches are out of balance and if so, call
|
//! Check to see if caches are out of balance and if so, call
|
||||||
//! ResizeCoinsCaches() as needed.
|
//! ResizeCoinsCaches() as needed.
|
||||||
void MaybeRebalanceCaches() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
void MaybeRebalanceCaches() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
||||||
|
|
||||||
~ChainstateManager() {
|
~ChainstateManager();
|
||||||
LOCK(::cs_main);
|
|
||||||
UnloadBlockIndex(/*mempool=*/nullptr, *this);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using FopenFn = std::function<FILE*(const fs::path&, const char*)>;
|
using FopenFn = std::function<FILE*(const fs::path&, const char*)>;
|
||||||
|
|
Loading…
Add table
Reference in a new issue