10
10
#include < dbwrapper.h>
11
11
#include < flatfile.h>
12
12
#include < hash.h>
13
+ #include < kernel/chain.h>
13
14
#include < kernel/chainparams.h>
14
15
#include < kernel/messagestartchars.h>
15
16
#include < logging.h>
@@ -273,7 +274,7 @@ void BlockManager::FindFilesToPruneManual(
273
274
const auto [min_block_to_prune, last_block_can_prune] = chainman.GetPruneRange (chain, nManualPruneHeight);
274
275
275
276
int count = 0 ;
276
- for (int fileNumber = 0 ; fileNumber < m_last_blockfile ; fileNumber++) {
277
+ for (int fileNumber = 0 ; fileNumber < this -> MaxBlockfileNum () ; fileNumber++) {
277
278
const auto & fileinfo = m_blockfile_info[fileNumber];
278
279
if (fileinfo.nSize == 0 || fileinfo.nHeightLast > (unsigned )last_block_can_prune || fileinfo.nHeightFirst < (unsigned )min_block_to_prune) {
279
280
continue ;
@@ -325,7 +326,7 @@ void BlockManager::FindFilesToPrune(
325
326
nBuffer += target / 10 ;
326
327
}
327
328
328
- for (int fileNumber = 0 ; fileNumber < m_last_blockfile ; fileNumber++) {
329
+ for (int fileNumber = 0 ; fileNumber < this -> MaxBlockfileNum () ; fileNumber++) {
329
330
const auto & fileinfo = m_blockfile_info[fileNumber];
330
331
nBytesToPrune = fileinfo.nSize + fileinfo.nUndoSize ;
331
332
@@ -385,19 +386,25 @@ bool BlockManager::LoadBlockIndex(const std::optional<uint256>& snapshot_blockha
385
386
return false ;
386
387
}
387
388
388
- int snapshot_height = -1 ;
389
389
if (snapshot_blockhash) {
390
390
const AssumeutxoData au_data = *Assert (GetParams ().AssumeutxoForBlockhash (*snapshot_blockhash));
391
- snapshot_height = au_data.height ;
391
+ m_snapshot_height = au_data.height ;
392
392
CBlockIndex* base{LookupBlockIndex (*snapshot_blockhash)};
393
393
394
- // Since nChainTx (responsible for estiamted progress) isn't persisted
394
+ // Since nChainTx (responsible for estimated progress) isn't persisted
395
395
// to disk, we must bootstrap the value for assumedvalid chainstates
396
396
// from the hardcoded assumeutxo chainparams.
397
397
base->nChainTx = au_data.nChainTx ;
398
398
LogPrintf (" [snapshot] set nChainTx=%d for %s\n " , au_data.nChainTx , snapshot_blockhash->ToString ());
399
+ } else {
400
+ // If this isn't called with a snapshot blockhash, make sure the cached snapshot height
401
+ // is null. This is relevant during snapshot completion, when the blockman may be loaded
402
+ // with a height that then needs to be cleared after the snapshot is fully validated.
403
+ m_snapshot_height.reset ();
399
404
}
400
405
406
+ Assert (m_snapshot_height.has_value () == snapshot_blockhash.has_value ());
407
+
401
408
// Calculate nChainWork
402
409
std::vector<CBlockIndex*> vSortedByHeight{GetAllBlockIndices ()};
403
410
std::sort (vSortedByHeight.begin (), vSortedByHeight.end (),
@@ -414,7 +421,7 @@ bool BlockManager::LoadBlockIndex(const std::optional<uint256>& snapshot_blockha
414
421
// Pruned nodes may have deleted the block.
415
422
if (pindex->nTx > 0 ) {
416
423
if (pindex->pprev ) {
417
- if (snapshot_blockhash && pindex->nHeight == snapshot_height &&
424
+ if (m_snapshot_height && pindex->nHeight == *m_snapshot_height &&
418
425
pindex->GetBlockHash () == *snapshot_blockhash) {
419
426
// Should have been set above; don't disturb it with code below.
420
427
Assert (pindex->nChainTx > 0 );
@@ -455,7 +462,8 @@ bool BlockManager::WriteBlockIndexDB()
455
462
vBlocks.push_back (*it);
456
463
m_dirty_blockindex.erase (it++);
457
464
}
458
- if (!m_block_tree_db->WriteBatchSync (vFiles, m_last_blockfile, vBlocks)) {
465
+ int max_blockfile = WITH_LOCK (cs_LastBlockFile, return this ->MaxBlockfileNum ());
466
+ if (!m_block_tree_db->WriteBatchSync (vFiles, max_blockfile, vBlocks)) {
459
467
return false ;
460
468
}
461
469
return true ;
@@ -466,16 +474,17 @@ bool BlockManager::LoadBlockIndexDB(const std::optional<uint256>& snapshot_block
466
474
if (!LoadBlockIndex (snapshot_blockhash)) {
467
475
return false ;
468
476
}
477
+ int max_blockfile_num{0 };
469
478
470
479
// Load block file info
471
- m_block_tree_db->ReadLastBlockFile (m_last_blockfile );
472
- m_blockfile_info.resize (m_last_blockfile + 1 );
473
- LogPrintf (" %s: last block file = %i\n " , __func__, m_last_blockfile );
474
- for (int nFile = 0 ; nFile <= m_last_blockfile ; nFile++) {
480
+ m_block_tree_db->ReadLastBlockFile (max_blockfile_num );
481
+ m_blockfile_info.resize (max_blockfile_num + 1 );
482
+ LogPrintf (" %s: last block file = %i\n " , __func__, max_blockfile_num );
483
+ for (int nFile = 0 ; nFile <= max_blockfile_num ; nFile++) {
475
484
m_block_tree_db->ReadBlockFileInfo (nFile, m_blockfile_info[nFile]);
476
485
}
477
- LogPrintf (" %s: last block file info: %s\n " , __func__, m_blockfile_info[m_last_blockfile ].ToString ());
478
- for (int nFile = m_last_blockfile + 1 ; true ; nFile++) {
486
+ LogPrintf (" %s: last block file info: %s\n " , __func__, m_blockfile_info[max_blockfile_num ].ToString ());
487
+ for (int nFile = max_blockfile_num + 1 ; true ; nFile++) {
479
488
CBlockFileInfo info;
480
489
if (m_block_tree_db->ReadBlockFileInfo (nFile, info)) {
481
490
m_blockfile_info.push_back (info);
@@ -499,6 +508,15 @@ bool BlockManager::LoadBlockIndexDB(const std::optional<uint256>& snapshot_block
499
508
}
500
509
}
501
510
511
+ {
512
+ // Initialize the blockfile cursors.
513
+ LOCK (cs_LastBlockFile);
514
+ for (size_t i = 0 ; i < m_blockfile_info.size (); ++i) {
515
+ const auto last_height_in_file = m_blockfile_info[i].nHeightLast ;
516
+ m_blockfile_cursors[BlockfileTypeForHeight (last_height_in_file)] = {static_cast <int >(i), 0 };
517
+ }
518
+ }
519
+
502
520
// Check whether we have ever pruned block & undo files
503
521
m_block_tree_db->ReadFlag (" prunedblockfiles" , m_have_pruned);
504
522
if (m_have_pruned) {
@@ -516,12 +534,13 @@ bool BlockManager::LoadBlockIndexDB(const std::optional<uint256>& snapshot_block
516
534
void BlockManager::ScanAndUnlinkAlreadyPrunedFiles ()
517
535
{
518
536
AssertLockHeld (::cs_main);
537
+ int max_blockfile = WITH_LOCK (cs_LastBlockFile, return this ->MaxBlockfileNum ());
519
538
if (!m_have_pruned) {
520
539
return ;
521
540
}
522
541
523
542
std::set<int > block_files_to_prune;
524
- for (int file_number = 0 ; file_number < m_last_blockfile ; file_number++) {
543
+ for (int file_number = 0 ; file_number < max_blockfile ; file_number++) {
525
544
if (m_blockfile_info[file_number].nSize == 0 ) {
526
545
block_files_to_prune.insert (file_number);
527
546
}
@@ -696,7 +715,7 @@ bool BlockManager::FlushUndoFile(int block_file, bool finalize)
696
715
return true ;
697
716
}
698
717
699
- bool BlockManager::FlushBlockFile (bool fFinalize , bool finalize_undo)
718
+ bool BlockManager::FlushBlockFile (int blockfile_num, bool fFinalize , bool finalize_undo)
700
719
{
701
720
bool success = true ;
702
721
LOCK (cs_LastBlockFile);
@@ -708,23 +727,43 @@ bool BlockManager::FlushBlockFile(bool fFinalize, bool finalize_undo)
708
727
// have populated `m_blockfile_info` via LoadBlockIndexDB().
709
728
return true ;
710
729
}
711
- assert (static_cast <int >(m_blockfile_info.size ()) > m_last_blockfile );
730
+ assert (static_cast <int >(m_blockfile_info.size ()) > blockfile_num );
712
731
713
- FlatFilePos block_pos_old (m_last_blockfile , m_blockfile_info[m_last_blockfile ].nSize );
732
+ FlatFilePos block_pos_old (blockfile_num , m_blockfile_info[blockfile_num ].nSize );
714
733
if (!BlockFileSeq ().Flush (block_pos_old, fFinalize )) {
715
734
m_opts.notifications .flushError (" Flushing block file to disk failed. This is likely the result of an I/O error." );
716
735
success = false ;
717
736
}
718
737
// we do not always flush the undo file, as the chain tip may be lagging behind the incoming blocks,
719
738
// e.g. during IBD or a sync after a node going offline
720
739
if (!fFinalize || finalize_undo) {
721
- if (!FlushUndoFile (m_last_blockfile , finalize_undo)) {
740
+ if (!FlushUndoFile (blockfile_num , finalize_undo)) {
722
741
success = false ;
723
742
}
724
743
}
725
744
return success;
726
745
}
727
746
747
+ BlockfileType BlockManager::BlockfileTypeForHeight (int height)
748
+ {
749
+ if (!m_snapshot_height) {
750
+ return BlockfileType::NORMAL;
751
+ }
752
+ return (height >= *m_snapshot_height) ? BlockfileType::ASSUMED : BlockfileType::NORMAL;
753
+ }
754
+
755
+ bool BlockManager::FlushChainstateBlockFile (int tip_height)
756
+ {
757
+ LOCK (cs_LastBlockFile);
758
+ auto & cursor = m_blockfile_cursors[BlockfileTypeForHeight (tip_height)];
759
+ if (cursor) {
760
+ // The cursor may not exist after a snapshot has been loaded but before any
761
+ // blocks have been downloaded.
762
+ return FlushBlockFile (cursor->file_num , /* fFinalize=*/ false , /* finalize_undo=*/ false );
763
+ }
764
+ return false ;
765
+ }
766
+
728
767
uint64_t BlockManager::CalculateCurrentUsage ()
729
768
{
730
769
LOCK (cs_LastBlockFile);
@@ -779,8 +818,19 @@ bool BlockManager::FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigne
779
818
{
780
819
LOCK (cs_LastBlockFile);
781
820
782
- unsigned int nFile = fKnown ? pos.nFile : m_last_blockfile;
783
- if (m_blockfile_info.size () <= nFile) {
821
+ const BlockfileType chain_type = BlockfileTypeForHeight (nHeight);
822
+
823
+ if (!m_blockfile_cursors[chain_type]) {
824
+ // If a snapshot is loaded during runtime, we may not have initialized this cursor yet.
825
+ assert (chain_type == BlockfileType::ASSUMED);
826
+ const auto new_cursor = BlockfileCursor{this ->MaxBlockfileNum () + 1 };
827
+ m_blockfile_cursors[chain_type] = new_cursor;
828
+ LogPrint (BCLog::BLOCKSTORAGE, " [%s] initializing blockfile cursor to %s\n " , chain_type, new_cursor);
829
+ }
830
+ const int last_blockfile = m_blockfile_cursors[chain_type]->file_num ;
831
+
832
+ int nFile = fKnown ? pos.nFile : last_blockfile;
833
+ if (static_cast <int >(m_blockfile_info.size ()) <= nFile) {
784
834
m_blockfile_info.resize (nFile + 1 );
785
835
}
786
836
@@ -797,23 +847,31 @@ bool BlockManager::FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigne
797
847
}
798
848
}
799
849
assert (nAddSize < max_blockfile_size);
850
+
800
851
while (m_blockfile_info[nFile].nSize + nAddSize >= max_blockfile_size) {
801
852
// when the undo file is keeping up with the block file, we want to flush it explicitly
802
853
// when it is lagging behind (more blocks arrive than are being connected), we let the
803
854
// undo block write case handle it
804
- finalize_undo = (m_blockfile_info[nFile].nHeightLast == m_undo_height_in_last_blockfile);
805
- nFile++;
806
- if (m_blockfile_info.size () <= nFile) {
855
+ finalize_undo = (static_cast <int >(m_blockfile_info[nFile].nHeightLast ) ==
856
+ Assert (m_blockfile_cursors[chain_type])->undo_height );
857
+
858
+ // Try the next unclaimed blockfile number
859
+ nFile = this ->MaxBlockfileNum () + 1 ;
860
+ // Set to increment MaxBlockfileNum() for next iteration
861
+ m_blockfile_cursors[chain_type] = BlockfileCursor{nFile};
862
+
863
+ if (static_cast <int >(m_blockfile_info.size ()) <= nFile) {
807
864
m_blockfile_info.resize (nFile + 1 );
808
865
}
809
866
}
810
867
pos.nFile = nFile;
811
868
pos.nPos = m_blockfile_info[nFile].nSize ;
812
869
}
813
870
814
- if (( int ) nFile != m_last_blockfile ) {
871
+ if (nFile != last_blockfile ) {
815
872
if (!fKnown ) {
816
- LogPrint (BCLog::BLOCKSTORAGE, " Leaving block file %i: %s\n " , m_last_blockfile, m_blockfile_info[m_last_blockfile].ToString ());
873
+ LogPrint (BCLog::BLOCKSTORAGE, " Leaving block file %i: %s (onto %i) (height %i)\n " ,
874
+ last_blockfile, m_blockfile_info[last_blockfile].ToString (), nFile, nHeight);
817
875
}
818
876
819
877
// Do not propagate the return code. The flush concerns a previous block
@@ -823,13 +881,13 @@ bool BlockManager::FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigne
823
881
// data may be inconsistent after a crash if the flush is called during
824
882
// a reindex. A flush error might also leave some of the data files
825
883
// untrimmed.
826
- if (!FlushBlockFile (!fKnown , finalize_undo)) {
884
+ if (!FlushBlockFile (last_blockfile, !fKnown , finalize_undo)) {
827
885
LogPrintLevel (BCLog::BLOCKSTORAGE, BCLog::Level::Warning,
828
886
" Failed to flush previous block file %05i (finalize=%i, finalize_undo=%i) before opening new block file %05i\n " ,
829
- m_last_blockfile , !fKnown , finalize_undo, nFile);
887
+ last_blockfile , !fKnown , finalize_undo, nFile);
830
888
}
831
- m_last_blockfile = nFile;
832
- m_undo_height_in_last_blockfile = 0 ; // No undo data yet in the new file, so reset our undo-height tracking.
889
+ // No undo data yet in the new file, so reset our undo-height tracking.
890
+ m_blockfile_cursors[chain_type] = BlockfileCursor{nFile};
833
891
}
834
892
835
893
m_blockfile_info[nFile].AddBlock (nHeight, nTime);
@@ -903,6 +961,9 @@ bool BlockManager::WriteBlockToDisk(const CBlock& block, FlatFilePos& pos) const
903
961
bool BlockManager::WriteUndoDataForBlock (const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex& block)
904
962
{
905
963
AssertLockHeld (::cs_main);
964
+ const BlockfileType type = BlockfileTypeForHeight (block.nHeight );
965
+ auto & cursor = *Assert (WITH_LOCK (cs_LastBlockFile, return m_blockfile_cursors[type]));
966
+
906
967
// Write undo information to disk
907
968
if (block.GetUndoPos ().IsNull ()) {
908
969
FlatFilePos _pos;
@@ -917,7 +978,7 @@ bool BlockManager::WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValid
917
978
// in the block file info as below; note that this does not catch the case where the undo writes are keeping up
918
979
// with the block writes (usually when a synced up node is getting newly mined blocks) -- this case is caught in
919
980
// the FindBlockPos function
920
- if (_pos.nFile < m_last_blockfile && static_cast <uint32_t >(block.nHeight ) == m_blockfile_info[_pos.nFile ].nHeightLast ) {
981
+ if (_pos.nFile < cursor. file_num && static_cast <uint32_t >(block.nHeight ) == m_blockfile_info[_pos.nFile ].nHeightLast ) {
921
982
// Do not propagate the return code, a failed flush here should not
922
983
// be an indication for a failed write. If it were propagated here,
923
984
// the caller would assume the undo data not to be written, when in
@@ -926,8 +987,8 @@ bool BlockManager::WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValid
926
987
if (!FlushUndoFile (_pos.nFile , true )) {
927
988
LogPrintLevel (BCLog::BLOCKSTORAGE, BCLog::Level::Warning, " Failed to flush undo file %05i\n " , _pos.nFile );
928
989
}
929
- } else if (_pos.nFile == m_last_blockfile && static_cast < uint32_t >( block.nHeight ) > m_undo_height_in_last_blockfile ) {
930
- m_undo_height_in_last_blockfile = block.nHeight ;
990
+ } else if (_pos.nFile == cursor. file_num && block.nHeight > cursor. undo_height ) {
991
+ cursor. undo_height = block.nHeight ;
931
992
}
932
993
// update nUndoPos in block index
933
994
block.nUndoPos = _pos.nPos ;
@@ -1126,4 +1187,18 @@ void ImportBlocks(ChainstateManager& chainman, std::vector<fs::path> vImportFile
1126
1187
}
1127
1188
} // End scope of ImportingNow
1128
1189
}
1190
+
1191
+ std::ostream& operator <<(std::ostream& os, const BlockfileType& type) {
1192
+ switch (type) {
1193
+ case BlockfileType::NORMAL: os << " normal" ; break ;
1194
+ case BlockfileType::ASSUMED: os << " assumed" ; break ;
1195
+ default : os.setstate (std::ios_base::failbit);
1196
+ }
1197
+ return os;
1198
+ }
1199
+
1200
+ std::ostream& operator <<(std::ostream& os, const BlockfileCursor& cursor) {
1201
+ os << strprintf (" BlockfileCursor(file_num=%d, undo_height=%d)" , cursor.file_num , cursor.undo_height );
1202
+ return os;
1203
+ }
1129
1204
} // namespace node
0 commit comments