From f28aec014edd29cfc669cf1c3f795c0f1e2ae7e2 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 3 Sep 2014 09:01:24 +0200 Subject: Use ModifyCoins instead of mutable GetCoins. Replace the mutable non-copying GetCoins method with a ModifyCoins, which returns an encapsulated iterator, so we can keep track of concurrent modifications (as iterators can be invalidated by those) and run cleanup code after a modification is finished. This also removes the overloading of the 'GetCoins' name. --- src/coins.h | 49 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) (limited to 'src/coins.h') diff --git a/src/coins.h b/src/coins.h index bf61f55aac..62beea3c23 100644 --- a/src/coins.h +++ b/src/coins.h @@ -83,11 +83,26 @@ public: // as new tx version will probably only be introduced at certain heights int nVersion; - // construct a CCoins from a CTransaction, at a given height - CCoins(const CTransaction &tx, int nHeightIn) : fCoinBase(tx.IsCoinBase()), vout(tx.vout), nHeight(nHeightIn), nVersion(tx.nVersion) { + void FromTx(const CTransaction &tx, int nHeightIn) { + fCoinBase = tx.IsCoinBase(); + vout = tx.vout; + nHeight = nHeightIn; + nVersion = tx.nVersion; ClearUnspendable(); } + // construct a CCoins from a CTransaction, at a given height + CCoins(const CTransaction &tx, int nHeightIn) { + FromTx(tx, nHeightIn); + } + + void Clear() { + fCoinBase = false; + std::vector().swap(vout); + nHeight = 0; + nVersion = 0; + } + // empty constructor CCoins() : fCoinBase(false), vout(0), nHeight(0), nVersion(0) { } @@ -323,10 +338,31 @@ public: }; +class CCoinsViewCache; + +/** A reference to a mutable cache entry. Encapsulating it allows us to run + * cleanup code after the modification is finished, and keeping track of + * concurrent modifications. */ +class CCoinsModifier +{ +private: + CCoinsViewCache& cache; + CCoinsMap::iterator it; + CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_); + +public: + CCoins* operator->() { return &it->second; } + CCoins& operator*() { return it->second; } + ~CCoinsModifier(); + friend class CCoinsViewCache; +}; + /** CCoinsView that adds a memory cache for transactions to another CCoinsView */ class CCoinsViewCache : public CCoinsViewBacked { protected: + /* Whether this cache has an active modifier. */ + bool hasModifier; /* Make mutable so that we can "fill the cache" even from Get-methods declared as "const". */ @@ -335,6 +371,7 @@ protected: public: CCoinsViewCache(CCoinsView &baseIn, bool fDummy = false); + ~CCoinsViewCache(); // Standard CCoinsView methods bool GetCoins(const uint256 &txid, CCoins &coins) const; @@ -349,8 +386,10 @@ public: // allowed while accessing the returned pointer. const CCoins* AccessCoins(const uint256 &txid) const; - // Return a modifiable reference to a CCoins. Check HaveCoins first. - CCoins &GetCoins(const uint256 &txid); + // Return a modifiable reference to a CCoins. If no entry with the given + // txid exists, a new one is created. Simultaneous modifications are not + // allowed. + CCoinsModifier ModifyCoins(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. @@ -377,6 +416,8 @@ public: const CTxOut &GetOutputFor(const CTxIn& input) const; + friend class CCoinsModifier; + private: CCoinsMap::iterator FetchCoins(const uint256 &txid); CCoinsMap::const_iterator FetchCoins(const uint256 &txid) const; -- cgit v1.2.3 From c9d1a81ce76737a73c9706e074a4fe8440c8277e Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 3 Sep 2014 09:25:32 +0200 Subject: Get rid of CCoinsView's SetCoins and SetBestBlock. All direct modifications are now done through ModifyCoins, and BatchWrite is used for pushing batches of queued modifications up, so we don't need the low-level SetCoins and SetBestBlock anymore in the top-level CCoinsView class. --- src/coins.h | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'src/coins.h') diff --git a/src/coins.h b/src/coins.h index 62beea3c23..ce7a79740b 100644 --- a/src/coins.h +++ b/src/coins.h @@ -294,9 +294,6 @@ public: // Retrieve the CCoins (unspent transaction outputs) for a given txid virtual bool GetCoins(const uint256 &txid, CCoins &coins) const; - // Modify the CCoins for a given txid - 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(const uint256 &txid) const; @@ -304,10 +301,7 @@ public: // Retrieve the block hash whose state this CCoinsView currently represents virtual uint256 GetBestBlock() const; - // Modify the currently active block hash - virtual bool SetBestBlock(const uint256 &hashBlock); - - // Do a bulk modification (multiple SetCoins + one SetBestBlock). + // Do a bulk modification (multiple CCoins changes + BestBlock change). // The passed mapCoins can be modified. virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); @@ -328,10 +322,8 @@ protected: public: CCoinsViewBacked(CCoinsView &viewIn); bool GetCoins(const uint256 &txid, CCoins &coins) const; - bool SetCoins(const uint256 &txid, const CCoins &coins); bool HaveCoins(const uint256 &txid) const; uint256 GetBestBlock() const; - bool SetBestBlock(const uint256 &hashBlock); void SetBackend(CCoinsView &viewIn); bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); bool GetStats(CCoinsStats &stats) const; @@ -375,10 +367,9 @@ public: // Standard CCoinsView methods bool GetCoins(const uint256 &txid, CCoins &coins) const; - bool SetCoins(const uint256 &txid, const CCoins &coins); bool HaveCoins(const uint256 &txid) const; uint256 GetBestBlock() const; - bool SetBestBlock(const uint256 &hashBlock); + void SetBestBlock(const uint256 &hashBlock); bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock); // Return a pointer to CCoins in the cache, or NULL if not found. This is -- cgit v1.2.3 From 058b08c147a6d56b57221faa5b6fcdb83b4140b2 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 3 Sep 2014 09:37:47 +0200 Subject: Do not keep fully spent but unwritten CCoins entries cached. Instead of storing CCoins entries directly in CCoinsMap, store a CCoinsCacheEntry which additionally keeps track of whether a particular entry is: * dirty: potentially different from its parent view. * fresh: the parent view is known to not have a non-pruned version. This allows us to skip non-dirty cache entries when pushing batches of changes up, and to remove CCoins entries about transactions that are fully spent before the parent cache learns about them. --- src/coins.h | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'src/coins.h') diff --git a/src/coins.h b/src/coins.h index ce7a79740b..71aea79adc 100644 --- a/src/coins.h +++ b/src/coins.h @@ -271,7 +271,20 @@ public: } }; -typedef boost::unordered_map CCoinsMap; +struct CCoinsCacheEntry +{ + CCoins coins; // The actual cached data. + unsigned char flags; + + enum Flags { + DIRTY = (1 << 0), // This cache entry is potentially different from the version in the parent view. + FRESH = (1 << 1), // The parent view does not have this entry (or it is pruned). + }; + + CCoinsCacheEntry() : coins(), flags(0) {} +}; + +typedef boost::unordered_map CCoinsMap; struct CCoinsStats { @@ -343,8 +356,8 @@ private: CCoinsModifier(CCoinsViewCache& cache_, CCoinsMap::iterator it_); public: - CCoins* operator->() { return &it->second; } - CCoins& operator*() { return it->second; } + CCoins* operator->() { return &it->second.coins; } + CCoins& operator*() { return it->second.coins; } ~CCoinsModifier(); friend class CCoinsViewCache; }; -- cgit v1.2.3 From 7c70438dc67547e83953ba0343a071fae304ce65 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 24 Sep 2014 03:19:04 +0200 Subject: Get rid of the dummy CCoinsViewCache constructor arg --- src/coins.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/coins.h') diff --git a/src/coins.h b/src/coins.h index 71aea79adc..4cb28e40c4 100644 --- a/src/coins.h +++ b/src/coins.h @@ -333,7 +333,7 @@ protected: CCoinsView *base; public: - CCoinsViewBacked(CCoinsView &viewIn); + CCoinsViewBacked(CCoinsView *viewIn); bool GetCoins(const uint256 &txid, CCoins &coins) const; bool HaveCoins(const uint256 &txid) const; uint256 GetBestBlock() const; @@ -375,7 +375,7 @@ protected: mutable CCoinsMap cacheCoins; public: - CCoinsViewCache(CCoinsView &baseIn, bool fDummy = false); + CCoinsViewCache(CCoinsView *baseIn); ~CCoinsViewCache(); // Standard CCoinsView methods -- cgit v1.2.3