src/validation.cpp
/**
 * Update the on-disk chain state.
 * The caches and indexes are flushed depending on the mode we're called with
 * if they're too large, if it's been a while since the last write,
 * or always and in all cases if we're in prune mode and are deleting files.
 */
Update the on-disk chain state.
The caches and indexes are flushed depending on the mode we're called with
if they're too large, if it's been a while since the last write,
or always and in all cases if we're in prune mode and are deleting files.
Update the on - disk chain state . The caches and indexes are flushed depending on the mode we ' re called with if they ' re too large if it ' s been a while since the last write or always and in all cases if we ' re in prune mode and are deleting files .
bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode, int nManualPruneHeight) {
    int64_t nMempoolUsage = mempool.DynamicMemoryUsage();
    const CChainParams& chainparams = Params();
    LOCK2(cs_main, cs_LastBlockFile);
    static int64_t nLastWrite = 0;
    static int64_t nLastFlush = 0;
    static int64_t nLastSetChain = 0;
    std::set<int> setFilesToPrune;
    bool fFlushForPrune = false;
    try {
    if (fPruneMode && (fCheckForPruning || nManualPruneHeight > 0) && !fReindex) {
        if (nManualPruneHeight > 0) {
            FindFilesToPruneManual(setFilesToPrune, nManualPruneHeight);
        } else {
            FindFilesToPrune(setFilesToPrune, chainparams.PruneAfterHeight());
            fCheckForPruning = false;
        }
        if (!setFilesToPrune.empty()) {
            fFlushForPrune = true;
            if (!fHavePruned) {
                pblocktree->WriteFlag("prunedblockfiles", true);
                fHavePruned = true;
            }
        }
    }
    int64_t nNow = GetTimeMicros();
    if (nLastWrite == 0) {
        nLastWrite = nNow;
    }
    if (nLastFlush == 0) {
        nLastFlush = nNow;
    }
    if (nLastSetChain == 0) {
        nLastSetChain = nNow;
    }
    size_t nMempoolSizeMax = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
    size_t cacheSize = pcoinsTip->DynamicMemoryUsage() * DB_PEAK_USAGE_FACTOR;
    size_t nTotalSpace = nCoinCacheUsage + std::max<int64_t>(nMempoolSizeMax - nMempoolUsage, 0);
    bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize > std::max((9 * nTotalSpace) / 10, nTotalSpace - MAX_BLOCK_COINSDB_USAGE * 1024 * 1024);
    bool fCacheCritical = mode == FLUSH_STATE_IF_NEEDED && cacheSize > nCoinCacheUsage;
    bool fPeriodicWrite = mode == FLUSH_STATE_PERIODIC && nNow > nLastWrite + (int64_t)DATABASE_WRITE_INTERVAL * 1000000;
    bool fPeriodicFlush = mode == FLUSH_STATE_PERIODIC && nNow > nLastFlush + (int64_t)DATABASE_FLUSH_INTERVAL * 1000000;
    bool fDoFullFlush = (mode == FLUSH_STATE_ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune;
    if (fDoFullFlush || fPeriodicWrite) {
        if (!CheckDiskSpace(0))
            return state.Error("out of disk space");
        FlushBlockFile();
        {
            std::vector<std::pair<int, const CBlockFileInfo*> > vFiles;
            vFiles.reserve(setDirtyFileInfo.size());
            for (std::set<int>::iterator it = setDirtyFileInfo.begin(); it != setDirtyFileInfo.end(); ) {
                vFiles.push_back(std::make_pair(*it, &vinfoBlockFile[*it]));
                setDirtyFileInfo.erase(it++);
            }
            std::vector<const CBlockIndex*> vBlocks;
            vBlocks.reserve(setDirtyBlockIndex.size());
            for (std::set<CBlockIndex*>::iterator it = setDirtyBlockIndex.begin(); it != setDirtyBlockIndex.end(); ) {
                vBlocks.push_back(*it);
                setDirtyBlockIndex.erase(it++);
            }
            if (!pblocktree->WriteBatchSync(vFiles, nLastBlockFile, vBlocks)) {
                return AbortNode(state, "Failed to write to block index database");
            }
        }
        if (fFlushForPrune)
            UnlinkPrunedFiles(setFilesToPrune);
        nLastWrite = nNow;
    }
    if (fDoFullFlush) {
        if (!CheckDiskSpace(48 * 2 * 2 * pcoinsTip->GetCacheSize()))
            return state.Error("out of disk space");
        if (!pcoinsTip->Flush())
            return AbortNode(state, "Failed to write to coin database");
		if (!FlushMartkistDBs())
			return AbortNode(state, "Failed to flush martkist databases");
        nLastFlush = nNow;
    }
    if (fDoFullFlush || ((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) && nNow > nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000)) {
        GetMainSignals().SetBestChain(chainActive.GetLocator());
        nLastSetChain = nNow;
    }
    } catch (const std::runtime_error& e) {
        return AbortNode(state, std::string("System error while flushing: ") + e.what());
    }
    return true;
}
bool static FlushStateToDisk ( CValidationState & state , FlushStateMode mode , int nManualPruneHeight ) { int64_t nMempoolUsage = mempool . DynamicMemoryUsage ( ) ; const CChainParams & chainparams = Params ( ) ; LOCK2 ( cs_main , cs_LastBlockFile ) ; static int64_t nLastWrite = 0 ; static int64_t nLastFlush = 0 ; static int64_t nLastSetChain = 0 ; std :: set < int > setFilesToPrune ; bool fFlushForPrune = false ; try { if ( fPruneMode && ( fCheckForPruning || nManualPruneHeight > 0 ) && ! fReindex ) { if ( nManualPruneHeight > 0 ) { FindFilesToPruneManual ( setFilesToPrune , nManualPruneHeight ) ; } else { FindFilesToPrune ( setFilesToPrune , chainparams . PruneAfterHeight ( ) ) ; fCheckForPruning = false ; } if ( ! setFilesToPrune . empty ( ) ) { fFlushForPrune = true ; if ( ! fHavePruned ) { pblocktree -> WriteFlag ( " " , true ) ; fHavePruned = true ; } } } int64_t nNow = GetTimeMicros ( ) ; if ( nLastWrite == 0 ) { nLastWrite = nNow ; } if ( nLastFlush == 0 ) { nLastFlush = nNow ; } if ( nLastSetChain == 0 ) { nLastSetChain = nNow ; } size_t nMempoolSizeMax = GetArg ( " " , DEFAULT_MAX_MEMPOOL_SIZE ) * 1000000 ; size_t cacheSize = pcoinsTip -> DynamicMemoryUsage ( ) * DB_PEAK_USAGE_FACTOR ; size_t nTotalSpace = nCoinCacheUsage + std :: max < int64_t > ( nMempoolSizeMax - nMempoolUsage , 0 ) ; bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize > std :: max ( ( 9 * nTotalSpace ) / 10 , nTotalSpace - MAX_BLOCK_COINSDB_USAGE * 1024 * 1024 ) ; bool fCacheCritical = mode == FLUSH_STATE_IF_NEEDED && cacheSize > nCoinCacheUsage ; bool fPeriodicWrite = mode == FLUSH_STATE_PERIODIC && nNow > nLastWrite + ( int64_t ) DATABASE_WRITE_INTERVAL * 1000000 ; bool fPeriodicFlush = mode == FLUSH_STATE_PERIODIC && nNow > nLastFlush + ( int64_t ) DATABASE_FLUSH_INTERVAL * 1000000 ; bool fDoFullFlush = ( mode == FLUSH_STATE_ALWAYS ) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune ; if ( fDoFullFlush || fPeriodicWrite ) { if ( ! CheckDiskSpace ( 0 ) ) return state . Error ( " " ) ; FlushBlockFile ( ) ; { std :: vector < std :: pair < int , const CBlockFileInfo * > > vFiles ; vFiles . reserve ( setDirtyFileInfo . size ( ) ) ; for ( std :: set < int > :: iterator it = setDirtyFileInfo . begin ( ) ; it != setDirtyFileInfo . end ( ) ; ) { vFiles . push_back ( std :: make_pair ( * it , & vinfoBlockFile [ * it ] ) ) ; setDirtyFileInfo . erase ( it ++ ) ; } std :: vector < const CBlockIndex * > vBlocks ; vBlocks . reserve ( setDirtyBlockIndex . size ( ) ) ; for ( std :: set < CBlockIndex * > :: iterator it = setDirtyBlockIndex . begin ( ) ; it != setDirtyBlockIndex . end ( ) ; ) { vBlocks . push_back ( * it ) ; setDirtyBlockIndex . erase ( it ++ ) ; } if ( ! pblocktree -> WriteBatchSync ( vFiles , nLastBlockFile , vBlocks ) ) { return AbortNode ( state , " " ) ; } } if ( fFlushForPrune ) UnlinkPrunedFiles ( setFilesToPrune ) ; nLastWrite = nNow ; } if ( fDoFullFlush ) { if ( ! CheckDiskSpace ( 48 * 2 * 2 * pcoinsTip -> GetCacheSize ( ) ) ) return state . Error ( " " ) ; if ( ! pcoinsTip -> Flush ( ) ) return AbortNode ( state , " " ) ; if ( ! FlushMartkistDBs ( ) ) return AbortNode ( state , " " ) ; nLastFlush = nNow ; } if ( fDoFullFlush || ( ( mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC ) && nNow > nLastSetChain + ( int64_t ) DATABASE_WRITE_INTERVAL * 1000000 ) ) { GetMainSignals ( ) . SetBestChain ( chainActive . GetLocator ( ) ) ; nLastSetChain = nNow ; } } catch ( const std :: runtime_error & e ) { return AbortNode ( state , std :: string ( " " ) + e . what ( ) ) ; } return true ; }
Update the on-disk chain state.
Update the on - disk chain state .
// Avoid writing/flushing immediately after startup. // The cache is large and we're within 10% and 10 MiB of the limit, but we have time now (not in the middle of a block processing). // The cache is over the limit, we have to write now. // It's been a while since we wrote the block index to disk. Do this frequently, so we don't need to redownload after a crash. // It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage. // Combine all conditions that result in a full cache flush. // Write blocks and block index to disk. // Depend on nMinDiskSpace to ensure we can write block index // First make sure all block and undo data is flushed to disk. // Then update all block file information (which may refer to block and undo files). // Finally remove any pruned files // Flush best chain related state. This can only be done if the blocks / block index write was also done. // Typical Coin structures on disk are around 48 bytes in size. // Pushing a new one to the database can cause it to be written // twice (once in the log, and once in the tables). This is already // an overestimation, as most will delete an existing entry or // overwrite one. Still, use a conservative safety factor of 2. // Flush the chainstate (which may refer to block index entries). // MARTKIST // Update best block in wallet (so we can detect restored wallets).