Browse Source

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.
miguelfreitas
Pieter Wuille 12 years ago
parent
commit
f369d02c51
  1. 37
      src/main.cpp
  2. 35
      src/main.h
  3. 6
      src/txdb.cpp
  4. 6
      src/txdb.h

37
src/main.cpp

@ -171,9 +171,9 @@ void static ResendWalletTransactions()
// CCoinsView implementations // CCoinsView implementations
// //
bool CCoinsView::GetCoins(uint256 txid, CCoins &coins) { return false; } bool CCoinsView::GetCoins(const uint256 &txid, CCoins &coins) { return false; }
bool CCoinsView::SetCoins(uint256 txid, const CCoins &coins) { return false; } bool CCoinsView::SetCoins(const uint256 &txid, const CCoins &coins) { return false; }
bool CCoinsView::HaveCoins(uint256 txid) { return false; } bool CCoinsView::HaveCoins(const uint256 &txid) { return false; }
CBlockIndex *CCoinsView::GetBestBlock() { return NULL; } CBlockIndex *CCoinsView::GetBestBlock() { return NULL; }
bool CCoinsView::SetBestBlock(CBlockIndex *pindex) { return false; } bool CCoinsView::SetBestBlock(CBlockIndex *pindex) { return false; }
bool CCoinsView::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) { return false; } bool CCoinsView::BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex) { return false; }
@ -181,9 +181,9 @@ bool CCoinsView::GetStats(CCoinsStats &stats) { return false; }
CCoinsViewBacked::CCoinsViewBacked(CCoinsView &viewIn) : base(&viewIn) { } CCoinsViewBacked::CCoinsViewBacked(CCoinsView &viewIn) : base(&viewIn) { }
bool CCoinsViewBacked::GetCoins(uint256 txid, CCoins &coins) { return base->GetCoins(txid, coins); } bool CCoinsViewBacked::GetCoins(const uint256 &txid, CCoins &coins) { return base->GetCoins(txid, coins); }
bool CCoinsViewBacked::SetCoins(uint256 txid, const CCoins &coins) { return base->SetCoins(txid, coins); } bool CCoinsViewBacked::SetCoins(const uint256 &txid, const CCoins &coins) { return base->SetCoins(txid, coins); }
bool CCoinsViewBacked::HaveCoins(uint256 txid) { return base->HaveCoins(txid); } bool CCoinsViewBacked::HaveCoins(const uint256 &txid) { return base->HaveCoins(txid); }
CBlockIndex *CCoinsViewBacked::GetBestBlock() { return base->GetBestBlock(); } CBlockIndex *CCoinsViewBacked::GetBestBlock() { return base->GetBestBlock(); }
bool CCoinsViewBacked::SetBestBlock(CBlockIndex *pindex) { return base->SetBestBlock(pindex); } bool CCoinsViewBacked::SetBestBlock(CBlockIndex *pindex) { return base->SetBestBlock(pindex); }
void CCoinsViewBacked::SetBackend(CCoinsView &viewIn) { base = &viewIn; } 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) { } 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)) { if (cacheCoins.count(txid)) {
coins = cacheCoins[txid]; coins = cacheCoins[txid];
return true; return true;
@ -204,29 +204,30 @@ bool CCoinsViewCache::GetCoins(uint256 txid, CCoins &coins) {
return false; return false;
} }
std::map<uint256,CCoins>::iterator CCoinsViewCache::FetchCoins(uint256 txid) { std::map<uint256,CCoins>::iterator CCoinsViewCache::FetchCoins(const uint256 &txid) {
std::map<uint256,CCoins>::iterator it = cacheCoins.find(txid); std::map<uint256,CCoins>::iterator it = cacheCoins.lower_bound(txid);
if (it != cacheCoins.end()) if (it != cacheCoins.end() && it->first == txid)
return it; return it;
CCoins tmp; CCoins tmp;
if (!base->GetCoins(txid,tmp)) if (!base->GetCoins(txid,tmp))
return it; return cacheCoins.end();
std::pair<std::map<uint256,CCoins>::iterator,bool> ret = cacheCoins.insert(std::make_pair(txid, tmp)); std::map<uint256,CCoins>::iterator ret = cacheCoins.insert(it, std::make_pair(txid, CCoins()));
return ret.first; tmp.swap(ret->second);
return ret;
} }
CCoins &CCoinsViewCache::GetCoins(uint256 txid) { CCoins &CCoinsViewCache::GetCoins(const uint256 &txid) {
std::map<uint256,CCoins>::iterator it = FetchCoins(txid); std::map<uint256,CCoins>::iterator it = FetchCoins(txid);
assert(it != cacheCoins.end()); assert(it != cacheCoins.end());
return it->second; return it->second;
} }
bool CCoinsViewCache::SetCoins(uint256 txid, const CCoins &coins) { bool CCoinsViewCache::SetCoins(const uint256 &txid, const CCoins &coins) {
cacheCoins[txid] = coins; cacheCoins[txid] = coins;
return true; return true;
} }
bool CCoinsViewCache::HaveCoins(uint256 txid) { bool CCoinsViewCache::HaveCoins(const uint256 &txid) {
return FetchCoins(txid) != cacheCoins.end(); return FetchCoins(txid) != cacheCoins.end();
} }
@ -263,7 +264,7 @@ unsigned int CCoinsViewCache::GetCacheSize() {
It does not check for spendings by memory pool transactions. */ It does not check for spendings by memory pool transactions. */
CCoinsViewMemPool::CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn) : CCoinsViewBacked(baseIn), mempool(mempoolIn) { } 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)) if (base->GetCoins(txid, coins))
return true; return true;
if (mempool.exists(txid)) { if (mempool.exists(txid)) {
@ -274,7 +275,7 @@ bool CCoinsViewMemPool::GetCoins(uint256 txid, CCoins &coins) {
return false; return false;
} }
bool CCoinsViewMemPool::HaveCoins(uint256 txid) { bool CCoinsViewMemPool::HaveCoins(const uint256 &txid) {
return mempool.exists(txid) || base->HaveCoins(txid); return mempool.exists(txid) || base->HaveCoins(txid);
} }

35
src/main.h

@ -918,6 +918,15 @@ public:
void Cleanup() { void Cleanup() {
while (vout.size() > 0 && vout.back().IsNull()) while (vout.size() > 0 && vout.back().IsNull())
vout.pop_back(); vout.pop_back();
if (vout.empty())
std::vector<CTxOut>().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 // equality test
@ -2077,14 +2086,14 @@ class CCoinsView
{ {
public: public:
// Retrieve the CCoins (unspent transaction outputs) for a given txid // 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 // 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. // Just check whether we have data for a given txid.
// This may (but cannot always) return true for fully spent transactions // 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 // Retrieve the block index whose state this CCoinsView currently represents
virtual CBlockIndex *GetBestBlock(); virtual CBlockIndex *GetBestBlock();
@ -2110,9 +2119,9 @@ protected:
public: public:
CCoinsViewBacked(CCoinsView &viewIn); CCoinsViewBacked(CCoinsView &viewIn);
bool GetCoins(uint256 txid, CCoins &coins); bool GetCoins(const uint256 &txid, CCoins &coins);
bool SetCoins(uint256 txid, const CCoins &coins); bool SetCoins(const uint256 &txid, const CCoins &coins);
bool HaveCoins(uint256 txid); bool HaveCoins(const uint256 &txid);
CBlockIndex *GetBestBlock(); CBlockIndex *GetBestBlock();
bool SetBestBlock(CBlockIndex *pindex); bool SetBestBlock(CBlockIndex *pindex);
void SetBackend(CCoinsView &viewIn); void SetBackend(CCoinsView &viewIn);
@ -2131,9 +2140,9 @@ public:
CCoinsViewCache(CCoinsView &baseIn, bool fDummy = false); CCoinsViewCache(CCoinsView &baseIn, bool fDummy = false);
// Standard CCoinsView methods // Standard CCoinsView methods
bool GetCoins(uint256 txid, CCoins &coins); bool GetCoins(const uint256 &txid, CCoins &coins);
bool SetCoins(uint256 txid, const CCoins &coins); bool SetCoins(const uint256 &txid, const CCoins &coins);
bool HaveCoins(uint256 txid); bool HaveCoins(const uint256 &txid);
CBlockIndex *GetBestBlock(); CBlockIndex *GetBestBlock();
bool SetBestBlock(CBlockIndex *pindex); bool SetBestBlock(CBlockIndex *pindex);
bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex); bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);
@ -2141,7 +2150,7 @@ public:
// Return a modifiable reference to a CCoins. Check HaveCoins first. // Return a modifiable reference to a CCoins. Check HaveCoins first.
// Many methods explicitly require a CCoinsViewCache because of this method, to reduce // Many methods explicitly require a CCoinsViewCache because of this method, to reduce
// copying. // copying.
CCoins &GetCoins(uint256 txid); CCoins &GetCoins(const uint256 &txid);
// Push the modifications applied to this cache to its base. // Push the modifications applied to this cache to its base.
// Failure to call this method before destruction will cause the changes to be forgotten. // Failure to call this method before destruction will cause the changes to be forgotten.
@ -2151,7 +2160,7 @@ public:
unsigned int GetCacheSize(); unsigned int GetCacheSize();
private: private:
std::map<uint256,CCoins>::iterator FetchCoins(uint256 txid); std::map<uint256,CCoins>::iterator FetchCoins(const uint256 &txid);
}; };
/** CCoinsView that brings transactions from a memorypool into view. /** CCoinsView that brings transactions from a memorypool into view.
@ -2163,8 +2172,8 @@ protected:
public: public:
CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn); CCoinsViewMemPool(CCoinsView &baseIn, CTxMemPool &mempoolIn);
bool GetCoins(uint256 txid, CCoins &coins); bool GetCoins(const uint256 &txid, CCoins &coins);
bool HaveCoins(uint256 txid); bool HaveCoins(const uint256 &txid);
}; };
/** Global variable that points to the active CCoinsView (protected by cs_main) */ /** Global variable that points to the active CCoinsView (protected by cs_main) */

6
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) { 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); 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; CLevelDBBatch batch;
BatchWriteCoins(batch, txid, coins); BatchWriteCoins(batch, txid, coins);
return db.WriteBatch(batch); return db.WriteBatch(batch);
} }
bool CCoinsViewDB::HaveCoins(uint256 txid) { bool CCoinsViewDB::HaveCoins(const uint256 &txid) {
return db.Exists(make_pair('c', txid)); return db.Exists(make_pair('c', txid));
} }

6
src/txdb.h

@ -16,9 +16,9 @@ protected:
public: public:
CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false); CCoinsViewDB(size_t nCacheSize, bool fMemory = false, bool fWipe = false);
bool GetCoins(uint256 txid, CCoins &coins); bool GetCoins(const uint256 &txid, CCoins &coins);
bool SetCoins(uint256 txid, const CCoins &coins); bool SetCoins(const uint256 &txid, const CCoins &coins);
bool HaveCoins(uint256 txid); bool HaveCoins(const uint256 &txid);
CBlockIndex *GetBestBlock(); CBlockIndex *GetBestBlock();
bool SetBestBlock(CBlockIndex *pindex); bool SetBestBlock(CBlockIndex *pindex);
bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex); bool BatchWrite(const std::map<uint256, CCoins> &mapCoins, CBlockIndex *pindex);

Loading…
Cancel
Save