From f369d02c51077ffa1644954d0478e93966e1bb72 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Sun, 20 Jan 2013 18:05:34 +0100 Subject: [PATCH] Various performance tweaks to CCoinsView * Pass txid's to CCoinsView functions by reference instead of by value * Add a method to swap CCoins, and use it in some places to avoid a allocating copy + destruct. * Optimize CCoinsViewCache::FetchCoins to do only a single search through the backing map. --- src/main.cpp | 37 +++++++++++++++++++------------------ src/main.h | 35 ++++++++++++++++++++++------------- src/txdb.cpp | 6 +++--- src/txdb.h | 6 +++--- 4 files changed, 47 insertions(+), 37 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 84a5cdc1..212240ec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -171,9 +171,9 @@ void static ResendWalletTransactions() // CCoinsView implementations // -bool CCoinsView::GetCoins(uint256 txid, CCoins &coins) { return false; } -bool CCoinsView::SetCoins(uint256 txid, const CCoins &coins) { return false; } -bool CCoinsView::HaveCoins(uint256 txid) { return false; } +bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) { return false; } +bool CCoinsView::SetCoins(const uint256 &txid, const CCoins &coins) { return false; } +bool CCoinsView::HaveCoins(const uint256 &txid) { return false; } CBlockIndex *CCoinsView::GetBestBlock() { return NULL; } bool CCoinsView::SetBestBlock(CBlockIndex *pindex) { return false; } bool CCoinsView::BatchWrite(const std::map &mapCoins, CBlockIndex *pindex) { return false; } @@ -181,9 +181,9 @@ bool CCoinsView::GetStats(CCoinsStats &stats) { return false; } CCoinsViewBacked::CCoinsViewBacked(CCoinsView &viewIn) : base(&viewIn) { } -bool CCoinsViewBacked::GetCoins(uint256 txid, CCoins &coins) { return base->GetCoins(txid, coins); } -bool CCoinsViewBacked::SetCoins(uint256 txid, const CCoins &coins) { return base->SetCoins(txid, coins); } -bool CCoinsViewBacked::HaveCoins(uint256 txid) { return base->HaveCoins(txid); } +bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) { return base->GetCoins(txid, coins); } +bool CCoinsViewBacked::SetCoins(const uint256 &txid, const CCoins &coins) { return base->SetCoins(txid, coins); } +bool CCoinsViewBacked::HaveCoins(const uint256 &txid) { return base->HaveCoins(txid); } CBlockIndex *CCoinsViewBacked::GetBestBlock() { return base->GetBestBlock(); } bool CCoinsViewBacked::SetBestBlock(CBlockIndex *pindex) { return base->SetBestBlock(pindex); } void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; } @@ -192,7 +192,7 @@ bool CCoinsViewBacked::GetStats(CCoinsStats &stats) { return base->GetStats(stat CCoinsViewCache::CCoinsViewCache(CCoinsView &baseIn, bool fDummy) : CCoinsViewBacked(baseIn), pindexTip(NULL) { } -bool CCoinsViewCache::GetCoins(uint256 txid, CCoins &coins) { +bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) { if (cacheCoins.count(txid)) { coins = cacheCoins[txid]; return true; @@ -204,29 +204,30 @@ bool CCoinsViewCache::GetCoins(uint256 txid, CCoins &coins) { return false; } -std::map::iterator CCoinsViewCache::FetchCoins(uint256 txid) { - std::map::iterator it = cacheCoins.find(txid); - if (it != cacheCoins.end()) +std::map::iterator CCoinsViewCache::FetchCoins(const uint256 &txid) { + std::map::iterator it = cacheCoins.lower_bound(txid); + if (it != cacheCoins.end() && it->first == txid) return it; CCoins tmp; if (!base->GetCoins(txid,tmp)) - return it; - std::pair::iterator,bool> ret = cacheCoins.insert(std::make_pair(txid, tmp)); - return ret.first; + return cacheCoins.end(); + std::map::iterator ret = cacheCoins.insert(it, std::make_pair(txid, CCoins())); + tmp.swap(ret->second); + return ret; } -CCoins &CCoinsViewCache::GetCoins(uint256 txid) { +CCoins &CCoinsViewCache::GetCoins(const uint256 &txid) { std::map::iterator it = FetchCoins(txid); assert(it != cacheCoins.end()); return it->second; } -bool CCoinsViewCache::SetCoins(uint256 txid, const CCoins &coins) { +bool CCoinsViewCache::SetCoins(const uint256 &txid, const CCoins &coins) { cacheCoins[txid] = coins; return true; } -bool CCoinsViewCache::HaveCoins(uint256 txid) { +bool CCoinsViewCache::HaveCoins(const uint256 &txid) { return FetchCoins(txid) != cacheCoins.end(); } @@ -263,7 +264,7 @@ unsigned int CCoinsViewCache::GetCacheSize() { It does not check for spendings by memory pool transactions. */ CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { } -bool CCoinsViewMemPool::GetCoins(uint256 txid, CCoins &coins) { +bool CCoinsViewMemPool::GetCoins(const uint256 &txid, CCoins &coins) { if (base->GetCoins(txid, coins)) return true; if (mempool.exists(txid)) { @@ -274,7 +275,7 @@ bool CCoinsViewMemPool::GetCoins(uint256 txid, CCoins &coins) { return false; } -bool CCoinsViewMemPool::HaveCoins(uint256 txid) { +bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) { return mempool.exists(txid) || base->HaveCoins(txid); } diff --git a/src/main.h b/src/main.h index edfea7b5..d5f7093e 100644 --- a/src/main.h +++ b/src/main.h @@ -918,6 +918,15 @@ public: void Cleanup() { while (vout.size() > 0 && vout.back().IsNull()) vout.pop_back(); + if (vout.empty()) + std::vector().swap(vout); + } + + void swap(CCoins &to) { + std::swap(to.fCoinBase, fCoinBase); + to.vout.swap(vout); + std::swap(to.nHeight, nHeight); + std::swap(to.nVersion, nVersion); } // equality test @@ -2077,14 +2086,14 @@ class CCoinsView { public: // Retrieve the CCoins (unspent transaction outputs) for a given txid - virtual bool GetCoins(uint256 txid, CCoins &coins); + virtual bool GetCoins(const uint256 &txid, CCoins &coins); // Modify the CCoins for a given txid - virtual bool SetCoins(uint256 txid, const CCoins &coins); + virtual bool SetCoins(const uint256 &txid, const CCoins &coins); // Just check whether we have data for a given txid. // This may (but cannot always) return true for fully spent transactions - virtual bool HaveCoins(uint256 txid); + virtual bool HaveCoins(const uint256 &txid); // Retrieve the block index whose state this CCoinsView currently represents virtual CBlockIndex *GetBestBlock(); @@ -2110,9 +2119,9 @@ protected: public: CCoinsViewBacked(CCoinsView &viewIn); - bool GetCoins(uint256 txid, CCoins &coins); - bool SetCoins(uint256 txid, const CCoins &coins); - bool HaveCoins(uint256 txid); + bool GetCoins(const uint256 &txid, CCoins &coins); + bool SetCoins(const uint256 &txid, const CCoins &coins); + bool HaveCoins(const uint256 &txid); CBlockIndex *GetBestBlock(); bool SetBestBlock(CBlockIndex *pindex); void SetBackend(CCoinsView &viewIn); @@ -2131,9 +2140,9 @@ public: CCoinsViewCache(CCoinsView &baseIn, bool fDummy = false); // Standard CCoinsView methods - bool GetCoins(uint256 txid, CCoins &coins); - bool SetCoins(uint256 txid, const CCoins &coins); - bool HaveCoins(uint256 txid); + bool GetCoins(const uint256 &txid, CCoins &coins); + bool SetCoins(const uint256 &txid, const CCoins &coins); + bool HaveCoins(const uint256 &txid); CBlockIndex *GetBestBlock(); bool SetBestBlock(CBlockIndex *pindex); bool BatchWrite(const std::map &mapCoins, CBlockIndex *pindex); @@ -2141,7 +2150,7 @@ public: // Return a modifiable reference to a CCoins. Check HaveCoins first. // Many methods explicitly require a CCoinsViewCache because of this method, to reduce // copying. - CCoins &GetCoins(uint256 txid); + CCoins &GetCoins(const uint256 &txid); // Push the modifications applied to this cache to its base. // Failure to call this method before destruction will cause the changes to be forgotten. @@ -2151,7 +2160,7 @@ public: unsigned int GetCacheSize(); private: - std::map::iterator FetchCoins(uint256 txid); + std::map::iterator FetchCoins(const uint256 &txid); }; /** CCoinsView that brings transactions from a memorypool into view. @@ -2163,8 +2172,8 @@ protected: public: CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn); - bool GetCoins(uint256 txid, CCoins &coins); - bool HaveCoins(uint256 txid); + bool GetCoins(const uint256 &txid, CCoins &coins); + bool HaveCoins(const uint256 &txid); }; /** Global variable that points to the active CCoinsView (protected by cs_main) */ diff --git a/src/txdb.cpp b/src/txdb.cpp index 78fa0279..ca4e6c9b 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -22,17 +22,17 @@ void static BatchWriteHashBestChain(CLevelDBBatch &batch, const uint256 &hash) { CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "coins", nCacheSize, fMemory, fWipe) { } -bool CCoinsViewDB::GetCoins(uint256 txid, CCoins &coins) { +bool CCoinsViewDB::GetCoins(const uint256 &txid, CCoins &coins) { return db.Read(make_pair('c', txid), coins); } -bool CCoinsViewDB::SetCoins(uint256 txid, const CCoins &coins) { +bool CCoinsViewDB::SetCoins(const uint256 &txid, const CCoins &coins) { CLevelDBBatch batch; BatchWriteCoins(batch, txid, coins); return db.WriteBatch(batch); } -bool CCoinsViewDB::HaveCoins(uint256 txid) { +bool CCoinsViewDB::HaveCoins(const uint256 &txid) { return db.Exists(make_pair('c', txid)); } diff --git a/src/txdb.h b/src/txdb.h index ebac81b3..47496edd 100644 --- a/src/txdb.h +++ b/src/txdb.h @@ -16,9 +16,9 @@ protected: public: CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); - bool GetCoins(uint256 txid, CCoins &coins); - bool SetCoins(uint256 txid, const CCoins &coins); - bool HaveCoins(uint256 txid); + bool GetCoins(const uint256 &txid, CCoins &coins); + bool SetCoins(const uint256 &txid, const CCoins &coins); + bool HaveCoins(const uint256 &txid); CBlockIndex *GetBestBlock(); bool SetBestBlock(CBlockIndex *pindex); bool BatchWrite(const std::map &mapCoins, CBlockIndex *pindex);