aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2015-05-04 22:00:19 +0200
committerPieter Wuille <pieter.wuille@gmail.com>2015-05-11 17:58:14 -0700
commit67708acff9c18e380fa6136ff0ae718959ead4b5 (patch)
tree26330eafe94d87179a131e73a641dca1533d06c0
parentb3ed4236beb7f68e1720ceb3da15e0c3682ef629 (diff)
Write block index more frequently than cache flushes
-rw-r--r--src/main.cpp55
-rw-r--r--src/main.h6
2 files changed, 44 insertions, 17 deletions
diff --git a/src/main.cpp b/src/main.cpp
index a1b3b81905..28582e0486 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1880,6 +1880,8 @@ enum FlushStateMode {
bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) {
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 {
@@ -1893,16 +1895,36 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) {
}
}
}
- if ((mode == FLUSH_STATE_ALWAYS) ||
- ((mode == FLUSH_STATE_PERIODIC || mode == FLUSH_STATE_IF_NEEDED) && pcoinsTip->DynamicMemoryUsage() > nCoinCacheUsage) ||
- (mode == FLUSH_STATE_PERIODIC && GetTimeMicros() > nLastWrite + DATABASE_WRITE_INTERVAL * 1000000) ||
- fFlushForPrune) {
- // Typical CCoins structures on disk are around 100 bytes in size.
+ int64_t nNow = GetTimeMicros();
+ // Avoid writing/flushing immediately after startup.
+ if (nLastWrite == 0) {
+ nLastWrite = nNow;
+ }
+ if (nLastFlush == 0) {
+ nLastFlush = nNow;
+ }
+ if (nLastSetChain == 0) {
+ nLastSetChain = nNow;
+ }
+ size_t cacheSize = pcoinsTip->DynamicMemoryUsage();
+ // The cache is large and close to the limit, but we have time now (not in the middle of a block processing).
+ bool fCacheLarge = mode == FLUSH_STATE_PERIODIC && cacheSize * (10.0/9) > nCoinCacheUsage;
+ // The cache is over the limit, we have to write now.
+ bool fCacheCritical = mode == FLUSH_STATE_IF_NEEDED && cacheSize > nCoinCacheUsage;
+ // 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.
+ bool fPeriodicWrite = mode == FLUSH_STATE_PERIODIC && nNow > nLastWrite + (int64_t)DATABASE_WRITE_INTERVAL * 1000000;
+ // It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage.
+ bool fPeriodicFlush = mode == FLUSH_STATE_PERIODIC && nNow > nLastFlush + (int64_t)DATABASE_FLUSH_INTERVAL * 1000000;
+ // Combine all conditions that result in a full cache flush.
+ bool fDoFullFlush = (mode == FLUSH_STATE_ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune;
+ // Write blocks and block index to disk.
+ if (fDoFullFlush || fPeriodicWrite) {
+ // Typical CCoins structures on disk are around 128 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.
- if (!CheckDiskSpace(100 * 2 * 2 * pcoinsTip->GetCacheSize()))
+ if (fDoFullFlush && !CheckDiskSpace(128 * 2 * 2 * pcoinsTip->GetCacheSize()))
return state.Error("out of disk space");
// First make sure all block and undo data is flushed to disk.
FlushBlockFile();
@@ -1924,21 +1946,24 @@ bool static FlushStateToDisk(CValidationState &state, FlushStateMode mode) {
return state.Abort("Files to write to block index database");
}
}
- // Flush the chainstate (which may refer to block index entries).
- if (!pcoinsTip->Flush())
- return state.Abort("Failed to write to coin database");
-
// Finally remove any pruned files
if (fFlushForPrune) {
UnlinkPrunedFiles(setFilesToPrune);
fCheckForPruning = false;
}
-
+ nLastWrite = nNow;
+ }
+ // Flush best chain related state. This can only be done if the blocks / block index write was also done.
+ if (fDoFullFlush) {
+ // Flush the chainstate (which may refer to block index entries).
+ if (!pcoinsTip->Flush())
+ return state.Abort("Failed to write to coin database");
+ nLastFlush = nNow;
+ }
+ if ((mode == FLUSH_STATE_ALWAYS || mode == FLUSH_STATE_PERIODIC) && nNow > nLastSetChain + (int64_t)DATABASE_WRITE_INTERVAL * 1000000) {
// Update best block in wallet (so we can detect restored wallets).
- if (mode != FLUSH_STATE_IF_NEEDED) {
- GetMainSignals().SetBestChain(chainActive.GetLocator());
- }
- nLastWrite = GetTimeMicros();
+ GetMainSignals().SetBestChain(chainActive.GetLocator());
+ nLastSetChain = nNow;
}
} catch (const std::runtime_error& e) {
return state.Abort(std::string("System error while flushing: ") + e.what());
diff --git a/src/main.h b/src/main.h
index 2c4a4cb7cd..fcbc4075d2 100644
--- a/src/main.h
+++ b/src/main.h
@@ -82,8 +82,10 @@ static const unsigned int MAX_HEADERS_RESULTS = 2000;
* degree of disordering of blocks on disk (which make reindexing and in the future perhaps pruning
* harder). We'll probably want to make this a per-peer adaptive value at some point. */
static const unsigned int BLOCK_DOWNLOAD_WINDOW = 1024;
-/** Time to wait (in seconds) between writing blockchain state to disk. */
-static const unsigned int DATABASE_WRITE_INTERVAL = 3600;
+/** Time to wait (in seconds) between writing blocks/block index to disk. */
+static const unsigned int DATABASE_WRITE_INTERVAL = 60 * 60;
+/** Time to wait (in seconds) between flushing chainstate to disk. */
+static const unsigned int DATABASE_FLUSH_INTERVAL = 24 * 60 * 60;
/** Maximum length of reject messages. */
static const unsigned int MAX_REJECT_MESSAGE_LENGTH = 111;