4
4
5
5
#include " coins.h"
6
6
7
+ #include " memusage.h"
7
8
#include " random.h"
8
9
9
10
#include < assert.h>
@@ -57,13 +58,17 @@ bool CCoinsViewBacked::GetStats(CCoinsStats &stats) const { return base->GetStat
57
58
58
59
CCoinsKeyHasher::CCoinsKeyHasher () : salt(GetRandHash()) {}
59
60
60
- CCoinsViewCache::CCoinsViewCache (CCoinsView *baseIn) : CCoinsViewBacked(baseIn), hasModifier(false ) { }
61
+ CCoinsViewCache::CCoinsViewCache (CCoinsView *baseIn) : CCoinsViewBacked(baseIn), hasModifier(false ), cachedCoinsUsage( 0 ) { }
61
62
62
63
CCoinsViewCache::~CCoinsViewCache ()
63
64
{
64
65
assert (!hasModifier);
65
66
}
66
67
68
+ size_t CCoinsViewCache::DynamicMemoryUsage () const {
69
+ return memusage::DynamicUsage (cacheCoins) + cachedCoinsUsage;
70
+ }
71
+
67
72
CCoinsMap::const_iterator CCoinsViewCache::FetchCoins (const uint256 &txid) const {
68
73
CCoinsMap::iterator it = cacheCoins.find (txid);
69
74
if (it != cacheCoins.end ())
@@ -78,6 +83,7 @@ CCoinsMap::const_iterator CCoinsViewCache::FetchCoins(const uint256 &txid) const
78
83
// version as fresh.
79
84
ret->second .flags = CCoinsCacheEntry::FRESH;
80
85
}
86
+ cachedCoinsUsage += memusage::DynamicUsage (ret->second .coins );
81
87
return ret;
82
88
}
83
89
@@ -93,6 +99,7 @@ bool CCoinsViewCache::GetCoins(const uint256 &txid, CCoins &coins) const {
93
99
CCoinsModifier CCoinsViewCache::ModifyCoins (const uint256 &txid) {
94
100
assert (!hasModifier);
95
101
std::pair<CCoinsMap::iterator, bool > ret = cacheCoins.insert (std::make_pair (txid, CCoinsCacheEntry ()));
102
+ size_t cachedCoinUsage = 0 ;
96
103
if (ret.second ) {
97
104
if (!base->GetCoins (txid, ret.first ->second .coins )) {
98
105
// The parent view does not have this entry; mark it as fresh.
@@ -102,10 +109,12 @@ CCoinsModifier CCoinsViewCache::ModifyCoins(const uint256 &txid) {
102
109
// The parent view only has a pruned entry for this; mark it as fresh.
103
110
ret.first ->second .flags = CCoinsCacheEntry::FRESH;
104
111
}
112
+ } else {
113
+ cachedCoinUsage = memusage::DynamicUsage (ret.first ->second .coins );
105
114
}
106
115
// Assume that whenever ModifyCoins is called, the entry will be modified.
107
116
ret.first ->second .flags |= CCoinsCacheEntry::DIRTY;
108
- return CCoinsModifier (*this , ret.first );
117
+ return CCoinsModifier (*this , ret.first , cachedCoinUsage );
109
118
}
110
119
111
120
const CCoins* CCoinsViewCache::AccessCoins (const uint256 &txid) const {
@@ -150,17 +159,21 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
150
159
assert (it->second .flags & CCoinsCacheEntry::FRESH);
151
160
CCoinsCacheEntry& entry = cacheCoins[it->first ];
152
161
entry.coins .swap (it->second .coins );
162
+ cachedCoinsUsage += memusage::DynamicUsage (entry.coins );
153
163
entry.flags = CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH;
154
164
}
155
165
} else {
156
166
if ((itUs->second .flags & CCoinsCacheEntry::FRESH) && it->second .coins .IsPruned ()) {
157
167
// The grandparent does not have an entry, and the child is
158
168
// modified and being pruned. This means we can just delete
159
169
// it from the parent.
170
+ cachedCoinsUsage -= memusage::DynamicUsage (itUs->second .coins );
160
171
cacheCoins.erase (itUs);
161
172
} else {
162
173
// A normal modification.
174
+ cachedCoinsUsage -= memusage::DynamicUsage (itUs->second .coins );
163
175
itUs->second .coins .swap (it->second .coins );
176
+ cachedCoinsUsage += memusage::DynamicUsage (itUs->second .coins );
164
177
itUs->second .flags |= CCoinsCacheEntry::DIRTY;
165
178
}
166
179
}
@@ -175,6 +188,7 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
175
188
bool CCoinsViewCache::Flush () {
176
189
bool fOk = base->BatchWrite (cacheCoins, hashBlock);
177
190
cacheCoins.clear ();
191
+ cachedCoinsUsage = 0 ;
178
192
return fOk ;
179
193
}
180
194
@@ -232,7 +246,7 @@ double CCoinsViewCache::GetPriority(const CTransaction &tx, int nHeight) const
232
246
return tx.ComputePriority (dResult);
233
247
}
234
248
235
- CCoinsModifier::CCoinsModifier (CCoinsViewCache& cache_, CCoinsMap::iterator it_) : cache(cache_), it(it_) {
249
+ CCoinsModifier::CCoinsModifier (CCoinsViewCache& cache_, CCoinsMap::iterator it_, size_t usage ) : cache(cache_), it(it_), cachedCoinUsage(usage ) {
236
250
assert (!cache.hasModifier );
237
251
cache.hasModifier = true ;
238
252
}
@@ -242,7 +256,11 @@ CCoinsModifier::~CCoinsModifier()
242
256
assert (cache.hasModifier );
243
257
cache.hasModifier = false ;
244
258
it->second .coins .Cleanup ();
259
+ cache.cachedCoinsUsage -= cachedCoinUsage; // Subtract the old usage
245
260
if ((it->second .flags & CCoinsCacheEntry::FRESH) && it->second .coins .IsPruned ()) {
246
261
cache.cacheCoins .erase (it);
262
+ } else {
263
+ // If the coin still exists after the modification, add the new usage
264
+ cache.cachedCoinsUsage += memusage::DynamicUsage (it->second .coins );
247
265
}
248
266
}
0 commit comments