1212bool CCoinsView::GetCoin (const COutPoint &outpoint, Coin &coin) const { return false ; }
1313uint256 CCoinsView::GetBestBlock () const { return uint256 (); }
1414std::vector<uint256> CCoinsView::GetHeadBlocks () const { return std::vector<uint256>(); }
15- bool CCoinsView::BatchWrite (CCoinsMap &mapCoins , const uint256 &hashBlock, bool erase ) { return false ; }
15+ bool CCoinsView::BatchWrite (CoinsViewCacheCursor& cursor , const uint256 &hashBlock) { return false ; }
1616std::unique_ptr<CCoinsViewCursor> CCoinsView::Cursor () const { return nullptr ; }
1717
1818bool CCoinsView::HaveCoin (const COutPoint &outpoint) const
@@ -27,7 +27,7 @@ bool CCoinsViewBacked::HaveCoin(const COutPoint &outpoint) const { return base->
2727uint256 CCoinsViewBacked::GetBestBlock () const { return base->GetBestBlock (); }
2828std::vector<uint256> CCoinsViewBacked::GetHeadBlocks () const { return base->GetHeadBlocks (); }
2929void CCoinsViewBacked::SetBackend (CCoinsView &viewIn) { base = &viewIn; }
30- bool CCoinsViewBacked::BatchWrite (CCoinsMap &mapCoins , const uint256 &hashBlock, bool erase ) { return base->BatchWrite (mapCoins , hashBlock, erase ); }
30+ bool CCoinsViewBacked::BatchWrite (CoinsViewCacheCursor& cursor , const uint256 &hashBlock) { return base->BatchWrite (cursor , hashBlock); }
3131std::unique_ptr<CCoinsViewCursor> CCoinsViewBacked::Cursor () const { return base->Cursor (); }
3232size_t CCoinsViewBacked::EstimateSize () const { return base->EstimateSize (); }
3333
@@ -183,10 +183,8 @@ void CCoinsViewCache::SetBestBlock(const uint256 &hashBlockIn) {
183183 hashBlock = hashBlockIn;
184184}
185185
186- bool CCoinsViewCache::BatchWrite (CCoinsMap &mapCoins, const uint256 &hashBlockIn, bool erase) {
187- for (CCoinsMap::iterator it = mapCoins.begin ();
188- it != mapCoins.end ();
189- it = erase ? mapCoins.erase (it) : std::next (it)) {
186+ bool CCoinsViewCache::BatchWrite (CoinsViewCacheCursor& cursor, const uint256 &hashBlockIn) {
187+ for (auto it{cursor.Begin ()}; it != cursor.End (); it = cursor.NextAndMaybeErase (*it)) {
190188 // Ignore non-dirty entries (optimization).
191189 if (!it->second .IsDirty ()) {
192190 continue ;
@@ -200,10 +198,9 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
200198 // and mark it as dirty.
201199 itUs = cacheCoins.try_emplace (it->first ).first ;
202200 CCoinsCacheEntry& entry{itUs->second };
203- if (erase) {
204- // The `move` call here is purely an optimization; we rely on the
205- // `mapCoins.erase` call in the `for` expression to actually remove
206- // the entry from the child map.
201+ if (cursor.WillErase (*it)) {
202+ // Since this entry will be erased,
203+ // we can move the coin into us instead of copying it
207204 entry.coin = std::move (it->second .coin );
208205 } else {
209206 entry.coin = it->second .coin ;
@@ -235,10 +232,9 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
235232 } else {
236233 // A normal modification.
237234 cachedCoinsUsage -= itUs->second .coin .DynamicMemoryUsage ();
238- if (erase) {
239- // The `move` call here is purely an optimization; we rely on the
240- // `mapCoins.erase` call in the `for` expression to actually remove
241- // the entry from the child map.
235+ if (cursor.WillErase (*it)) {
236+ // Since this entry will be erased,
237+ // we can move the coin into us instead of copying it
242238 itUs->second .coin = std::move (it->second .coin );
243239 } else {
244240 itUs->second .coin = it->second .coin ;
@@ -257,12 +253,10 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
257253}
258254
259255bool CCoinsViewCache::Flush () {
260- bool fOk = base->BatchWrite (cacheCoins, hashBlock, /* erase=*/ true );
256+ auto cursor{CoinsViewCacheCursor (cachedCoinsUsage, m_sentinel, cacheCoins, /* will_erase=*/ true )};
257+ bool fOk = base->BatchWrite (cursor, hashBlock);
261258 if (fOk ) {
262- if (!cacheCoins.empty ()) {
263- /* BatchWrite must erase all cacheCoins elements when erase=true. */
264- throw std::logic_error (" Not all cached coins were erased" );
265- }
259+ cacheCoins.clear ();
266260 ReallocateCache ();
267261 }
268262 cachedCoinsUsage = 0 ;
@@ -271,7 +265,8 @@ bool CCoinsViewCache::Flush() {
271265
272266bool CCoinsViewCache::Sync ()
273267{
274- bool fOk = base->BatchWrite (cacheCoins, hashBlock, /* erase=*/ false );
268+ auto cursor{CoinsViewCacheCursor (cachedCoinsUsage, m_sentinel, cacheCoins, /* will_erase=*/ false )};
269+ bool fOk = base->BatchWrite (cursor, hashBlock);
275270 // Instead of clearing `cacheCoins` as we would in Flush(), just clear the
276271 // FRESH/DIRTY flags of any coin that isn't spent.
277272 for (auto it = cacheCoins.begin (); it != cacheCoins.end (); ) {
0 commit comments