@@ -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,36 @@ 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->DynamicMemoryUsage () > nCoinCacheUsage) ||
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.
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
+ // Typical CCoins structures on disk are around 128 bytes in size.
1901
1923
// Pushing a new one to the database can cause it to be written
1902
1924
// twice (once in the log, and once in the tables). This is already
1903
1925
// an overestimation, as most will delete an existing entry or
1904
1926
// overwrite one. Still, use a conservative safety factor of 2.
1905
- if (!CheckDiskSpace (100 * 2 * 2 * pcoinsTip->GetCacheSize ()))
1927
+ if (fDoFullFlush && !CheckDiskSpace (128 * 2 * 2 * pcoinsTip->GetCacheSize ()))
1906
1928
return state.Error (" out of disk space" );
1907
1929
// First make sure all block and undo data is flushed to disk.
1908
1930
FlushBlockFile ();
@@ -1924,21 +1946,24 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) {
1924
1946
return state.Abort (" Files to write to block index database" );
1925
1947
}
1926
1948
}
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
1949
// Finally remove any pruned files
1932
1950
if (fFlushForPrune ) {
1933
1951
UnlinkPrunedFiles (setFilesToPrune);
1934
1952
fCheckForPruning = false ;
1935
1953
}
1936
-
1954
+ nLastWrite = nNow;
1955
+ }
1956
+ // Flush best chain related state. This can only be done if the blocks / block index write was also done.
1957
+ if (fDoFullFlush ) {
1958
+ // Flush the chainstate (which may refer to block index entries).
1959
+ if (!pcoinsTip->Flush ())
1960
+ return state.Abort (" Failed to write to coin database" );
1961
+ nLastFlush = nNow;
1962
+ }
1963
+ if ((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) && nNow > nLastSetChain + (int64_t )DATABASE_WRITE_INTERVAL * 1000000 ) {
1937
1964
// 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 ();
1965
+ GetMainSignals ().SetBestChain (chainActive.GetLocator ());
1966
+ nLastSetChain = nNow;
1942
1967
}
1943
1968
} catch (const std::runtime_error& e) {
1944
1969
return state.Abort (std::string (" System error while flushing: " ) + e.what ());
0 commit comments