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:
Wladimir J. van der Laan 2018-05-02 13:04:02 +02:00 committed by UdjinM6
parent 370ec04a02
commit 56bd5aea1b
No known key found for this signature in database
GPG Key ID: 83592BD1400D58D9
7 changed files with 33 additions and 26 deletions

View File

@ -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

View File

@ -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.

View File

@ -2450,13 +2450,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) {
@ -2473,7 +2472,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;
@ -2481,9 +2480,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();
cacheSize += evoDb->GetMemoryUsage(); cacheSize += evoDb->GetMemoryUsage();
@ -2544,12 +2540,12 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
return AbortNode(state, "Failed to commit EvoDB"); return AbortNode(state, "Failed to commit EvoDB");
} }
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());

View File

@ -26,7 +26,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> &, const CBlockIndex* pindexDisconnected)> BlockDisconnected; boost::signals2::signal<void (const std::shared_ptr<const CBlock> &, const CBlockIndex* pindexDisconnected)> BlockDisconnected;
boost::signals2::signal<void (const CTransactionRef &, MemPoolRemovalReason)> TransactionRemovedFromMempool; boost::signals2::signal<void (const CTransactionRef &, MemPoolRemovalReason)> TransactionRemovedFromMempool;
boost::signals2::signal<void (const CBlockLocator &)> SetBestChain; boost::signals2::signal<void (const CBlockLocator &)> ChainStateFlushed;
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;
boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock; boost::signals2::signal<void (const CBlockIndex *, const std::shared_ptr<const CBlock>&)> NewPoWValidBlock;
@ -93,7 +93,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
g_signals.m_internals->NotifyTransactionLock.connect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, _1, _2)); g_signals.m_internals->NotifyTransactionLock.connect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, _1, _2));
g_signals.m_internals->NotifyChainLock.connect(boost::bind(&CValidationInterface::NotifyChainLock, pwalletIn, _1, _2)); g_signals.m_internals->NotifyChainLock.connect(boost::bind(&CValidationInterface::NotifyChainLock, pwalletIn, _1, _2));
g_signals.m_internals->TransactionRemovedFromMempool.connect(boost::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, _1, _2)); g_signals.m_internals->TransactionRemovedFromMempool.connect(boost::bind(&CValidationInterface::TransactionRemovedFromMempool, pwalletIn, _1, _2));
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->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));
g_signals.m_internals->NewPoWValidBlock.connect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2)); g_signals.m_internals->NewPoWValidBlock.connect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
@ -107,7 +107,7 @@ void RegisterValidationInterface(CValidationInterface* pwalletIn) {
void UnregisterValidationInterface(CValidationInterface* pwalletIn) { 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->SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1)); g_signals.m_internals->ChainStateFlushed.disconnect(boost::bind(&CValidationInterface::ChainStateFlushed, pwalletIn, _1));
g_signals.m_internals->NotifyChainLock.disconnect(boost::bind(&CValidationInterface::NotifyChainLock, pwalletIn, _1, _2)); g_signals.m_internals->NotifyChainLock.disconnect(boost::bind(&CValidationInterface::NotifyChainLock, pwalletIn, _1, _2));
g_signals.m_internals->NotifyTransactionLock.disconnect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, _1, _2)); g_signals.m_internals->NotifyTransactionLock.disconnect(boost::bind(&CValidationInterface::NotifyTransactionLock, pwalletIn, _1, _2));
g_signals.m_internals->TransactionAddedToMempool.disconnect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1, _2)); g_signals.m_internals->TransactionAddedToMempool.disconnect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1, _2));
@ -132,7 +132,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->SetBestChain.disconnect_all_slots(); g_signals.m_internals->ChainStateFlushed.disconnect_all_slots();
g_signals.m_internals->NotifyTransactionLock.disconnect_all_slots(); g_signals.m_internals->NotifyTransactionLock.disconnect_all_slots();
g_signals.m_internals->NotifyChainLock.disconnect_all_slots(); g_signals.m_internals->NotifyChainLock.disconnect_all_slots();
g_signals.m_internals->TransactionAddedToMempool.disconnect_all_slots(); g_signals.m_internals->TransactionAddedToMempool.disconnect_all_slots();
@ -205,9 +205,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);
}); });
} }

View File

@ -136,9 +136,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) {}
/** Tells listeners to broadcast their data. */ /** Tells listeners to broadcast their data. */
virtual void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) {} virtual void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) {}
/** /**
@ -198,7 +209,7 @@ public:
void NotifyInstantSendDoubleSpendAttempt(const CTransactionRef &currentTx, const CTransactionRef &previousTx); void NotifyInstantSendDoubleSpendAttempt(const CTransactionRef &currentTx, const CTransactionRef &previousTx);
void NotifyRecoveredSig(const std::shared_ptr<const llmq::CRecoveredSig> &sig); void NotifyRecoveredSig(const std::shared_ptr<const llmq::CRecoveredSig> &sig);
void NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff); void NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff);
void SetBestChain(const CBlockLocator &); void ChainStateFlushed(const CBlockLocator &);
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&);
void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr<const CBlock>&); void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr<const CBlock>&);

View File

@ -627,7 +627,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);
@ -5093,7 +5093,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(const WalletLocation& loc
return error(_("Unable to generate initial keys")); return error(_("Unable to generate initial keys"));
} }
walletInstance->SetBestChain(chainActive.GetLocator()); walletInstance->ChainStateFlushed(chainActive.GetLocator());
// Try to create wallet backup right after new wallet was created // Try to create wallet backup right after new wallet was created
std::string strBackupWarning; std::string strBackupWarning;
@ -5240,7 +5240,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(const WalletLocation& loc
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

View File

@ -1120,7 +1120,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);
void AutoLockMasternodeCollaterals(); void AutoLockMasternodeCollaterals();