@@ -1876,6 +1876,8 @@ enum FlushStateMode {
1876
1876
bool static FlushStateToDisk (CValidationState &state, FlushStateMode mode) {
1877
1877
LOCK2 (cs_main, cs_LastBlockFile);
1878
1878
static int64_t nLastWrite = 0 ;
1879
+ static int64_t nLastFlush = 0 ;
1880
+ static int64_t nLastSetChain = 0 ;
1879
1881
std::set<int > setFilesToPrune;
1880
1882
bool fFlushForPrune = false ;
1881
1883
try {
@@ -1889,16 +1891,36 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) {
1889
1891
}
1890
1892
}
1891
1893
}
1892
- if ((mode == FLUSH_STATE_ALWAYS) ||
1893
- ((mode == FLUSH_STATE_PERIODIC || mode == FLUSH_STATE_IF_NEEDED) && pcoinsTip->DynamicMemoryUsage () > nCoinCacheUsage) ||
1894
- (mode == FLUSH_STATE_PERIODIC && GetTimeMicros () > nLastWrite + DATABASE_WRITE_INTERVAL * 1000000 ) ||
1895
- fFlushForPrune ) {
1896
- // Typical CCoins structures on disk are around 100 bytes in size.
1894
+ int64_t nNow = GetTimeMicros ();
1895
+ // Avoid writing/flushing immediately after startup.
1896
+ if (nLastWrite == 0 ) {
1897
+ nLastWrite = nNow;
1898
+ }
1899
+ if (nLastFlush == 0 ) {
1900
+ nLastFlush = nNow;
1901
+ }
1902
+ if (nLastSetChain == 0 ) {
1903
+ nLastSetChain = nNow;
1904
+ }
1905
+ size_t cacheSize = pcoinsTip->DynamicMemoryUsage ();
1906
+ // The cache is large and close to the limit, but we have time now (not in the middle of a block processing).
1907
+ bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize * (10.0 /9 ) > nCoinCacheUsage;
1908
+ // The cache is over the limit, we have to write now.
1909
+ bool fCacheCritical = mode == FLUSH_STATE_IF_NEEDED && cacheSize > nCoinCacheUsage;
1910
+ // 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.
1911
+ bool fPeriodicWrite = mode == FLUSH_STATE_PERIODIC && nNow > nLastWrite + (int64_t )DATABASE_WRITE_INTERVAL * 1000000 ;
1912
+ // It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage.
1913
+ bool fPeriodicFlush = mode == FLUSH_STATE_PERIODIC && nNow > nLastFlush + (int64_t )DATABASE_FLUSH_INTERVAL * 1000000 ;
1914
+ // Combine all conditions that result in a full cache flush.
1915
+ bool fDoFullFlush = (mode == FLUSH_STATE_ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune ;
1916
+ // Write blocks and block index to disk.
1917
+ if (fDoFullFlush || fPeriodicWrite ) {
1918
+ // Typical CCoins structures on disk are around 128 bytes in size.
1897
1919
// Pushing a new one to the database can cause it to be written
1898
1920
// twice (once in the log, and once in the tables). This is already
1899
1921
// an overestimation, as most will delete an existing entry or
1900
1922
// overwrite one. Still, use a conservative safety factor of 2.
1901
- if (!CheckDiskSpace (100 * 2 * 2 * pcoinsTip->GetCacheSize ()))
1923
+ if (fDoFullFlush && !CheckDiskSpace (128 * 2 * 2 * pcoinsTip->GetCacheSize ()))
1902
1924
return state.Error (" out of disk space" );
1903
1925
// First make sure all block and undo data is flushed to disk.
1904
1926
FlushBlockFile ();
@@ -1920,21 +1942,24 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) {
1920
1942
return state.Abort (" Files to write to block index database" );
1921
1943
}
1922
1944
}
1923
- // Flush the chainstate (which may refer to block index entries).
1924
- if (!pcoinsTip->Flush ())
1925
- return state.Abort (" Failed to write to coin database" );
1926
-
1927
1945
// Finally remove any pruned files
1928
1946
if (fFlushForPrune ) {
1929
1947
UnlinkPrunedFiles (setFilesToPrune);
1930
1948
fCheckForPruning = false ;
1931
1949
}
1932
-
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
+ // Flush the chainstate (which may refer to block index entries).
1955
+ if (!pcoinsTip->Flush ())
1956
+ return state.Abort (" Failed to write to coin database" );
1957
+ nLastFlush = nNow;
1958
+ }
1959
+ if ((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) && nNow > nLastSetChain + (int64_t )DATABASE_WRITE_INTERVAL * 1000000 ) {
1933
1960
// Update best block in wallet (so we can detect restored wallets).
1934
- if (mode != FLUSH_STATE_IF_NEEDED) {
1935
- GetMainSignals ().SetBestChain (chainActive.GetLocator ());
1936
- }
1937
- nLastWrite = GetTimeMicros ();
1961
+ GetMainSignals ().SetBestChain (chainActive.GetLocator ());
1962
+ nLastSetChain = nNow;
1938
1963
}
1939
1964
} catch (const std::runtime_error& e) {
1940
1965
return state.Abort (std::string (" System error while flushing: " ) + e.what ());
0 commit comments