Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 169 Lines • ▼ Show 20 Lines | for (const BlockHash &hash : locator.vHave) { | ||||
} | } | ||||
} | } | ||||
} | } | ||||
return chain.Genesis(); | return chain.Genesis(); | ||||
} | } | ||||
std::unique_ptr<CBlockTreeDB> pblocktree; | std::unique_ptr<CBlockTreeDB> pblocktree; | ||||
// See definition for documentation | |||||
static void FindFilesToPruneManual(ChainstateManager &chainman, | |||||
std::set<int> &setFilesToPrune, | |||||
int nManualPruneHeight); | |||||
static void FindFilesToPrune(ChainstateManager &chainman, | |||||
std::set<int> &setFilesToPrune, | |||||
uint64_t nPruneAfterHeight); | |||||
static uint32_t GetNextBlockScriptFlags(const Consensus::Params ¶ms, | static uint32_t GetNextBlockScriptFlags(const Consensus::Params ¶ms, | ||||
const CBlockIndex *pindex); | const CBlockIndex *pindex); | ||||
bool TestLockPointValidity(const LockPoints *lp) { | bool TestLockPointValidity(const LockPoints *lp) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
assert(lp); | assert(lp); | ||||
// If there are relative lock times then the maxInputBlock will be set | // If there are relative lock times then the maxInputBlock will be set | ||||
// If there are no relative lock times, the LockPoints don't depend on the | // If there are no relative lock times, the LockPoints don't depend on the | ||||
▲ Show 20 Lines • Show All 1,930 Lines • ▼ Show 20 Lines | try { | ||||
{ | { | ||||
bool fFlushForPrune = false; | bool fFlushForPrune = false; | ||||
bool fDoFullFlush = false; | bool fDoFullFlush = false; | ||||
CoinsCacheSizeState cache_state = | CoinsCacheSizeState cache_state = | ||||
GetCoinsCacheSizeState(&m_mempool); | GetCoinsCacheSizeState(&m_mempool); | ||||
LOCK(cs_LastBlockFile); | LOCK(cs_LastBlockFile); | ||||
if (fPruneMode && (fCheckForPruning || nManualPruneHeight > 0) && | if (fPruneMode && (fCheckForPruning || nManualPruneHeight > 0) && | ||||
!fReindex) { | !fReindex) { | ||||
// Previously, we called the global function ::ChainActive() in | |||||
// FindFilesToPrune{,Manual} to get the tip height and to | |||||
// determine whether or not a tip even exists. Now, we are | |||||
// simply passing in m_chain.Height() (which returns -1 if the | |||||
// tip doesn't exist). To make sure we're not changing | |||||
// behaviour, let's check that | |||||
// ::ChainActive() is the same object as m_chain (not just | |||||
// identical). | |||||
// | |||||
// This comment and the following assert will be removed in a | |||||
// subsequent commit, as they're just meant to demonstrate | |||||
// correctness (you can run tests against it and see that | |||||
// nothing exit unexpectedly). | |||||
assert(std::addressof(::ChainActive()) == | |||||
std::addressof(m_chain)); | |||||
if (nManualPruneHeight > 0) { | if (nManualPruneHeight > 0) { | ||||
LOG_TIME_MILLIS_WITH_CATEGORY( | LOG_TIME_MILLIS_WITH_CATEGORY( | ||||
"find files to prune (manual)", BCLog::BENCH); | "find files to prune (manual)", BCLog::BENCH); | ||||
FindFilesToPruneManual(g_chainman, setFilesToPrune, | m_blockman.FindFilesToPruneManual( | ||||
nManualPruneHeight); | setFilesToPrune, nManualPruneHeight, m_chain.Height()); | ||||
} else { | } else { | ||||
LOG_TIME_MILLIS_WITH_CATEGORY("find files to prune", | LOG_TIME_MILLIS_WITH_CATEGORY("find files to prune", | ||||
BCLog::BENCH); | BCLog::BENCH); | ||||
FindFilesToPrune(g_chainman, setFilesToPrune, | // Previously, we called the global function | ||||
chainparams.PruneAfterHeight()); | // ::ChainstateActive() in FindFilesToPrune{,Manual} to get | ||||
// the IBD status. Now, we are simply passing in | |||||
// IsInitialBlockDownload(). To make sure we're not changing | |||||
// behaviour, let's check that ::ChainstateActive() is the | |||||
// same object as *this (not just identical). | |||||
// | |||||
// This comment and the following assert will be removed in | |||||
// a subsequent commit, as they're just meant to demonstrate | |||||
// correctness (you can run tests against it and see that | |||||
// nothing exit unexpectedly). | |||||
assert(std::addressof(::ChainstateActive()) == | |||||
std::addressof(*this)); | |||||
// Previously, we called PruneOneBlockFile on g_chainman's | |||||
// m_blockman in FindFilesToPrune{,Manual}. Now, we are | |||||
// instead calling PruneOneBlockFile on _our_ m_blockman. To | |||||
// make sure we're not changing behaviour, let's check that | |||||
// g_chainman.m_blockman is the same object as _our_ | |||||
// m_blockman (not just identical). | |||||
// | |||||
// This comment and the following assert will be removed in | |||||
// a subsequent commit, as they're just meant to demonstrate | |||||
// correctness (you can run tests against it and see that | |||||
// nothing exit unexpectedly). | |||||
assert(std::addressof(g_chainman.m_blockman) == | |||||
std::addressof(m_blockman)); | |||||
m_blockman.FindFilesToPrune( | |||||
setFilesToPrune, chainparams.PruneAfterHeight(), | |||||
m_chain.Height(), IsInitialBlockDownload()); | |||||
fCheckForPruning = false; | fCheckForPruning = false; | ||||
} | } | ||||
if (!setFilesToPrune.empty()) { | if (!setFilesToPrune.empty()) { | ||||
fFlushForPrune = true; | fFlushForPrune = true; | ||||
if (!fHavePruned) { | if (!fHavePruned) { | ||||
pblocktree->WriteFlag("prunedblockfiles", true); | pblocktree->WriteFlag("prunedblockfiles", true); | ||||
fHavePruned = true; | fHavePruned = true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 2,398 Lines • ▼ Show 20 Lines | for (const int i : setFilesToPrune) { | ||||
LogPrintf("Prune: %s deleted blk/rev (%05u)\n", __func__, i); | LogPrintf("Prune: %s deleted blk/rev (%05u)\n", __func__, i); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Calculate the block/rev files to delete based on height specified by user | * Calculate the block/rev files to delete based on height specified by user | ||||
* with RPC command pruneblockchain | * with RPC command pruneblockchain | ||||
*/ | */ | ||||
static void FindFilesToPruneManual(ChainstateManager &chainman, | void BlockManager::FindFilesToPruneManual(std::set<int> &setFilesToPrune, | ||||
std::set<int> &setFilesToPrune, | int nManualPruneHeight, | ||||
int nManualPruneHeight) { | int chain_tip_height) { | ||||
assert(fPruneMode && nManualPruneHeight > 0); | assert(fPruneMode && nManualPruneHeight > 0); | ||||
LOCK2(cs_main, cs_LastBlockFile); | LOCK2(cs_main, cs_LastBlockFile); | ||||
if (::ChainActive().Tip() == nullptr) { | if (chain_tip_height < 0) { | ||||
return; | return; | ||||
} | } | ||||
// last block to prune is the lesser of (user-specified height, | // last block to prune is the lesser of (user-specified height, | ||||
// MIN_BLOCKS_TO_KEEP from the tip) | // MIN_BLOCKS_TO_KEEP from the tip) | ||||
unsigned int nLastBlockWeCanPrune = | unsigned int nLastBlockWeCanPrune = std::min( | ||||
std::min((unsigned)nManualPruneHeight, | (unsigned)nManualPruneHeight, chain_tip_height - MIN_BLOCKS_TO_KEEP); | ||||
::ChainActive().Tip()->nHeight - MIN_BLOCKS_TO_KEEP); | |||||
int count = 0; | int count = 0; | ||||
for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) { | for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) { | ||||
if (vinfoBlockFile[fileNumber].nSize == 0 || | if (vinfoBlockFile[fileNumber].nSize == 0 || | ||||
vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune) { | vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune) { | ||||
continue; | continue; | ||||
} | } | ||||
chainman.m_blockman.PruneOneBlockFile(fileNumber); | PruneOneBlockFile(fileNumber); | ||||
setFilesToPrune.insert(fileNumber); | setFilesToPrune.insert(fileNumber); | ||||
count++; | count++; | ||||
} | } | ||||
LogPrintf("Prune (Manual): prune_height=%d removed %d blk/rev pairs\n", | LogPrintf("Prune (Manual): prune_height=%d removed %d blk/rev pairs\n", | ||||
nLastBlockWeCanPrune, count); | nLastBlockWeCanPrune, count); | ||||
} | } | ||||
/* This function is called from the RPC code for pruneblockchain */ | /* This function is called from the RPC code for pruneblockchain */ | ||||
Show All 23 Lines | |||||
* within a defined distance (currently 288) from the active chain's tip. The | * within a defined distance (currently 288) from the active chain's tip. The | ||||
* block index is updated by unsetting HAVE_DATA and HAVE_UNDO for any blocks | * block index is updated by unsetting HAVE_DATA and HAVE_UNDO for any blocks | ||||
* that were stored in the deleted files. A db flag records the fact that at | * that were stored in the deleted files. A db flag records the fact that at | ||||
* least some block files have been pruned. | * least some block files have been pruned. | ||||
* | * | ||||
* @param[out] setFilesToPrune The set of file indices that can be unlinked | * @param[out] setFilesToPrune The set of file indices that can be unlinked | ||||
* will be returned | * will be returned | ||||
*/ | */ | ||||
static void FindFilesToPrune(ChainstateManager &chainman, | void BlockManager::FindFilesToPrune(std::set<int> &setFilesToPrune, | ||||
std::set<int> &setFilesToPrune, | uint64_t nPruneAfterHeight, | ||||
uint64_t nPruneAfterHeight) { | int chain_tip_height, bool is_ibd) { | ||||
LOCK2(cs_main, cs_LastBlockFile); | LOCK2(cs_main, cs_LastBlockFile); | ||||
if (::ChainActive().Tip() == nullptr || nPruneTarget == 0) { | if (chain_tip_height < 0 || nPruneTarget == 0) { | ||||
return; | return; | ||||
} | } | ||||
if (uint64_t(::ChainActive().Tip()->nHeight) <= nPruneAfterHeight) { | if (uint64_t(chain_tip_height) <= nPruneAfterHeight) { | ||||
return; | return; | ||||
} | } | ||||
unsigned int nLastBlockWeCanPrune = | unsigned int nLastBlockWeCanPrune = chain_tip_height - MIN_BLOCKS_TO_KEEP; | ||||
::ChainActive().Tip()->nHeight - MIN_BLOCKS_TO_KEEP; | |||||
uint64_t nCurrentUsage = CalculateCurrentUsage(); | uint64_t nCurrentUsage = CalculateCurrentUsage(); | ||||
// We don't check to prune until after we've allocated new space for files, | // We don't check to prune until after we've allocated new space for files, | ||||
// so we should leave a buffer under our target to account for another | // so we should leave a buffer under our target to account for another | ||||
// allocation before the next pruning. | // allocation before the next pruning. | ||||
uint64_t nBuffer = BLOCKFILE_CHUNK_SIZE + UNDOFILE_CHUNK_SIZE; | uint64_t nBuffer = BLOCKFILE_CHUNK_SIZE + UNDOFILE_CHUNK_SIZE; | ||||
uint64_t nBytesToPrune; | uint64_t nBytesToPrune; | ||||
int count = 0; | int count = 0; | ||||
if (nCurrentUsage + nBuffer >= nPruneTarget) { | if (nCurrentUsage + nBuffer >= nPruneTarget) { | ||||
// On a prune event, the chainstate DB is flushed. | // On a prune event, the chainstate DB is flushed. | ||||
// To avoid excessive prune events negating the benefit of high dbcache | // To avoid excessive prune events negating the benefit of high dbcache | ||||
// values, we should not prune too rapidly. | // values, we should not prune too rapidly. | ||||
// So when pruning in IBD, increase the buffer a bit to avoid a re-prune | // So when pruning in IBD, increase the buffer a bit to avoid a re-prune | ||||
// too soon. | // too soon. | ||||
if (::ChainstateActive().IsInitialBlockDownload()) { | if (is_ibd) { | ||||
// Since this is only relevant during IBD, we use a fixed 10% | // Since this is only relevant during IBD, we use a fixed 10% | ||||
nBuffer += nPruneTarget / 10; | nBuffer += nPruneTarget / 10; | ||||
} | } | ||||
for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) { | for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) { | ||||
nBytesToPrune = vinfoBlockFile[fileNumber].nSize + | nBytesToPrune = vinfoBlockFile[fileNumber].nSize + | ||||
vinfoBlockFile[fileNumber].nUndoSize; | vinfoBlockFile[fileNumber].nUndoSize; | ||||
if (vinfoBlockFile[fileNumber].nSize == 0) { | if (vinfoBlockFile[fileNumber].nSize == 0) { | ||||
continue; | continue; | ||||
} | } | ||||
// are we below our target? | // are we below our target? | ||||
if (nCurrentUsage + nBuffer < nPruneTarget) { | if (nCurrentUsage + nBuffer < nPruneTarget) { | ||||
break; | break; | ||||
} | } | ||||
// don't prune files that could have a block within | // don't prune files that could have a block within | ||||
// MIN_BLOCKS_TO_KEEP of the main chain's tip but keep scanning | // MIN_BLOCKS_TO_KEEP of the main chain's tip but keep scanning | ||||
if (vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune) { | if (vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune) { | ||||
continue; | continue; | ||||
} | } | ||||
chainman.m_blockman.PruneOneBlockFile(fileNumber); | PruneOneBlockFile(fileNumber); | ||||
// Queue up the files for removal | // Queue up the files for removal | ||||
setFilesToPrune.insert(fileNumber); | setFilesToPrune.insert(fileNumber); | ||||
nCurrentUsage -= nBytesToPrune; | nCurrentUsage -= nBytesToPrune; | ||||
count++; | count++; | ||||
} | } | ||||
} | } | ||||
LogPrint(BCLog::PRUNE, | LogPrint(BCLog::PRUNE, | ||||
▲ Show 20 Lines • Show All 1,477 Lines • Show Last 20 Lines |