Prune: Support noncontiguous block files
In some corner cases, it may be possible for recent blocks to end up in the same block file as much older blocks. Previously, the pruning code would stop looking for files to remove upon first encountering a file containing a block that cannot be pruned, now it will keep looking for candidate files until the target is met and all other criteria are satisfied. This can result in a noncontiguous set of block files (by number) on disk, which is fine except for during some reindex corner cases, so make reindex preparation smarter such that we keep the data we can actually use and throw away the rest. This allows pruning to work correctly while downloading any blocks needed during the reindex.
This commit is contained in:
parent
f00b62391b
commit
c257a8c9a6
53
src/init.cpp
53
src/init.cpp
|
@ -473,25 +473,44 @@ struct CImportingNow
|
|||
|
||||
// If we're using -prune with -reindex, then delete block files that will be ignored by the
|
||||
// reindex. Since reindexing works by starting at block file 0 and looping until a blockfile
|
||||
// is missing, and since pruning works by deleting the oldest block file first, just check
|
||||
// for block file 0, and if it doesn't exist, delete all the block files in the
|
||||
// directory (since they won't be read by the reindex but will take up disk space).
|
||||
void DeleteAllBlockFiles()
|
||||
// is missing, do the same here to delete any later block files after a gap. Also delete all
|
||||
// rev files since they'll be rewritten by the reindex anyway. This ensures that vinfoBlockFile
|
||||
// is in sync with what's actually on disk by the time we start downloading, so that pruning
|
||||
// works correctly.
|
||||
void CleanupBlockRevFiles()
|
||||
{
|
||||
if (boost::filesystem::exists(GetBlockPosFilename(CDiskBlockPos(0, 0), "blk")))
|
||||
return;
|
||||
using namespace boost::filesystem;
|
||||
map<string, path> mapBlockFiles;
|
||||
|
||||
LogPrintf("Removing all blk?????.dat and rev?????.dat files for -reindex with -prune\n");
|
||||
boost::filesystem::path blocksdir = GetDataDir() / "blocks";
|
||||
for (boost::filesystem::directory_iterator it(blocksdir); it != boost::filesystem::directory_iterator(); it++) {
|
||||
if (is_regular_file(*it)) {
|
||||
if ((it->path().filename().string().length() == 12) &&
|
||||
(it->path().filename().string().substr(8,4) == ".dat") &&
|
||||
((it->path().filename().string().substr(0,3) == "blk") ||
|
||||
(it->path().filename().string().substr(0,3) == "rev")))
|
||||
boost::filesystem::remove(it->path());
|
||||
// Glob all blk?????.dat and rev?????.dat files from the blocks directory.
|
||||
// Remove the rev files immediately and insert the blk file paths into an
|
||||
// ordered map keyed by block file index.
|
||||
LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\n");
|
||||
path blocksdir = GetDataDir() / "blocks";
|
||||
for (directory_iterator it(blocksdir); it != directory_iterator(); it++) {
|
||||
if (is_regular_file(*it) &&
|
||||
it->path().filename().string().length() == 12 &&
|
||||
it->path().filename().string().substr(8,4) == ".dat")
|
||||
{
|
||||
if (it->path().filename().string().substr(0,3) == "blk")
|
||||
mapBlockFiles[it->path().filename().string().substr(3,5)] = it->path();
|
||||
else if (it->path().filename().string().substr(0,3) == "rev")
|
||||
remove(it->path());
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all block files that aren't part of a contiguous set starting at
|
||||
// zero by walking the ordered map (keys are block file indices) by
|
||||
// keeping a separate counter. Once we hit a gap (or if 0 doesn't exist)
|
||||
// start removing block files.
|
||||
int nContigCounter = 0;
|
||||
BOOST_FOREACH(const PAIRTYPE(string, path)& item, mapBlockFiles) {
|
||||
if (atoi(item.first) == nContigCounter) {
|
||||
nContigCounter++;
|
||||
continue;
|
||||
}
|
||||
remove(item.second);
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadImport(std::vector<boost::filesystem::path> vImportFiles)
|
||||
|
@ -1110,9 +1129,9 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||
|
||||
if (fReindex) {
|
||||
pblocktree->WriteReindexing(true);
|
||||
//If we're reindexing in prune mode, wipe away all our block and undo data files
|
||||
//If we're reindexing in prune mode, wipe away unusable block files and all undo data files
|
||||
if (fPruneMode)
|
||||
DeleteAllBlockFiles();
|
||||
CleanupBlockRevFiles();
|
||||
}
|
||||
|
||||
if (!LoadBlockIndex()) {
|
||||
|
|
|
@ -3031,9 +3031,9 @@ void FindFilesToPrune(std::set<int>& setFilesToPrune)
|
|||
if (nCurrentUsage + nBuffer < nPruneTarget) // are we below our target?
|
||||
break;
|
||||
|
||||
// don't prune files that could have a block within MIN_BLOCKS_TO_KEEP of the main chain's tip
|
||||
// don't prune files that could have a block within MIN_BLOCKS_TO_KEEP of the main chain's tip but keep scanning
|
||||
if (vinfoBlockFile[fileNumber].nHeightLast > nLastBlockWeCanPrune)
|
||||
break;
|
||||
continue;
|
||||
|
||||
PruneOneBlockFile(fileNumber);
|
||||
// Queue up the files for removal
|
||||
|
|
Loading…
Reference in New Issue