mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-06-09 14:41:42 +02:00
refactor: encapsulate flags access for dirty and fresh checks
No behavior change. This prepares moving the cache entry flags field to private access. Co-Authored-By: l0rinc <pap.lorinc@gmail.com>
This commit is contained in:
parent
9774a958b5
commit
df34a94e57
@ -93,7 +93,7 @@ void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possi
|
|||||||
//
|
//
|
||||||
// If the coin doesn't exist in the current cache, or is spent but not
|
// If the coin doesn't exist in the current cache, or is spent but not
|
||||||
// DIRTY, then it can be marked FRESH.
|
// DIRTY, then it can be marked FRESH.
|
||||||
fresh = !(it->second.flags & CCoinsCacheEntry::DIRTY);
|
fresh = !it->second.IsDirty();
|
||||||
}
|
}
|
||||||
it->second.coin = std::move(coin);
|
it->second.coin = std::move(coin);
|
||||||
it->second.flags |= CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0);
|
it->second.flags |= CCoinsCacheEntry::DIRTY | (fresh ? CCoinsCacheEntry::FRESH : 0);
|
||||||
@ -138,7 +138,7 @@ bool CCoinsViewCache::SpendCoin(const COutPoint &outpoint, Coin* moveout) {
|
|||||||
if (moveout) {
|
if (moveout) {
|
||||||
*moveout = std::move(it->second.coin);
|
*moveout = std::move(it->second.coin);
|
||||||
}
|
}
|
||||||
if (it->second.flags & CCoinsCacheEntry::FRESH) {
|
if (it->second.IsFresh()) {
|
||||||
cacheCoins.erase(it);
|
cacheCoins.erase(it);
|
||||||
} else {
|
} else {
|
||||||
it->second.flags |= CCoinsCacheEntry::DIRTY;
|
it->second.flags |= CCoinsCacheEntry::DIRTY;
|
||||||
@ -183,14 +183,14 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
|
|||||||
it != mapCoins.end();
|
it != mapCoins.end();
|
||||||
it = erase ? mapCoins.erase(it) : std::next(it)) {
|
it = erase ? mapCoins.erase(it) : std::next(it)) {
|
||||||
// Ignore non-dirty entries (optimization).
|
// Ignore non-dirty entries (optimization).
|
||||||
if (!(it->second.flags & CCoinsCacheEntry::DIRTY)) {
|
if (!it->second.IsDirty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
CCoinsMap::iterator itUs = cacheCoins.find(it->first);
|
CCoinsMap::iterator itUs = cacheCoins.find(it->first);
|
||||||
if (itUs == cacheCoins.end()) {
|
if (itUs == cacheCoins.end()) {
|
||||||
// The parent cache does not have an entry, while the child cache does.
|
// The parent cache does not have an entry, while the child cache does.
|
||||||
// We can ignore it if it's both spent and FRESH in the child
|
// We can ignore it if it's both spent and FRESH in the child
|
||||||
if (!(it->second.flags & CCoinsCacheEntry::FRESH && it->second.coin.IsSpent())) {
|
if (!(it->second.IsFresh() && it->second.coin.IsSpent())) {
|
||||||
// Create the coin in the parent cache, move the data up
|
// Create the coin in the parent cache, move the data up
|
||||||
// and mark it as dirty.
|
// and mark it as dirty.
|
||||||
CCoinsCacheEntry& entry = cacheCoins[it->first];
|
CCoinsCacheEntry& entry = cacheCoins[it->first];
|
||||||
@ -207,13 +207,13 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
|
|||||||
// We can mark it FRESH in the parent if it was FRESH in the child
|
// 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
|
// Otherwise it might have just been flushed from the parent's cache
|
||||||
// and already exist in the grandparent
|
// and already exist in the grandparent
|
||||||
if (it->second.flags & CCoinsCacheEntry::FRESH) {
|
if (it->second.IsFresh()) {
|
||||||
entry.flags |= CCoinsCacheEntry::FRESH;
|
entry.flags |= CCoinsCacheEntry::FRESH;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Found the entry in the parent cache
|
// Found the entry in the parent cache
|
||||||
if ((it->second.flags & CCoinsCacheEntry::FRESH) && !itUs->second.coin.IsSpent()) {
|
if (it->second.IsFresh() && !itUs->second.coin.IsSpent()) {
|
||||||
// The coin was marked FRESH in the child cache, but the coin
|
// The coin was marked FRESH in the child cache, but the coin
|
||||||
// exists in the parent cache. If this ever happens, it means
|
// exists in the parent cache. If this ever happens, it means
|
||||||
// the FRESH flag was misapplied and there is a logic error in
|
// the FRESH flag was misapplied and there is a logic error in
|
||||||
@ -221,7 +221,7 @@ bool CCoinsViewCache::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlockIn
|
|||||||
throw std::logic_error("FRESH flag misapplied to coin that exists in parent cache");
|
throw std::logic_error("FRESH flag misapplied to coin that exists in parent cache");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((itUs->second.flags & CCoinsCacheEntry::FRESH) && it->second.coin.IsSpent()) {
|
if (itUs->second.IsFresh() && it->second.coin.IsSpent()) {
|
||||||
// The grandparent cache does not have an entry, and the coin
|
// The grandparent cache does not have an entry, and the coin
|
||||||
// has been spent. We can just delete it from the parent cache.
|
// has been spent. We can just delete it from the parent cache.
|
||||||
cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
|
cachedCoinsUsage -= itUs->second.coin.DynamicMemoryUsage();
|
||||||
@ -283,7 +283,7 @@ bool CCoinsViewCache::Sync()
|
|||||||
void CCoinsViewCache::Uncache(const COutPoint& hash)
|
void CCoinsViewCache::Uncache(const COutPoint& hash)
|
||||||
{
|
{
|
||||||
CCoinsMap::iterator it = cacheCoins.find(hash);
|
CCoinsMap::iterator it = cacheCoins.find(hash);
|
||||||
if (it != cacheCoins.end() && it->second.flags == 0) {
|
if (it != cacheCoins.end() && !it->second.IsDirty() && !it->second.IsFresh()) {
|
||||||
cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
|
cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
|
||||||
TRACE5(utxocache, uncache,
|
TRACE5(utxocache, uncache,
|
||||||
hash.hash.data(),
|
hash.hash.data(),
|
||||||
@ -326,8 +326,8 @@ void CCoinsViewCache::SanityCheck() const
|
|||||||
size_t recomputed_usage = 0;
|
size_t recomputed_usage = 0;
|
||||||
for (const auto& [_, entry] : cacheCoins) {
|
for (const auto& [_, entry] : cacheCoins) {
|
||||||
unsigned attr = 0;
|
unsigned attr = 0;
|
||||||
if (entry.flags & CCoinsCacheEntry::DIRTY) attr |= 1;
|
if (entry.IsDirty()) attr |= 1;
|
||||||
if (entry.flags & CCoinsCacheEntry::FRESH) attr |= 2;
|
if (entry.IsFresh()) attr |= 2;
|
||||||
if (entry.coin.IsSpent()) attr |= 4;
|
if (entry.coin.IsSpent()) attr |= 4;
|
||||||
// Only 5 combinations are possible.
|
// Only 5 combinations are possible.
|
||||||
assert(attr != 2 && attr != 4 && attr != 7);
|
assert(attr != 2 && attr != 4 && attr != 7);
|
||||||
|
@ -130,6 +130,9 @@ struct CCoinsCacheEntry
|
|||||||
CCoinsCacheEntry() : flags(0) {}
|
CCoinsCacheEntry() : flags(0) {}
|
||||||
explicit CCoinsCacheEntry(Coin&& coin_) : coin(std::move(coin_)), flags(0) {}
|
explicit CCoinsCacheEntry(Coin&& coin_) : coin(std::move(coin_)), flags(0) {}
|
||||||
CCoinsCacheEntry(Coin&& coin_, unsigned char flag) : coin(std::move(coin_)), flags(flag) {}
|
CCoinsCacheEntry(Coin&& coin_, unsigned char flag) : coin(std::move(coin_)), flags(flag) {}
|
||||||
|
|
||||||
|
inline bool IsDirty() const noexcept { return flags & DIRTY; }
|
||||||
|
inline bool IsFresh() const noexcept { return flags & FRESH; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -58,7 +58,7 @@ public:
|
|||||||
bool BatchWrite(CCoinsMap& mapCoins, const uint256& hashBlock, bool erase = true) override
|
bool BatchWrite(CCoinsMap& mapCoins, const uint256& hashBlock, bool erase = true) override
|
||||||
{
|
{
|
||||||
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); it = erase ? mapCoins.erase(it) : std::next(it)) {
|
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); it = erase ? mapCoins.erase(it) : std::next(it)) {
|
||||||
if (it->second.flags & CCoinsCacheEntry::DIRTY) {
|
if (it->second.IsDirty()) {
|
||||||
// Same optimization used in CCoinsViewDB is to only write dirty entries.
|
// Same optimization used in CCoinsViewDB is to only write dirty entries.
|
||||||
map_[it->first] = it->second.coin;
|
map_[it->first] = it->second.coin;
|
||||||
if (it->second.coin.IsSpent() && InsecureRandRange(3) == 0) {
|
if (it->second.coin.IsSpent() && InsecureRandRange(3) == 0) {
|
||||||
|
@ -175,7 +175,7 @@ public:
|
|||||||
bool BatchWrite(CCoinsMap& data, const uint256&, bool erase) final
|
bool BatchWrite(CCoinsMap& data, const uint256&, bool erase) final
|
||||||
{
|
{
|
||||||
for (auto it = data.begin(); it != data.end(); it = erase ? data.erase(it) : std::next(it)) {
|
for (auto it = data.begin(); it != data.end(); it = erase ? data.erase(it) : std::next(it)) {
|
||||||
if (it->second.flags & CCoinsCacheEntry::DIRTY) {
|
if (it->second.IsDirty()) {
|
||||||
if (it->second.coin.IsSpent() && (it->first.n % 5) != 4) {
|
if (it->second.coin.IsSpent() && (it->first.n % 5) != 4) {
|
||||||
m_data.erase(it->first);
|
m_data.erase(it->first);
|
||||||
} else if (erase) {
|
} else if (erase) {
|
||||||
|
@ -115,7 +115,7 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, boo
|
|||||||
batch.Write(DB_HEAD_BLOCKS, Vector(hashBlock, old_tip));
|
batch.Write(DB_HEAD_BLOCKS, Vector(hashBlock, old_tip));
|
||||||
|
|
||||||
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
|
for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
|
||||||
if (it->second.flags & CCoinsCacheEntry::DIRTY) {
|
if (it->second.IsDirty()) {
|
||||||
CoinEntry entry(&it->first);
|
CoinEntry entry(&it->first);
|
||||||
if (it->second.coin.IsSpent())
|
if (it->second.coin.IsSpent())
|
||||||
batch.Erase(entry);
|
batch.Erase(entry);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user