mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-13 11:25:02 -05:00
Merge #13106: Simplify semantics of ChainStateFlushed callback
9cb6cdc
Simplify semantics of ChainStateFlushed callback (Matt Corallo)50b6533
scripted-diff: Rename SetBestChain callback ChainStateFlushed (Matt Corallo) Pull request description: Previously, ChainStateFlushed would fire either if a full flush completed (which can happen due to memory limits, forced flush, or on its own DATABASE_WRITE_INTERVAL timer) *or* on a ChainStateFlushed-specific DATABASE_WRITE_INTERVAL timer. This is both less clear for clients (as there are no guarantees about a flush having actually happened prior to the call), and reults in extra flushes not clearly intended by the code. We drop the second case, providing a strong guarantee without removing the periodit timer-based flushing. This is a follow-up to discussion in #11857. Tree-SHA512: 22ba3a0954d265d28413dbf87040790ca5b439820ee7bbadab14028295ec190de82ce5cd664426c82e58b706dc84278868026fa8d066702eb6e6962c9ace1f8e
This commit is contained in:
commit
598db389c3
7 changed files with 33 additions and 26 deletions
|
@ -192,7 +192,7 @@ void TxIndex::BlockConnected(const std::shared_ptr<const CBlock>& block, const C
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TxIndex::SetBestChain(const CBlockLocator& locator)
|
void TxIndex::ChainStateFlushed(const CBlockLocator& locator)
|
||||||
{
|
{
|
||||||
if (!m_synced) {
|
if (!m_synced) {
|
||||||
return;
|
return;
|
||||||
|
@ -211,7 +211,7 @@ void TxIndex::SetBestChain(const CBlockLocator& locator)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This checks that SetBestChain callbacks are received after BlockConnected. The check may fail
|
// This checks that ChainStateFlushed callbacks are received after BlockConnected. The check may fail
|
||||||
// immediately after the the sync thread catches up and sets m_synced. Consider the case where
|
// immediately after the the sync thread catches up and sets m_synced. Consider the case where
|
||||||
// there is a reorg and the blocks on the stale branch are in the ValidationInterface queue
|
// there is a reorg and the blocks on the stale branch are in the ValidationInterface queue
|
||||||
// backlog even after the sync thread has caught up to the new chain tip. In this unlikely
|
// backlog even after the sync thread has caught up to the new chain tip. In this unlikely
|
||||||
|
|
|
@ -55,7 +55,7 @@ protected:
|
||||||
void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex,
|
void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex,
|
||||||
const std::vector<CTransactionRef>& txn_conflicted) override;
|
const std::vector<CTransactionRef>& txn_conflicted) override;
|
||||||
|
|
||||||
void SetBestChain(const CBlockLocator& locator) override;
|
void ChainStateFlushed(const CBlockLocator& locator) override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Constructs the TxIndex, which becomes available to be queried.
|
/// Constructs the TxIndex, which becomes available to be queried.
|
||||||
|
|
|
@ -2066,13 +2066,12 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
|
||||||
LOCK(cs_main);
|
LOCK(cs_main);
|
||||||
static int64_t nLastWrite = 0;
|
static int64_t nLastWrite = 0;
|
||||||
static int64_t nLastFlush = 0;
|
static int64_t nLastFlush = 0;
|
||||||
static int64_t nLastSetChain = 0;
|
|
||||||
std::set<int> setFilesToPrune;
|
std::set<int> setFilesToPrune;
|
||||||
bool fFlushForPrune = false;
|
bool full_flush_completed = false;
|
||||||
bool fDoFullFlush = false;
|
|
||||||
int64_t nNow = 0;
|
|
||||||
try {
|
try {
|
||||||
{
|
{
|
||||||
|
bool fFlushForPrune = false;
|
||||||
|
bool fDoFullFlush = false;
|
||||||
LOCK(cs_LastBlockFile);
|
LOCK(cs_LastBlockFile);
|
||||||
if (fPruneMode && (fCheckForPruning || nManualPruneHeight > 0) && !fReindex) {
|
if (fPruneMode && (fCheckForPruning || nManualPruneHeight > 0) && !fReindex) {
|
||||||
if (nManualPruneHeight > 0) {
|
if (nManualPruneHeight > 0) {
|
||||||
|
@ -2089,7 +2088,7 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nNow = GetTimeMicros();
|
int64_t nNow = GetTimeMicros();
|
||||||
// Avoid writing/flushing immediately after startup.
|
// Avoid writing/flushing immediately after startup.
|
||||||
if (nLastWrite == 0) {
|
if (nLastWrite == 0) {
|
||||||
nLastWrite = nNow;
|
nLastWrite = nNow;
|
||||||
|
@ -2097,9 +2096,6 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
|
||||||
if (nLastFlush == 0) {
|
if (nLastFlush == 0) {
|
||||||
nLastFlush = nNow;
|
nLastFlush = nNow;
|
||||||
}
|
}
|
||||||
if (nLastSetChain == 0) {
|
|
||||||
nLastSetChain = nNow;
|
|
||||||
}
|
|
||||||
int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
|
int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
|
||||||
int64_t cacheSize = pcoinsTip->DynamicMemoryUsage();
|
int64_t cacheSize = pcoinsTip->DynamicMemoryUsage();
|
||||||
int64_t nTotalSpace = nCoinCacheUsage + std::max<int64_t>(nMempoolSizeMax - nMempoolUsage, 0);
|
int64_t nTotalSpace = nCoinCacheUsage + std::max<int64_t>(nMempoolSizeMax - nMempoolUsage, 0);
|
||||||
|
@ -2156,12 +2152,12 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
|
||||||
if (!pcoinsTip->Flush())
|
if (!pcoinsTip->Flush())
|
||||||
return AbortNode(state, "Failed to write to coin database");
|
return AbortNode(state, "Failed to write to coin database");
|
||||||
nLastFlush = nNow;
|
nLastFlush = nNow;
|
||||||
|
full_flush_completed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fDoFullFlush || ((mode == FlushStateMode::ALWAYS || mode == FlushStateMode::PERIODIC) && nNow > nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000)) {
|
if (full_flush_completed) {
|
||||||
// Update best block in wallet (so we can detect restored wallets).
|
// Update best block in wallet (so we can detect restored wallets).
|
||||||
GetMainSignals().SetBestChain(chainActive.GetLocator());
|
GetMainSignals().ChainStateFlushed(chainActive.GetLocator());
|
||||||
nLastSetChain = nNow;
|
|
||||||
}
|
}
|
||||||
} catch (const std::runtime_error& e) {
|
} catch (const std::runtime_error& e) {
|
||||||
return AbortNode(state, std::string("System error while flushing: ") + e.what());
|
return AbortNode(state, std::string("System error while flushing: ") + e.what());
|
||||||
|
|
|
@ -25,7 +25,7 @@ struct MainSignalsInstance {
|
||||||
boost::signals2::signal<void (const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::vector<CTransactionRef>&)> BlockConnected;
|
boost::signals2::signal<void (const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::vector<CTransactionRef>&)> BlockConnected;
|
||||||
boost::signals2::signal<void (const std::shared_ptr<const CBlock> &)> BlockDisconnected;
|
boost::signals2::signal<void (const std::shared_ptr<const CBlock> &)> BlockDisconnected;
|
||||||
boost::signals2::signal<void (const CTransactionRef &)> TransactionRemovedFromMempool;
|
boost::signals2::signal<void (const CTransactionRef &)> TransactionRemovedFromMempool;
|
||||||
boost::signals2::signal<void (const CBlockLocator &)> SetBestChain;
|
boost::signals2::signal<void (const CBlockLocator &)> ChainStateFlushed;
|
||||||
boost::signals2::signal<void (const uint256 &)> Inventory;
|
boost::signals2::signal<void (const uint256 &)> Inventory;
|
||||||
boost::signals2::signal<void (int64_t nBestBlockTime, CConnman* connman)> Broadcast;
|
boost::signals2::signal<void (int64_t nBestBlockTime, CConnman* connman)> Broadcast;
|
||||||
boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
|
boost::signals2::signal<void (const CBlock&, const CValidationState&)> BlockChecked;
|
||||||
|
@ -80,7 +80,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
|
||||||
g_signals.m_internals->BlockConnected.connect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
|
g_signals.m_internals->BlockConnected.connect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
|
||||||
g_signals.m_internals->BlockDisconnected.connect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
|
g_signals.m_internals->BlockDisconnected.connect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
|
||||||
g_signals.m_internals->TransactionRemovedFromMempool.connect(boost::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, _1));
|
g_signals.m_internals->TransactionRemovedFromMempool.connect(boost::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, _1));
|
||||||
g_signals.m_internals->SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
|
g_signals.m_internals->ChainStateFlushed.connect(boost::bind(&CValidationInterface::ChainStateFlushed, pwalletIn, _1));
|
||||||
g_signals.m_internals->Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
|
g_signals.m_internals->Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
|
||||||
g_signals.m_internals->Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
|
g_signals.m_internals->Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
|
||||||
g_signals.m_internals->BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
|
g_signals.m_internals->BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
|
||||||
|
@ -91,7 +91,7 @@ void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
|
||||||
g_signals.m_internals->BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
|
g_signals.m_internals->BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
|
||||||
g_signals.m_internals->Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
|
g_signals.m_internals->Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
|
||||||
g_signals.m_internals->Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
|
g_signals.m_internals->Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
|
||||||
g_signals.m_internals->SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
|
g_signals.m_internals->ChainStateFlushed.disconnect(boost::bind(&CValidationInterface::ChainStateFlushed, pwalletIn, _1));
|
||||||
g_signals.m_internals->TransactionAddedToMempool.disconnect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
|
g_signals.m_internals->TransactionAddedToMempool.disconnect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
|
||||||
g_signals.m_internals->BlockConnected.disconnect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
|
g_signals.m_internals->BlockConnected.disconnect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
|
||||||
g_signals.m_internals->BlockDisconnected.disconnect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
|
g_signals.m_internals->BlockDisconnected.disconnect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
|
||||||
|
@ -107,7 +107,7 @@ void UnregisterAllValidationInterfaces() {
|
||||||
g_signals.m_internals->BlockChecked.disconnect_all_slots();
|
g_signals.m_internals->BlockChecked.disconnect_all_slots();
|
||||||
g_signals.m_internals->Broadcast.disconnect_all_slots();
|
g_signals.m_internals->Broadcast.disconnect_all_slots();
|
||||||
g_signals.m_internals->Inventory.disconnect_all_slots();
|
g_signals.m_internals->Inventory.disconnect_all_slots();
|
||||||
g_signals.m_internals->SetBestChain.disconnect_all_slots();
|
g_signals.m_internals->ChainStateFlushed.disconnect_all_slots();
|
||||||
g_signals.m_internals->TransactionAddedToMempool.disconnect_all_slots();
|
g_signals.m_internals->TransactionAddedToMempool.disconnect_all_slots();
|
||||||
g_signals.m_internals->BlockConnected.disconnect_all_slots();
|
g_signals.m_internals->BlockConnected.disconnect_all_slots();
|
||||||
g_signals.m_internals->BlockDisconnected.disconnect_all_slots();
|
g_signals.m_internals->BlockDisconnected.disconnect_all_slots();
|
||||||
|
@ -166,9 +166,9 @@ void CMainSignals::BlockDisconnected(const std::shared_ptr<const CBlock> &pblock
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMainSignals::SetBestChain(const CBlockLocator &locator) {
|
void CMainSignals::ChainStateFlushed(const CBlockLocator &locator) {
|
||||||
m_internals->m_schedulerClient.AddToProcessQueue([locator, this] {
|
m_internals->m_schedulerClient.AddToProcessQueue([locator, this] {
|
||||||
m_internals->SetBestChain(locator);
|
m_internals->ChainStateFlushed(locator);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -99,9 +99,20 @@ protected:
|
||||||
/**
|
/**
|
||||||
* Notifies listeners of the new active block chain on-disk.
|
* Notifies listeners of the new active block chain on-disk.
|
||||||
*
|
*
|
||||||
|
* Prior to this callback, any updates are not guaranteed to persist on disk
|
||||||
|
* (ie clients need to handle shutdown/restart safety by being able to
|
||||||
|
* understand when some updates were lost due to unclean shutdown).
|
||||||
|
*
|
||||||
|
* When this callback is invoked, the validation changes done by any prior
|
||||||
|
* callback are guaranteed to exist on disk and survive a restart, including
|
||||||
|
* an unclean shutdown.
|
||||||
|
*
|
||||||
|
* Provides a locator describing the best chain, which is likely useful for
|
||||||
|
* storing current state on disk in client DBs.
|
||||||
|
*
|
||||||
* Called on a background thread.
|
* Called on a background thread.
|
||||||
*/
|
*/
|
||||||
virtual void SetBestChain(const CBlockLocator &locator) {}
|
virtual void ChainStateFlushed(const CBlockLocator &locator) {}
|
||||||
/**
|
/**
|
||||||
* Notifies listeners about an inventory item being seen on the network.
|
* Notifies listeners about an inventory item being seen on the network.
|
||||||
*
|
*
|
||||||
|
@ -157,7 +168,7 @@ public:
|
||||||
void TransactionAddedToMempool(const CTransactionRef &);
|
void TransactionAddedToMempool(const CTransactionRef &);
|
||||||
void BlockConnected(const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::shared_ptr<const std::vector<CTransactionRef>> &);
|
void BlockConnected(const std::shared_ptr<const CBlock> &, const CBlockIndex *pindex, const std::shared_ptr<const std::vector<CTransactionRef>> &);
|
||||||
void BlockDisconnected(const std::shared_ptr<const CBlock> &);
|
void BlockDisconnected(const std::shared_ptr<const CBlock> &);
|
||||||
void SetBestChain(const CBlockLocator &);
|
void ChainStateFlushed(const CBlockLocator &);
|
||||||
void Inventory(const uint256 &);
|
void Inventory(const uint256 &);
|
||||||
void Broadcast(int64_t nBestBlockTime, CConnman* connman);
|
void Broadcast(int64_t nBestBlockTime, CConnman* connman);
|
||||||
void BlockChecked(const CBlock&, const CValidationState&);
|
void BlockChecked(const CBlock&, const CValidationState&);
|
||||||
|
|
|
@ -453,7 +453,7 @@ bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CWallet::SetBestChain(const CBlockLocator& loc)
|
void CWallet::ChainStateFlushed(const CBlockLocator& loc)
|
||||||
{
|
{
|
||||||
WalletBatch batch(*database);
|
WalletBatch batch(*database);
|
||||||
batch.WriteBestBlock(loc);
|
batch.WriteBestBlock(loc);
|
||||||
|
@ -4038,7 +4038,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path&
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
walletInstance->SetBestChain(chainActive.GetLocator());
|
walletInstance->ChainStateFlushed(chainActive.GetLocator());
|
||||||
} else if (gArgs.IsArgSet("-usehd")) {
|
} else if (gArgs.IsArgSet("-usehd")) {
|
||||||
bool useHD = gArgs.GetBoolArg("-usehd", true);
|
bool useHD = gArgs.GetBoolArg("-usehd", true);
|
||||||
if (walletInstance->IsHDEnabled() && !useHD) {
|
if (walletInstance->IsHDEnabled() && !useHD) {
|
||||||
|
@ -4180,7 +4180,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string& name, const fs::path&
|
||||||
walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, reserver, true);
|
walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, reserver, true);
|
||||||
}
|
}
|
||||||
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
|
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
|
||||||
walletInstance->SetBestChain(chainActive.GetLocator());
|
walletInstance->ChainStateFlushed(chainActive.GetLocator());
|
||||||
walletInstance->database->IncrementUpdateCounter();
|
walletInstance->database->IncrementUpdateCounter();
|
||||||
|
|
||||||
// Restore wallet transaction metadata after -zapwallettxes=1
|
// Restore wallet transaction metadata after -zapwallettxes=1
|
||||||
|
|
|
@ -1013,7 +1013,7 @@ public:
|
||||||
bool IsAllFromMe(const CTransaction& tx, const isminefilter& filter) const;
|
bool IsAllFromMe(const CTransaction& tx, const isminefilter& filter) const;
|
||||||
CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const;
|
CAmount GetCredit(const CTransaction& tx, const isminefilter& filter) const;
|
||||||
CAmount GetChange(const CTransaction& tx) const;
|
CAmount GetChange(const CTransaction& tx) const;
|
||||||
void SetBestChain(const CBlockLocator& loc) override;
|
void ChainStateFlushed(const CBlockLocator& loc) override;
|
||||||
|
|
||||||
DBErrors LoadWallet(bool& fFirstRunRet);
|
DBErrors LoadWallet(bool& fFirstRunRet);
|
||||||
DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);
|
DBErrors ZapWalletTx(std::vector<CWalletTx>& vWtx);
|
||||||
|
|
Loading…
Add table
Reference in a new issue