Alter assumptions in CCoinsViewCache::BatchWrite
Previously it would break if you flushed a parent cache while there was a child cache referring to it. This change will allow the flushing of parent caches.
This commit is contained in:
parent
73fa5e6043
commit
072e2f8644
@ -160,18 +160,23 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
|
|||||||
if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
|
if (it->second.flags & CCoinsCacheEntry::DIRTY) { // Ignore non-dirty entries (optimization).
|
||||||
CCoinsMap::iterator itUs = cacheCoins.find(it->first);
|
CCoinsMap::iterator itUs = cacheCoins.find(it->first);
|
||||||
if (itUs == cacheCoins.end()) {
|
if (itUs == cacheCoins.end()) {
|
||||||
if (!it->second.coins.IsPruned()) {
|
// The parent cache does not have an entry, while the child does
|
||||||
// The parent cache does not have an entry, while the child
|
// We can ignore it if it's both FRESH and pruned in the child
|
||||||
// cache does have (a non-pruned) one. Move the data up, and
|
if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coins.IsPruned())) {
|
||||||
// mark it as fresh (if the grandparent did have it, we
|
// Otherwise we will need to create it in the parent
|
||||||
// would have pulled it in at first GetCoins).
|
// and move the data up and mark it as dirty
|
||||||
assert(it->second.flags & CCoinsCacheEntry::FRESH);
|
|
||||||
CCoinsCacheEntry& entry = cacheCoins[it->first];
|
CCoinsCacheEntry& entry = cacheCoins[it->first];
|
||||||
entry.coins.swap(it->second.coins);
|
entry.coins.swap(it->second.coins);
|
||||||
cachedCoinsUsage += entry.coins.DynamicMemoryUsage();
|
cachedCoinsUsage += entry.coins.DynamicMemoryUsage();
|
||||||
entry.flags = CCoinsCacheEntry::DIRTY | CCoinsCacheEntry::FRESH;
|
entry.flags = CCoinsCacheEntry::DIRTY;
|
||||||
|
// We can mark it FRESH in the parent if it was FRESH in the child
|
||||||
|
// Otherwise it might have just been flushed from the parent's cache
|
||||||
|
// and already exist in the grandparent
|
||||||
|
if (it->second.flags & CCoinsCacheEntry::FRESH)
|
||||||
|
entry.flags |= CCoinsCacheEntry::FRESH;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Found the entry in the parent cache
|
||||||
if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coins.IsPruned()) {
|
if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coins.IsPruned()) {
|
||||||
// The grandparent does not have an entry, and the child is
|
// The grandparent does not have an entry, and the child is
|
||||||
// modified and being pruned. This means we can just delete
|
// modified and being pruned. This means we can just delete
|
||||||
|
@ -164,14 +164,23 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (insecure_rand() % 100 == 0) {
|
||||||
|
// Every 100 iterations, flush an intermediate cache
|
||||||
|
if (stack.size() > 1 && insecure_rand() % 2 == 0) {
|
||||||
|
unsigned int flushIndex = insecure_rand() % (stack.size() - 1);
|
||||||
|
stack[flushIndex]->Flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (insecure_rand() % 100 == 0) {
|
if (insecure_rand() % 100 == 0) {
|
||||||
// Every 100 iterations, change the cache stack.
|
// Every 100 iterations, change the cache stack.
|
||||||
if (stack.size() > 0 && insecure_rand() % 2 == 0) {
|
if (stack.size() > 0 && insecure_rand() % 2 == 0) {
|
||||||
|
//Remove the top cache
|
||||||
stack.back()->Flush();
|
stack.back()->Flush();
|
||||||
delete stack.back();
|
delete stack.back();
|
||||||
stack.pop_back();
|
stack.pop_back();
|
||||||
}
|
}
|
||||||
if (stack.size() == 0 || (stack.size() < 4 && insecure_rand() % 2)) {
|
if (stack.size() == 0 || (stack.size() < 4 && insecure_rand() % 2)) {
|
||||||
|
//Add a new cache
|
||||||
CCoinsView* tip = &base;
|
CCoinsView* tip = &base;
|
||||||
if (stack.size() > 0) {
|
if (stack.size() > 0) {
|
||||||
tip = stack.back();
|
tip = stack.back();
|
||||||
@ -304,6 +313,13 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (insecure_rand() % 100 == 0) {
|
||||||
|
// Every 100 iterations, flush an intermediate cache
|
||||||
|
if (stack.size() > 1 && insecure_rand() % 2 == 0) {
|
||||||
|
unsigned int flushIndex = insecure_rand() % (stack.size() - 1);
|
||||||
|
stack[flushIndex]->Flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (insecure_rand() % 100 == 0) {
|
if (insecure_rand() % 100 == 0) {
|
||||||
// Every 100 iterations, change the cache stack.
|
// Every 100 iterations, change the cache stack.
|
||||||
if (stack.size() > 0 && insecure_rand() % 2 == 0) {
|
if (stack.size() > 0 && insecure_rand() % 2 == 0) {
|
||||||
|
Loading…
Reference in New Issue
Block a user