flush more, disk sync less

This commit is contained in:
Brannon King 2020-02-12 11:40:14 -07:00
parent 873c597ba6
commit 4c342fae29
4 changed files with 25 additions and 31 deletions

View file

@ -241,7 +241,7 @@ void Shutdown()
// FlushStateToDisk generates a ChainStateFlushed callback, which we should avoid missing
if (pcoinsTip != nullptr) {
FlushStateToDisk();
FlushStateToDisk(true);
}
// After there are no more peers/RPC left to give us new data which may generate
@ -257,7 +257,7 @@ void Shutdown()
{
LOCK(cs_main);
if (pcoinsTip != nullptr) {
FlushStateToDisk();
FlushStateToDisk(true);
}
pcoinsTip.reset();
pcoinscatcher.reset();

View file

@ -115,7 +115,7 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, boo
auto dbd = db << "DELETE FROM unspent WHERE txID = ? AND txN = ?";
auto dbi = db << "INSERT OR REPLACE INTO unspent VALUES(?,?,?,?,?,?,?)";
for (auto it = mapCoins.begin(); it != mapCoins.end();) {
for (auto it = mapCoins.begin(); it != mapCoins.end(); it = mapCoins.erase(it)) {
if (it->second.flags & CCoinsCacheEntry::DIRTY) {
if (it->second.coin.IsSpent()) {
// at present the "IsSpent" flag is used for both "spent" and "block going backwards"
@ -135,10 +135,7 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, boo
}
changed++;
}
count++;
auto itOld = it++;
mapCoins.erase(itOld);
if (crash_simulate && count % 200000 == 0) {
if (crash_simulate && ++count % 200000 == 0) {
static FastRandomContext rng;
if (rng.randrange(crash_simulate) == 0) {
LogPrintf("Simulating a crash. Goodbye.\n");
@ -153,14 +150,14 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, boo
auto code = sqlite::commit(db);
if (code != SQLITE_OK) {
LogPrint(BCLog::COINDB, "Error committing transaction outputs changes to coin database. SQLite error: %d\n", code);
LogPrintf("%s: Error committing coins info to database. SQLite error: %d\n", __func__, code);
return false;
}
LogPrint(BCLog::COINDB, "Committed %u changed transaction outputs (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
LogPrint(BCLog::COINDB, "Committed %zu changed transaction outputs (out of %zu) to coin database...\n", changed, count);
if (sync) {
auto code = sqlite::sync(db);
code = sqlite::sync(db);
if (code != SQLITE_OK) {
LogPrint(BCLog::COINDB, "Error syncing coin database. SQLite error: %d\n", code);
LogPrintf("%s: Error syncing coin database. SQLite error: %d\n", __func__, code);
return false;
}
}
@ -340,7 +337,7 @@ bool CBlockTreeDB::BatchWrite(const std::vector<std::pair<int, const CBlockFileI
}
// by Sync they mean disk sync:
if (sync) {
auto code = sqlite::sync(db);
code = sqlite::sync(db);
if (code != SQLITE_OK) {
LogPrintf("%s: Error syncing block database. SQLite error: %d\n", __func__, code);
return false;

View file

@ -156,7 +156,7 @@ enum class FlushStateMode {
};
// See definition for documentation
static bool FlushStateToDisk(const CChainParams& chainParams, CValidationState &state, FlushStateMode mode, int nManualPruneHeight=0);
static bool FlushStateToDisk(const CChainParams& chainParams, CValidationState &state, FlushStateMode mode, int nManualPruneHeight=0, bool syncToDisk=false);
static void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight);
static void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight);
bool CheckInputs(const CTransaction& tx, CValidationState &state, const CCoinsViewCache &inputs, bool fScriptChecks, unsigned int flags, bool cacheSigStore, bool cacheFullScriptStore, PrecomputedTransactionData& txdata, std::vector<CScriptCheck> *pvChecks = nullptr);
@ -2117,7 +2117,8 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl
* If FlushStateMode::NONE is used, then FlushStateToDisk(...) won't do anything
* besides checking if we need to prune.
*/
bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &state, FlushStateMode mode, int nManualPruneHeight) {
bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &state,
FlushStateMode mode, int nManualPruneHeight, bool syncToDisk) {
int64_t nMempoolUsage = mempool.DynamicMemoryUsage();
LOCK(cs_main);
static int64_t nLastWrite = 0;
@ -2186,7 +2187,7 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
vBlocks.push_back(*it);
setDirtyBlockIndex.erase(it++);
}
if (!pblocktree->BatchWrite(vFiles, nLastBlockFile, vBlocks, mode == FlushStateMode::ALWAYS)) {
if (!pblocktree->BatchWrite(vFiles, nLastBlockFile, vBlocks, syncToDisk)) {
return AbortNode(state, "Failed to write to block index database");
}
}
@ -2204,10 +2205,10 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
// overwrite one. Still, use a conservative safety factor of 2.
if (!CheckDiskSpace(48 * 2 * 2 * pcoinsTip->GetCacheSize()))
return state.Error("out of disk space");
if (mode == FlushStateMode::ALWAYS && !pclaimTrie->SyncToDisk())
if (syncToDisk && !pclaimTrie->SyncToDisk())
return state.Error("Failed to write to claim trie database");
// Flush the chainstate (which may refer to block index entries).
if (!pcoinsTip->Flush(mode == FlushStateMode::ALWAYS))
if (!pcoinsTip->Flush(syncToDisk))
return AbortNode(state, "Failed to write to coin database");
nLastFlush = nNow;
full_flush_completed = true;
@ -2224,10 +2225,10 @@ bool static FlushStateToDisk(const CChainParams& chainparams, CValidationState &
return true;
}
void FlushStateToDisk() {
void FlushStateToDisk(bool diskSync) {
CValidationState state;
const CChainParams& chainparams = Params();
if (!FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS)) {
if (!FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS, 0, diskSync)) {
LogPrintf("%s: failed to flush state (%s)\n", __func__, FormatStateMessage(state));
}
}
@ -2355,7 +2356,7 @@ bool CChainState::DisconnectTip(CValidationState& state, const CChainParams& cha
}
LogPrint(BCLog::BENCH, "- Disconnect block: %.2fms\n", (GetTimeMicros() - nStart) * MILLI);
// Write the chain state to disk, if necessary.
if (!FlushStateToDisk(chainparams, state, FlushStateMode::IF_NEEDED))
if (!IsInitialBlockDownload() && !FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS))
return false;
if (disconnectpool) {
@ -2502,7 +2503,7 @@ bool CChainState::ConnectTip(CValidationState& state, const CChainParams& chainp
int64_t nTime4 = GetTimeMicros(); nTimeFlush += nTime4 - nTime3;
LogPrint(BCLog::BENCH, " - Flush: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime4 - nTime3) * MILLI, nTimeFlush * MICRO, nTimeFlush * MILLI / nBlocksTotal);
// Write the chain state to disk, if necessary.
if (!FlushStateToDisk(chainparams, state, FlushStateMode::IF_NEEDED))
if (!IsInitialBlockDownload() && !FlushStateToDisk(chainparams, state, FlushStateMode::ALWAYS))
return false;
int64_t nTime5 = GetTimeMicros(); nTimeChainState += nTime5 - nTime4;
LogPrint(BCLog::BENCH, " - Writing chainstate: %.2fms [%.2fs (%.2fms/blk)]\n", (nTime5 - nTime4) * MILLI, nTimeChainState * MICRO, nTimeChainState * MILLI / nBlocksTotal);
@ -2775,11 +2776,11 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
if (!blocks_connected) return true;
const CBlockIndex* pindexFork = chainActive.FindFork(starting_tip);
bool fInitialDownload = IsInitialBlockDownload();
// Notify external listeners about the new tip.
// Enqueue while holding cs_main to ensure that UpdatedBlockTip is called in the order in which blocks are connected
if (pindexFork != pindexNewTip) {
bool fInitialDownload = IsInitialBlockDownload();
// Notify ValidationInterface subscribers
GetMainSignals().UpdatedBlockTip(pindexNewTip, pindexFork, fInitialDownload);
@ -2802,14 +2803,10 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
auto& consensus = chainparams.GetConsensus();
CheckBlockIndex(consensus);
auto flushMode = FlushStateMode::PERIODIC;
if (pindexNewTip && chainparams.NetworkIDString() != CBaseChainParams::REGTEST
&& pindexNewTip->nTime + consensus.nPowTargetSpacing > GetAdjustedTime()) {
// trying to ensure that we flush to disk after new blocks when we're caught up to the chain
// they're technically allowed to be two hours late, but experience says one minute is more likely
flushMode = FlushStateMode::ALWAYS;
}
return FlushStateToDisk(chainparams, state, flushMode);
auto flushMode = IsInitialBlockDownload() ? FlushStateMode::IF_NEEDED : FlushStateMode::ALWAYS;
auto diskSync = chainparams.NetworkIDString() != CBaseChainParams::REGTEST
&& flushMode == FlushStateMode::ALWAYS;
return FlushStateToDisk(chainparams, state, flushMode, 0, diskSync);
}
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock) {

View file

@ -291,7 +291,7 @@ void PruneOneBlockFile(const int fileNumber);
void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune);
/** Flush all state, indexes and buffers to disk. */
void FlushStateToDisk();
void FlushStateToDisk(bool diskSync = false);
/** Prune block files and flush state to disk. */
void PruneAndFlush();
/** Prune block files up to a given height */