@@ -57,7 +57,7 @@ bool fPruneMode = false;
57
57
bool fIsBareMultisigStd = true ;
58
58
bool fCheckBlockIndex = false ;
59
59
bool fCheckpointsEnabled = true ;
60
- unsigned int nCoinCacheSize = 5000 ;
60
+ size_t nCoinCacheUsage = 5000 * 300 ;
61
61
uint64_t nPruneTarget = 0 ;
62
62
63
63
/* * Fees smaller than this (in satoshi) are considered zero fee (for relaying and mining) */
@@ -1880,6 +1880,8 @@ enum FlushStateMode {
1880
1880
bool static FlushStateToDisk (CValidationState &state, FlushStateMode mode) {
1881
1881
LOCK2 (cs_main, cs_LastBlockFile);
1882
1882
static int64_t nLastWrite = 0 ;
1883
+ static int64_t nLastFlush = 0 ;
1884
+ static int64_t nLastSetChain = 0 ;
1883
1885
std::set<int > setFilesToPrune;
1884
1886
bool fFlushForPrune = false ;
1885
1887
try {
@@ -1893,16 +1895,32 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) {
1893
1895
}
1894
1896
}
1895
1897
}
1896
- if ((mode == FLUSH_STATE_ALWAYS) ||
1897
- ((mode == FLUSH_STATE_PERIODIC || mode == FLUSH_STATE_IF_NEEDED) && pcoinsTip->GetCacheSize () > nCoinCacheSize) ||
1898
- (mode == FLUSH_STATE_PERIODIC && GetTimeMicros () > nLastWrite + DATABASE_WRITE_INTERVAL * 1000000 ) ||
1899
- fFlushForPrune ) {
1900
- // Typical CCoins structures on disk are around 100 bytes in size.
1901
- // Pushing a new one to the database can cause it to be written
1902
- // twice (once in the log, and once in the tables). This is already
1903
- // an overestimation, as most will delete an existing entry or
1904
- // overwrite one. Still, use a conservative safety factor of 2.
1905
- if (!CheckDiskSpace (100 * 2 * 2 * pcoinsTip->GetCacheSize ()))
1898
+ int64_t nNow = GetTimeMicros ();
1899
+ // Avoid writing/flushing immediately after startup.
1900
+ if (nLastWrite == 0 ) {
1901
+ nLastWrite = nNow;
1902
+ }
1903
+ if (nLastFlush == 0 ) {
1904
+ nLastFlush = nNow;
1905
+ }
1906
+ if (nLastSetChain == 0 ) {
1907
+ nLastSetChain = nNow;
1908
+ }
1909
+ size_t cacheSize = pcoinsTip->DynamicMemoryUsage ();
1910
+ // The cache is large and close to the limit, but we have time now (not in the middle of a block processing).
1911
+ bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize * (10.0 /9 ) > nCoinCacheUsage;
1912
+ // The cache is over the limit, we have to write now.
1913
+ bool fCacheCritical = mode == FLUSH_STATE_IF_NEEDED && cacheSize > nCoinCacheUsage;
1914
+ // 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.
1915
+ bool fPeriodicWrite = mode == FLUSH_STATE_PERIODIC && nNow > nLastWrite + (int64_t )DATABASE_WRITE_INTERVAL * 1000000 ;
1916
+ // It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage.
1917
+ bool fPeriodicFlush = mode == FLUSH_STATE_PERIODIC && nNow > nLastFlush + (int64_t )DATABASE_FLUSH_INTERVAL * 1000000 ;
1918
+ // Combine all conditions that result in a full cache flush.
1919
+ bool fDoFullFlush = (mode == FLUSH_STATE_ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune ;
1920
+ // Write blocks and block index to disk.
1921
+ if (fDoFullFlush || fPeriodicWrite ) {
1922
+ // Depend on nMinDiskSpace to ensure we can write block index
1923
+ if (!CheckDiskSpace (0 ))
1906
1924
return state.Error (" out of disk space" );
1907
1925
// First make sure all block and undo data is flushed to disk.
1908
1926
FlushBlockFile ();
@@ -1924,21 +1942,31 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) {
1924
1942
return state.Abort (" Files to write to block index database" );
1925
1943
}
1926
1944
}
1927
- // Flush the chainstate (which may refer to block index entries).
1928
- if (!pcoinsTip->Flush ())
1929
- return state.Abort (" Failed to write to coin database" );
1930
-
1931
1945
// Finally remove any pruned files
1932
1946
if (fFlushForPrune ) {
1933
1947
UnlinkPrunedFiles (setFilesToPrune);
1934
1948
fCheckForPruning = false ;
1935
1949
}
1936
-
1950
+ nLastWrite = nNow;
1951
+ }
1952
+ // Flush best chain related state. This can only be done if the blocks / block index write was also done.
1953
+ if (fDoFullFlush ) {
1954
+ // Typical CCoins structures on disk are around 128 bytes in size.
1955
+ // Pushing a new one to the database can cause it to be written
1956
+ // twice (once in the log, and once in the tables). This is already
1957
+ // an overestimation, as most will delete an existing entry or
1958
+ // overwrite one. Still, use a conservative safety factor of 2.
1959
+ if (!CheckDiskSpace (128 * 2 * 2 * pcoinsTip->GetCacheSize ()))
1960
+ return state.Error (" out of disk space" );
1961
+ // Flush the chainstate (which may refer to block index entries).
1962
+ if (!pcoinsTip->Flush ())
1963
+ return state.Abort (" Failed to write to coin database" );
1964
+ nLastFlush = nNow;
1965
+ }
1966
+ if ((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) && nNow > nLastSetChain + (int64_t )DATABASE_WRITE_INTERVAL * 1000000 ) {
1937
1967
// Update best block in wallet (so we can detect restored wallets).
1938
- if (mode != FLUSH_STATE_IF_NEEDED) {
1939
- GetMainSignals ().SetBestChain (chainActive.GetLocator ());
1940
- }
1941
- nLastWrite = GetTimeMicros ();
1968
+ GetMainSignals ().SetBestChain (chainActive.GetLocator ());
1969
+ nLastSetChain = nNow;
1942
1970
}
1943
1971
} catch (const std::runtime_error& e) {
1944
1972
return state.Abort (std::string (" System error while flushing: " ) + e.what ());
@@ -1966,10 +1994,10 @@ void static UpdateTip(CBlockIndex *pindexNew) {
1966
1994
nTimeBestReceived = GetTime ();
1967
1995
mempool.AddTransactionsUpdated (1 );
1968
1996
1969
- LogPrintf (" %s: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%u \n " , __func__,
1997
+ LogPrintf (" %s: new best=%s height=%d log2_work=%.8g tx=%lu date=%s progress=%f cache=%.1fMiB(%utx) \n " , __func__,
1970
1998
chainActive.Tip ()->GetBlockHash ().ToString (), chainActive.Height (), log (chainActive.Tip ()->nChainWork .getdouble ())/log (2.0 ), (unsigned long )chainActive.Tip ()->nChainTx ,
1971
1999
DateTimeStrFormat (" %Y-%m-%d %H:%M:%S" , chainActive.Tip ()->GetBlockTime ()),
1972
- Checkpoints::GuessVerificationProgress (chainParams.Checkpoints (), chainActive.Tip ()), ( unsigned int ) pcoinsTip->GetCacheSize ());
2000
+ Checkpoints::GuessVerificationProgress (chainParams.Checkpoints (), chainActive.Tip ()), pcoinsTip-> DynamicMemoryUsage () * ( 1.0 / ( 1 << 20 )), pcoinsTip->GetCacheSize ());
1973
2001
1974
2002
cvBlockChange.notify_all ();
1975
2003
@@ -3197,7 +3225,7 @@ bool CVerifyDB::VerifyDB(CCoinsView *coinsview, int nCheckLevel, int nCheckDepth
3197
3225
}
3198
3226
}
3199
3227
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
3200
- if (nCheckLevel >= 3 && pindex == pindexState && (coins.GetCacheSize () + pcoinsTip->GetCacheSize ()) <= nCoinCacheSize ) {
3228
+ if (nCheckLevel >= 3 && pindex == pindexState && (coins.DynamicMemoryUsage () + pcoinsTip->DynamicMemoryUsage ()) <= nCoinCacheUsage ) {
3201
3229
bool fClean = true ;
3202
3230
if (!DisconnectBlock (block, state, pindex, coins, &fClean ))
3203
3231
return error (" VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s" , pindex->nHeight , pindex->GetBlockHash ().ToString ());
0 commit comments