aboutsummaryrefslogtreecommitdiff
path: root/src/txdb.cpp
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2017-06-28 18:24:32 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2017-06-28 18:26:41 +0200
commitd4e551adfec298d12f2147467227f07e3a94b872 (patch)
tree38479ecf10f5bf10363d208334e25bb6271b3429 /src/txdb.cpp
parent416af3edf5b5ab265acf95568f2bc9eabd3d96de (diff)
parent176c021d085f5a45bc9e038e760942aa648dd797 (diff)
downloadbitcoin-d4e551adfec298d12f2147467227f07e3a94b872.tar.xz
Merge #10148: Use non-atomic flushing with block replay
176c021 [qa] Test non-atomic chainstate writes (Suhas Daftuar) d6af06d Dont create pcoinsTip until after ReplayBlocks. (Matt Corallo) eaca1b7 Random db flush crash simulator (Pieter Wuille) 0580ee0 Adapt memory usage estimation for flushing (Pieter Wuille) 013a56a Non-atomic flushing using the blockchain as replay journal (Pieter Wuille) b3a279c [MOVEONLY] Move LastCommonAncestor to chain (Pieter Wuille) Tree-SHA512: 47ccc62303f9075c44d2a914be75bd6969ff881a857a2ff1227f05ec7def6f4c71c46680c5a28cb150c814999526797dc05cf2701fde1369c06169f46eccddee
Diffstat (limited to 'src/txdb.cpp')
-rw-r--r--src/txdb.cpp51
1 files changed, 49 insertions, 2 deletions
diff --git a/src/txdb.cpp b/src/txdb.cpp
index 97e916fd22..d24162ba2d 100644
--- a/src/txdb.cpp
+++ b/src/txdb.cpp
@@ -7,8 +7,10 @@
#include "chainparams.h"
#include "hash.h"
+#include "random.h"
#include "pow.h"
#include "uint256.h"
+#include "util.h"
#include <stdint.h>
@@ -21,6 +23,7 @@ static const char DB_TXINDEX = 't';
static const char DB_BLOCK_INDEX = 'b';
static const char DB_BEST_BLOCK = 'B';
+static const char DB_HEAD_BLOCKS = 'H';
static const char DB_FLAG = 'F';
static const char DB_REINDEX_FLAG = 'R';
static const char DB_LAST_BLOCK = 'l';
@@ -68,10 +71,39 @@ uint256 CCoinsViewDB::GetBestBlock() const {
return hashBestChain;
}
+std::vector<uint256> CCoinsViewDB::GetHeadBlocks() const {
+ std::vector<uint256> vhashHeadBlocks;
+ if (!db.Read(DB_HEAD_BLOCKS, vhashHeadBlocks)) {
+ return std::vector<uint256>();
+ }
+ return vhashHeadBlocks;
+}
+
bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
CDBBatch batch(db);
size_t count = 0;
size_t changed = 0;
+ size_t batch_size = (size_t)GetArg("-dbbatchsize", nDefaultDbBatchSize);
+ int crash_simulate = GetArg("-dbcrashratio", 0);
+ assert(!hashBlock.IsNull());
+
+ uint256 old_tip = GetBestBlock();
+ if (old_tip.IsNull()) {
+ // We may be in the middle of replaying.
+ std::vector<uint256> old_heads = GetHeadBlocks();
+ if (old_heads.size() == 2) {
+ assert(old_heads[0] == hashBlock);
+ old_tip = old_heads[1];
+ }
+ }
+
+ // In the first batch, mark the database as being in the middle of a
+ // transition from old_tip to hashBlock.
+ // A vector is used for future extensibility, as we may want to support
+ // interrupting after partial writes from multiple independent reorgs.
+ batch.Erase(DB_BEST_BLOCK);
+ batch.Write(DB_HEAD_BLOCKS, std::vector<uint256>{hashBlock, old_tip});
+
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
if (it->second.flags & CCoinsCacheEntry::DIRTY) {
CoinEntry entry(&it->first);
@@ -84,10 +116,25 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
count++;
CCoinsMap::iterator itOld = it++;
mapCoins.erase(itOld);
+ if (batch.SizeEstimate() > batch_size) {
+ LogPrint(BCLog::COINDB, "Writing partial batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0));
+ db.WriteBatch(batch);
+ batch.Clear();
+ if (crash_simulate) {
+ static FastRandomContext rng;
+ if (rng.randrange(crash_simulate) == 0) {
+ LogPrintf("Simulating a crash. Goodbye.\n");
+ _Exit(0);
+ }
+ }
+ }
}
- if (!hashBlock.IsNull())
- batch.Write(DB_BEST_BLOCK, hashBlock);
+ // In the last batch, mark the database as consistent with hashBlock again.
+ batch.Erase(DB_HEAD_BLOCKS);
+ batch.Write(DB_BEST_BLOCK, hashBlock);
+
+ LogPrint(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0));
bool ret = db.WriteBatch(batch);
LogPrint(BCLog::COINDB, "Committed %u changed transaction outputs (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
return ret;