Skip to content

Commit 05d5918

Browse files
committed
Merge pull request #5967
072e2f8 Alter assumptions in CCoinsViewCache::BatchWrite (Alex Morcos)
2 parents 9a3e1a5 + 072e2f8 commit 05d5918

File tree

2 files changed

+28
-7
lines changed

2 files changed

+28
-7
lines changed

src/coins.cpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -160,18 +160,23 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
160160
if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
161161
CCoinsMap::iterator itUs = cacheCoins.find(it->first);
162162
if (itUs == cacheCoins.end()) {
163-
if (!it->second.coins.IsPruned()) {
164-
// The parent cache does not have an entry, while the child
165-
// cache does have (a non-pruned) one. Move the data up, and
166-
// mark it as fresh (if the grandparent did have it, we
167-
// would have pulled it in at first GetCoins).
168-
assert(it->second.flags & CCoinsCacheEntry::FRESH);
163+
// The parent cache does not have an entry, while the child does
164+
// We can ignore it if it's both FRESH and pruned in the child
165+
if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coins.IsPruned())) {
166+
// Otherwise we will need to create it in the parent
167+
// and move the data up and mark it as dirty
169168
CCoinsCacheEntry& entry = cacheCoins[it->first];
170169
entry.coins.swap(it->second.coins);
171170
cachedCoinsUsage += entry.coins.DynamicMemoryUsage();
172-
entry.flags = CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH;
171+
entry.flags = CCoinsCacheEntry::DIRTY;
172+
// We can mark it FRESH in the parent if it was FRESH in the child
173+
// Otherwise it might have just been flushed from the parent's cache
174+
// and already exist in the grandparent
175+
if (it->second.flags & CCoinsCacheEntry::FRESH)
176+
entry.flags |= CCoinsCacheEntry::FRESH;
173177
}
174178
} else {
179+
// Found the entry in the parent cache
175180
if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coins.IsPruned()) {
176181
// The grandparent does not have an entry, and the child is
177182
// modified and being pruned. This means we can just delete

src/test/coins_tests.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,14 +164,23 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
164164
}
165165
}
166166

167+
if (insecure_rand() % 100 == 0) {
168+
// Every 100 iterations, flush an intermediate cache
169+
if (stack.size() > 1 && insecure_rand() % 2 == 0) {
170+
unsigned int flushIndex = insecure_rand() % (stack.size() - 1);
171+
stack[flushIndex]->Flush();
172+
}
173+
}
167174
if (insecure_rand() % 100 == 0) {
168175
// Every 100 iterations, change the cache stack.
169176
if (stack.size() > 0 && insecure_rand() % 2 == 0) {
177+
//Remove the top cache
170178
stack.back()->Flush();
171179
delete stack.back();
172180
stack.pop_back();
173181
}
174182
if (stack.size() == 0 || (stack.size() < 4 && insecure_rand() % 2)) {
183+
//Add a new cache
175184
CCoinsView* tip = &base;
176185
if (stack.size() > 0) {
177186
tip = stack.back();
@@ -304,6 +313,13 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
304313
}
305314
}
306315

316+
if (insecure_rand() % 100 == 0) {
317+
// Every 100 iterations, flush an intermediate cache
318+
if (stack.size() > 1 && insecure_rand() % 2 == 0) {
319+
unsigned int flushIndex = insecure_rand() % (stack.size() - 1);
320+
stack[flushIndex]->Flush();
321+
}
322+
}
307323
if (insecure_rand() % 100 == 0) {
308324
// Every 100 iterations, change the cache stack.
309325
if (stack.size() > 0 && insecure_rand() % 2 == 0) {

0 commit comments

Comments
 (0)