aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPieter Wuille <pieter.wuille@gmail.com>2012-03-10 23:04:06 +0100
committerPieter Wuille <pieter.wuille@gmail.com>2012-03-12 20:31:56 +0100
commitd68dcf741e088d8d7033521aa1a1e5e87d9dd283 (patch)
tree5b98bddc5cb9258e5afab24505ad3dba7238b31a
parent336ba312a6ddc08f40ce456bfd09f0711bdc78dc (diff)
downloadbitcoin-d68dcf741e088d8d7033521aa1a1e5e87d9dd283.tar.xz
Limit the impact of reorganisations on the database
Sometimes a new block arrives in a new chain that was already the best valid one, but wasn't marked that way. This happens for example when network rules change to recover after a fork. In this case, it is not necessary to do the entire reorganisation inside a single db commit. These can become huge, and exceed the objects/lockers limits in bdb. This patch limits the blocks the actual reorganisation is applied to, and adds the next blocks afterwards in separate db transactions.
-rw-r--r--src/main.cpp78
-rw-r--r--src/main.h3
2 files changed, 64 insertions, 17 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 20aa069a79..1b56cead3c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1457,6 +1457,32 @@ runCommand(std::string strCommand)
printf("runCommand error: system(%s) returned %d\n", strCommand.c_str(), nErr);
}
+bool CBlock::SetBestChainInner(CTxDB& txdb, CBlockIndex *pindexNew)
+{
+ assert(pindexNew->pprev == pindexBest);
+
+ uint256 hash = GetHash();
+
+ // Adding to current best branch
+ if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash))
+ {
+ txdb.TxnAbort();
+ InvalidChainFound(pindexNew);
+ return false;
+ }
+ if (!txdb.TxnCommit())
+ return error("SetBestChain() : TxnCommit failed");
+
+ // Add to current best branch
+ pindexNew->pprev->pnext = pindexNew;
+
+ // Delete redundant memory transactions
+ BOOST_FOREACH(CTransaction& tx, vtx)
+ tx.RemoveFromMemoryPool();
+
+ return true;
+}
+
bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
{
uint256 hash = GetHash();
@@ -1471,32 +1497,50 @@ bool CBlock::SetBestChain(CTxDB& txdb, CBlockIndex* pindexNew)
}
else if (hashPrevBlock == hashBestChain)
{
- // Adding to current best branch
- if (!ConnectBlock(txdb, pindexNew) || !txdb.WriteHashBestChain(hash))
+ if (!SetBestChainInner(txdb, pindexNew))
+ return error("SetBestChain() : SetBestChainInner failed");
+ }
+ else
+ {
+ // the first block in the new chain that will cause it to become the new best chain
+ CBlockIndex *pindexIntermediate = pindexNew;
+
+ // list of blocks that need to be connected afterwards
+ std::vector<CBlockIndex*> vpindexSecondary;
+
+ // Reorganize is costly in terms of db load, as it works in a single db transaction.
+ // Try to limit how much needs to be done inside
+ while (pindexIntermediate->pprev && pindexIntermediate->pprev->bnChainWork > pindexBest->bnChainWork)
{
- txdb.TxnAbort();
- InvalidChainFound(pindexNew);
- return error("SetBestChain() : ConnectBlock failed");
+ vpindexSecondary.push_back(pindexIntermediate);
+ pindexIntermediate = pindexIntermediate->pprev;
}
- if (!txdb.TxnCommit())
- return error("SetBestChain() : TxnCommit failed");
- // Add to current best branch
- pindexNew->pprev->pnext = pindexNew;
+ if (!vpindexSecondary.empty())
+ printf("Postponing %i reconnects\n", vpindexSecondary.size());
- // Delete redundant memory transactions
- BOOST_FOREACH(CTransaction& tx, vtx)
- tx.RemoveFromMemoryPool();
- }
- else
- {
- // New best branch
- if (!Reorganize(txdb, pindexNew))
+ // Switch to new best branch
+ if (!Reorganize(txdb, pindexIntermediate))
{
txdb.TxnAbort();
InvalidChainFound(pindexNew);
return error("SetBestChain() : Reorganize failed");
}
+
+ // Connect futher blocks
+ BOOST_REVERSE_FOREACH(CBlockIndex *pindex, vpindexSecondary)
+ {
+ CBlock block;
+ if (!block.ReadFromDisk(pindex))
+ {
+ printf("SetBestChain() : ReadFromDisk failed\n");
+ break;
+ }
+ txdb.TxnBegin();
+ // errors now are not fatal, we still did a reorganisation to a new chain in a valid way
+ if (!block.SetBestChainInner(txdb, pindex))
+ break;
+ }
}
// Update best block in wallet (so we can detect restored wallets)
diff --git a/src/main.h b/src/main.h
index 25750dae46..b731d896e8 100644
--- a/src/main.h
+++ b/src/main.h
@@ -1030,6 +1030,9 @@ public:
bool AddToBlockIndex(unsigned int nFile, unsigned int nBlockPos);
bool CheckBlock() const;
bool AcceptBlock();
+
+private:
+ bool SetBestChainInner(CTxDB& txdb, CBlockIndex *pindexNew);
};