| 120 | } |
| 121 | |
| 122 | void CCoinsViewDB::BatchWrite(CoinsViewCacheCursor& cursor, const uint256& block_hash) |
| 123 | { |
| 124 | CDBBatch batch(*m_db); |
| 125 | size_t count = 0; |
| 126 | const size_t dirty_count{cursor.GetDirtyCount()}; |
| 127 | assert(!block_hash.IsNull()); |
| 128 | |
| 129 | uint256 old_tip = GetBestBlock(); |
| 130 | if (old_tip.IsNull()) { |
| 131 | // We may be in the middle of replaying. |
| 132 | std::vector<uint256> old_heads = GetHeadBlocks(); |
| 133 | if (old_heads.size() == 2) { |
| 134 | if (old_heads[0] != block_hash) { |
| 135 | LogError("The coins database detected an inconsistent state, likely due to a previous crash or shutdown. You will need to restart bitcoind with the -reindex-chainstate or -reindex configuration option.\n"); |
| 136 | } |
| 137 | assert(old_heads[0] == block_hash); |
| 138 | old_tip = old_heads[1]; |
| 139 | } |
| 140 | } |
| 141 | |
| 142 | if (dirty_count > WARN_FLUSH_COINS_COUNT) LogWarning("Flushing large (%d entries) UTXO set to disk, it may take several minutes", dirty_count); |
| 143 | LOG_TIME_MILLIS_WITH_CATEGORY(strprintf("write coins cache to disk (%d out of %d cached coins)", |
| 144 | dirty_count, cursor.GetTotalCount()), BCLog::BENCH); |
| 145 | |
| 146 | // In the first batch, mark the database as being in the middle of a |
| 147 | // transition from old_tip to block_hash. |
| 148 | // A vector is used for future extensibility, as we may want to support |
| 149 | // interrupting after partial writes from multiple independent reorgs. |
| 150 | batch.Erase(DB_BEST_BLOCK); |
| 151 | batch.Write(DB_HEAD_BLOCKS, Vector(block_hash, old_tip)); |
| 152 | |
| 153 | for (auto it{cursor.Begin()}; it != cursor.End();) { |
| 154 | if (it->second.IsDirty()) { |
| 155 | CoinEntry entry(&it->first); |
| 156 | if (it->second.coin.IsSpent()) { |
| 157 | batch.Erase(entry); |
| 158 | } else { |
| 159 | batch.Write(entry, it->second.coin); |
| 160 | } |
| 161 | } |
| 162 | count++; |
| 163 | it = cursor.NextAndMaybeErase(*it); |
| 164 | if (batch.ApproximateSize() > m_options.batch_write_bytes) { |
| 165 | LogDebug(BCLog::COINDB, "Writing partial batch of %.2f MiB\n", batch.ApproximateSize() / double(1_MiB)); |
| 166 | |
| 167 | m_db->WriteBatch(batch); |
| 168 | batch.Clear(); |
| 169 | if (m_options.simulate_crash_ratio) { |
| 170 | static FastRandomContext rng; |
| 171 | if (rng.randrange(m_options.simulate_crash_ratio) == 0) { |
| 172 | LogError("Simulating a crash. Goodbye."); |
| 173 | _Exit(0); |
| 174 | } |
| 175 | } |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | // In the last batch, mark the database as consistent with block_hash again. |
nothing calls this directly
no test coverage detected