Skip to content

Commit ac94141

Browse files
committed
validation: delay flushing undo files in syncing node case
Data files are pre-allocated, and upon flush/finalization, they are trimmed down to their resulting size. Block (blk) files are written to disk as blocks come in, which is often out of order, whereas undo (rev) files are written sequentially, as each block is added to the top of the chain. When a block file hits the size limit, the system flushes and trims the file down to its final size, and moves on to the next block file. Case 1: blocks are added to the chain as they come in (synced up node case) -- in this case, we will flush and finalize the undo file together with the block file. Case 2: blocks are added to the chain after they have been downloaded (syncing node case) -- in this case, we postpone finalizing the undo file until we know the undo data for the last block in the file has been written to disk.
1 parent 04f78b8 commit ac94141

File tree

1 file changed

+27
-9
lines changed

1 file changed

+27
-9
lines changed

src/validation.cpp

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1731,19 +1731,24 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI
17311731
return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;
17321732
}
17331733

1734-
void static FlushBlockFile(bool fFinalize = false)
1734+
static void FlushUndoFile(int block_file, bool finalize = false)
17351735
{
1736-
LOCK(cs_LastBlockFile);
1736+
FlatFilePos undo_pos_old(block_file, vinfoBlockFile[block_file].nUndoSize);
1737+
if (!UndoFileSeq().Flush(undo_pos_old, finalize)) {
1738+
AbortNode("Flushing undo file to disk failed. This is likely the result of an I/O error.");
1739+
}
1740+
}
17371741

1742+
static void FlushBlockFile(bool fFinalize = false, bool finalize_undo = false)
1743+
{
1744+
LOCK(cs_LastBlockFile);
17381745
FlatFilePos block_pos_old(nLastBlockFile, vinfoBlockFile[nLastBlockFile].nSize);
1739-
FlatFilePos undo_pos_old(nLastBlockFile, vinfoBlockFile[nLastBlockFile].nUndoSize);
1740-
1741-
bool status = true;
1742-
status &= BlockFileSeq().Flush(block_pos_old, fFinalize);
1743-
status &= UndoFileSeq().Flush(undo_pos_old, fFinalize);
1744-
if (!status) {
1746+
if (!BlockFileSeq().Flush(block_pos_old, fFinalize)) {
17451747
AbortNode("Flushing block file to disk failed. This is likely the result of an I/O error.");
17461748
}
1749+
// we do not always flush the undo file, as the chain tip may be lagging behind the incoming blocks,
1750+
// e.g. during IBD or a sync after a node going offline
1751+
if (!fFinalize || finalize_undo) FlushUndoFile(nLastBlockFile, finalize_undo);
17471752
}
17481753

17491754
static bool FindUndoPos(BlockValidationState &state, int nFile, FlatFilePos &pos, unsigned int nAddSize);
@@ -1757,6 +1762,14 @@ static bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationSt
17571762
return error("ConnectBlock(): FindUndoPos failed");
17581763
if (!UndoWriteToDisk(blockundo, _pos, pindex->pprev->GetBlockHash(), chainparams.MessageStart()))
17591764
return AbortNode(state, "Failed to write undo data");
1765+
// rev files are written in block height order, whereas blk files are written as blocks come in (often out of order)
1766+
// we want to flush the rev (undo) file once we've written the last block, which is indicated by the last height
1767+
// in the block file info as below; note that this does not catch the case where the undo writes are keeping up
1768+
// with the block writes (usually when a synced up node is getting newly mined blocks) -- this case is caught in
1769+
// the FindBlockPos function
1770+
if (_pos.nFile < nLastBlockFile && static_cast<uint32_t>(pindex->nHeight) == vinfoBlockFile[_pos.nFile].nHeightLast) {
1771+
FlushUndoFile(_pos.nFile, true);
1772+
}
17601773

17611774
// update nUndoPos in block index
17621775
pindex->nUndoPos = _pos.nPos;
@@ -3220,8 +3233,13 @@ static bool FindBlockPos(FlatFilePos &pos, unsigned int nAddSize, unsigned int n
32203233
vinfoBlockFile.resize(nFile + 1);
32213234
}
32223235

3236+
bool finalize_undo = false;
32233237
if (!fKnown) {
32243238
while (vinfoBlockFile[nFile].nSize + nAddSize >= MAX_BLOCKFILE_SIZE) {
3239+
// when the undo file is keeping up with the block file, we want to flush it explicitly
3240+
// when it is lagging behind (more blocks arrive than are being connected), we let the
3241+
// undo block write case handle it
3242+
finalize_undo = (vinfoBlockFile[nFile].nHeightLast == (unsigned int)ChainActive().Tip()->nHeight);
32253243
nFile++;
32263244
if (vinfoBlockFile.size() <= nFile) {
32273245
vinfoBlockFile.resize(nFile + 1);
@@ -3235,7 +3253,7 @@ static bool FindBlockPos(FlatFilePos &pos, unsigned int nAddSize, unsigned int n
32353253
if (!fKnown) {
32363254
LogPrintf("Leaving block file %i: %s\n", nLastBlockFile, vinfoBlockFile[nLastBlockFile].ToString());
32373255
}
3238-
FlushBlockFile(!fKnown);
3256+
FlushBlockFile(!fKnown, finalize_undo);
32393257
nLastBlockFile = nFile;
32403258
}
32413259

0 commit comments

Comments
 (0)