0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-08 10:31:50 -05:00
This commit is contained in:
Martin Zumsande 2025-01-31 21:47:56 +01:00 committed by GitHub
commit ea0c954222
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 31 additions and 9 deletions

View file

@ -95,26 +95,32 @@ bool CCoinsViewDB::BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashB
size_t count = 0; size_t count = 0;
size_t changed = 0; size_t changed = 0;
assert(!hashBlock.IsNull()); assert(!hashBlock.IsNull());
bool unfinished_replay{false};
uint256 old_tip = GetBestBlock(); uint256 old_tip = GetBestBlock();
if (old_tip.IsNull()) { if (old_tip.IsNull()) {
// We may be in the middle of replaying. // We may be in the process of replaying.
std::vector<uint256> old_heads = GetHeadBlocks(); std::vector<uint256> old_heads = GetHeadBlocks();
if (old_heads.size() == 2) { if (old_heads.size() == 2) {
if (old_heads[0] != hashBlock) { if (old_heads[0] != hashBlock) {
LogPrintLevel(BCLog::COINDB, BCLog::Level::Error, "The coins database detected an inconsistent state, likely due to a previous crash or shutdown. You will need to restart bitcoind with the -reindex-chainstate or -reindex configuration option.\n"); // We haven't reached the target of replaying yet.
} // This happens if the replay was interrupted by the user.
assert(old_heads[0] == hashBlock); unfinished_replay = true;
} else {
// Replaying has reached its end, flush the results.
old_tip = old_heads[1]; old_tip = old_heads[1];
} }
} }
}
// In the first batch, mark the database as being in the middle of a // In the first batch, mark the database as being in the middle of a
// transition from old_tip to hashBlock. // transition from old_tip to hashBlock.
// A vector is used for future extensibility, as we may want to support // A vector is used for future extensibility, as we may want to support
// interrupting after partial writes from multiple independent reorgs. // interrupting after partial writes from multiple independent reorgs.
if (!unfinished_replay) {
batch.Erase(DB_BEST_BLOCK); batch.Erase(DB_BEST_BLOCK);
batch.Write(DB_HEAD_BLOCKS, Vector(hashBlock, old_tip)); batch.Write(DB_HEAD_BLOCKS, Vector(hashBlock, old_tip));
}
for (auto it{cursor.Begin()}; it != cursor.End();) { for (auto it{cursor.Begin()}; it != cursor.End();) {
if (it->second.IsDirty()) { if (it->second.IsDirty()) {
@ -141,9 +147,19 @@ bool CCoinsViewDB::BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashB
} }
} }
if (unfinished_replay) {
// This is called when, during ReplayBlocks, an interrupt is received.
// Update the replay origin (saved in second place in DB_HEAD_BLOCKS)
// so that the replay can pick up from here after restart.
// The replay target remains unchanged.
std::vector<uint256> old_heads = GetHeadBlocks();
assert(old_heads.size() == 2);
batch.Write(DB_HEAD_BLOCKS, Vector(old_heads[0], hashBlock));
} else {
// In the last batch, mark the database as consistent with hashBlock again. // In the last batch, mark the database as consistent with hashBlock again.
batch.Erase(DB_HEAD_BLOCKS); batch.Erase(DB_HEAD_BLOCKS);
batch.Write(DB_BEST_BLOCK, hashBlock); batch.Write(DB_BEST_BLOCK, hashBlock);
}
LogDebug(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0)); LogDebug(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0));
bool ret = m_db->WriteBatch(batch); bool ret = m_db->WriteBatch(batch);

View file

@ -4976,6 +4976,12 @@ bool Chainstate::ReplayBlocks()
LogPrintf("Rolling forward %s (%i)\n", pindex.GetBlockHash().ToString(), nHeight); LogPrintf("Rolling forward %s (%i)\n", pindex.GetBlockHash().ToString(), nHeight);
m_chainman.GetNotifications().progress(_("Replaying blocks…"), (int)((nHeight - nForkHeight) * 100.0 / (pindexNew->nHeight - nForkHeight)), false); m_chainman.GetNotifications().progress(_("Replaying blocks…"), (int)((nHeight - nForkHeight) * 100.0 / (pindexNew->nHeight - nForkHeight)), false);
if (!RollforwardBlock(&pindex, cache)) return false; if (!RollforwardBlock(&pindex, cache)) return false;
if (m_chainman.m_interrupt) {
LogInfo("Flushing intermediate state of replay\n");
cache.SetBestBlock(pindex.GetBlockHash());
cache.Flush();
return false;
}
} }
cache.SetBestBlock(pindexNew->GetBlockHash()); cache.SetBestBlock(pindexNew->GetBlockHash());