| 330 | } |
| 331 | |
| 332 | void BlockManager::FindFilesToPrune( |
| 333 | std::set<int>& setFilesToPrune, |
| 334 | int last_prune, |
| 335 | const Chainstate& chain, |
| 336 | ChainstateManager& chainman) |
| 337 | { |
| 338 | LOCK(::cs_main); |
| 339 | // Compute `target` value with maximum size (in bytes) of blocks below the |
| 340 | // `last_prune` height which should be preserved and not pruned. The |
| 341 | // `target` value will be derived from the -prune preference provided by the |
| 342 | // user. If there is a historical chainstate being used to populate indexes |
| 343 | // and validate the snapshot, the target is divided by two so half of the |
| 344 | // block storage will be reserved for the historical chainstate, and the |
| 345 | // other half will be reserved for the most-work chainstate. |
| 346 | const int num_chainstates{chainman.HistoricalChainstate() ? 2 : 1}; |
| 347 | const auto target = std::max( |
| 348 | MIN_DISK_SPACE_FOR_BLOCK_FILES, GetPruneTarget() / num_chainstates); |
| 349 | const uint64_t target_sync_height = chainman.m_best_header->nHeight; |
| 350 | |
| 351 | if (chain.m_chain.Height() < 0 || target == 0) { |
| 352 | return; |
| 353 | } |
| 354 | if (static_cast<uint64_t>(chain.m_chain.Height()) <= chainman.GetParams().PruneAfterHeight()) { |
| 355 | return; |
| 356 | } |
| 357 | |
| 358 | const auto [min_block_to_prune, last_block_can_prune] = chain.GetPruneRange(last_prune); |
| 359 | |
| 360 | uint64_t nCurrentUsage = CalculateCurrentUsage(); |
| 361 | // We don't check to prune until after we've allocated new space for files |
| 362 | // So we should leave a buffer under our target to account for another allocation |
| 363 | // before the next pruning. |
| 364 | uint64_t nBuffer = BLOCKFILE_CHUNK_SIZE + UNDOFILE_CHUNK_SIZE; |
| 365 | uint64_t nBytesToPrune; |
| 366 | int count = 0; |
| 367 | |
| 368 | if (nCurrentUsage + nBuffer >= target) { |
| 369 | // On a prune event, the chainstate DB is flushed. |
| 370 | // To avoid excessive prune events negating the benefit of high dbcache |
| 371 | // values, we should not prune too rapidly. |
| 372 | // So when pruning in IBD, increase the buffer to avoid a re-prune too soon. |
| 373 | const auto chain_tip_height = chain.m_chain.Height(); |
| 374 | if (chainman.IsInitialBlockDownload() && target_sync_height > (uint64_t)chain_tip_height) { |
| 375 | // Since this is only relevant during IBD, we assume blocks are at least 1 MB on average |
| 376 | static constexpr uint64_t average_block_size = 1000000; /* 1 MB */ |
| 377 | const uint64_t remaining_blocks = target_sync_height - chain_tip_height; |
| 378 | nBuffer += average_block_size * remaining_blocks; |
| 379 | } |
| 380 | |
| 381 | for (int fileNumber = 0; fileNumber < this->MaxBlockfileNum(); fileNumber++) { |
| 382 | const auto& fileinfo = m_blockfile_info[fileNumber]; |
| 383 | nBytesToPrune = fileinfo.nSize + fileinfo.nUndoSize; |
| 384 | |
| 385 | if (fileinfo.nSize == 0) { |
| 386 | continue; |
| 387 | } |
| 388 | |
| 389 | if (nCurrentUsage + nBuffer < target) { // are we below our target? |
no test coverage detected