From b0875eb3fea0934f3a6651fbc22aac12e33e15e5 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 24 Aug 2014 02:08:05 +0200 Subject: [PATCH] Allow BatchWrite to destroy its input, reducing copying --- src/coins.cpp | 16 +++++++++------- src/coins.h | 10 ++++++---- src/txdb.cpp | 7 +++++-- src/txdb.h | 2 +- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/coins.cpp b/src/coins.cpp index fe40911db..6137b51c5 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -57,7 +57,7 @@ bool CCoinsView::SetCoins(const uint256 &txid, const CCoins &coins) { return fal bool CCoinsView::HaveCoins(const uint256 &txid) { return false; } uint256 CCoinsView::GetBestBlock() { return uint256(0); } bool CCoinsView::SetBestBlock(const uint256 &hashBlock) { return false; } -bool CCoinsView::BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; } +bool CCoinsView::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return false; } bool CCoinsView::GetStats(CCoinsStats &stats) { return false; } @@ -68,7 +68,7 @@ bool CCoinsViewBacked::HaveCoins(const uint256 &txid) { return base->HaveCoins(t uint256 CCoinsViewBacked::GetBestBlock() { return base->GetBestBlock(); } bool CCoinsViewBacked::SetBestBlock(const uint256 &hashBlock) { return base->SetBestBlock(hashBlock); } void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; } -bool CCoinsViewBacked::BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); } +bool CCoinsViewBacked::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { return base->BatchWrite(mapCoins, hashBlock); } bool CCoinsViewBacked::GetStats(CCoinsStats &stats) { return base->GetStats(stats); } CCoinsKeyHasher::CCoinsKeyHasher() : salt(GetRandHash()) {} @@ -130,17 +130,19 @@ bool CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) { return true; } -bool CCoinsViewCache::BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlockIn) { - for (CCoinsMap::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++) - cacheCoins[it->first] = it->second; +bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn) { + for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { + cacheCoins[it->first].swap(it->second); + CCoinsMap::iterator itOld = it++; + mapCoins.erase(itOld); + } hashBlock = hashBlockIn; return true; } bool CCoinsViewCache::Flush() { bool fOk = base->BatchWrite(cacheCoins, hashBlock); - if (fOk) - cacheCoins.clear(); + cacheCoins.clear(); return fOk; } diff --git a/src/coins.h b/src/coins.h index ff6028816..2b657299e 100644 --- a/src/coins.h +++ b/src/coins.h @@ -291,8 +291,9 @@ public: // Modify the currently active block hash virtual bool SetBestBlock(const uint256 &hashBlock); - // Do a bulk modification (multiple SetCoins + one SetBestBlock) - virtual bool BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock); + // Do a bulk modification (multiple SetCoins + one SetBestBlock). + // The passed mapCoins can be modified. + virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); // Calculate statistics about the unspent transaction output set virtual bool GetStats(CCoinsStats &stats); @@ -316,7 +317,7 @@ public: uint256 GetBestBlock(); bool SetBestBlock(const uint256 &hashBlock); void SetBackend(CCoinsView &viewIn); - bool BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock); + bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); bool GetStats(CCoinsStats &stats); }; @@ -337,7 +338,7 @@ public: bool HaveCoins(const uint256 &txid); uint256 GetBestBlock(); bool SetBestBlock(const uint256 &hashBlock); - bool BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock); + bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); // Return a modifiable reference to a CCoins. Check HaveCoins first. // Many methods explicitly require a CCoinsViewCache because of this method, to reduce @@ -346,6 +347,7 @@ public: // Push the modifications applied to this cache to its base. // Failure to call this method before destruction will cause the changes to be forgotten. + // If false is returned, the state of this cache (and its backing view) will be undefined. bool Flush(); // Calculate the size of the cache (in number of transactions) diff --git a/src/txdb.cpp b/src/txdb.cpp index d3d05c58d..7c0683aaf 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -54,12 +54,15 @@ bool CCoinsViewDB::SetBestBlock(const uint256 &hashBlock) { return db.WriteBatch(batch); } -bool CCoinsViewDB::BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock) { +bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { LogPrint("coindb", "Committing %u changed transactions to coin database...\n", (unsigned int)mapCoins.size()); CLevelDBBatch batch; - for (CCoinsMap::const_iterator it = mapCoins.begin(); it != mapCoins.end(); it++) + for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { BatchWriteCoins(batch, it->first, it->second); + CCoinsMap::iterator itOld = it++; + mapCoins.erase(itOld); + } if (hashBlock != uint256(0)) BatchWriteHashBestChain(batch, hashBlock); diff --git a/src/txdb.h b/src/txdb.h index 7d670c254..099f15177 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -37,7 +37,7 @@ public: bool HaveCoins(const uint256 &txid); uint256 GetBestBlock(); bool SetBestBlock(const uint256 &hashBlock); - bool BatchWrite(const CCoinsMap &mapCoins, const uint256 &hashBlock); + bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); bool GetStats(CCoinsStats &stats); };