| 82 | } |
| 83 | |
| 84 | bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) { |
| 85 | CDBBatch batch(db); |
| 86 | size_t count = 0; |
| 87 | size_t changed = 0; |
| 88 | size_t batch_size = (size_t)gArgs.GetArg("-dbbatchsize", nDefaultDbBatchSize); |
| 89 | int crash_simulate = gArgs.GetArg("-dbcrashratio", 0); |
| 90 | assert(!hashBlock.IsNull()); |
| 91 | |
| 92 | uint256 old_tip = GetBestBlock(); |
| 93 | if (old_tip.IsNull()) { |
| 94 | // We may be in the middle of replaying. |
| 95 | std::vector<uint256> old_heads = GetHeadBlocks(); |
| 96 | if (old_heads.size() == 2) { |
| 97 | assert(old_heads[0] == hashBlock); |
| 98 | old_tip = old_heads[1]; |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | // In the first batch, mark the database as being in the middle of a |
| 103 | // transition from old_tip to hashBlock. |
| 104 | // A vector is used for future extensibility, as we may want to support |
| 105 | // interrupting after partial writes from multiple independent reorgs. |
| 106 | batch.Erase(DB_BEST_BLOCK); |
| 107 | batch.Write(DB_HEAD_BLOCKS, std::vector<uint256>{hashBlock, old_tip}); |
| 108 | |
| 109 | for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) { |
| 110 | if (it->second.flags & CCoinsCacheEntry::DIRTY) { |
| 111 | CoinEntry entry(&it->first); |
| 112 | if (it->second.coin.IsSpent()) |
| 113 | batch.Erase(entry); |
| 114 | else |
| 115 | batch.Write(entry, it->second.coin); |
| 116 | changed++; |
| 117 | } |
| 118 | count++; |
| 119 | CCoinsMap::iterator itOld = it++; |
| 120 | mapCoins.erase(itOld); |
| 121 | if (batch.SizeEstimate() > batch_size) { |
| 122 | LogPrint(BCLog::COINDB, "Writing partial batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0)); |
| 123 | db.WriteBatch(batch); |
| 124 | batch.Clear(); |
| 125 | if (crash_simulate) { |
| 126 | static FastRandomContext rng; |
| 127 | if (rng.randrange(crash_simulate) == 0) { |
| 128 | LogPrintf("Simulating a crash. Goodbye.\n"); |
| 129 | _Exit(0); |
| 130 | } |
| 131 | } |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | // In the last batch, mark the database as consistent with hashBlock again. |
| 136 | batch.Erase(DB_HEAD_BLOCKS); |
| 137 | batch.Write(DB_BEST_BLOCK, hashBlock); |
| 138 | |
| 139 | LogPrint(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0)); |
| 140 | bool ret = db.WriteBatch(batch); |
| 141 | LogPrint(BCLog::COINDB, "Committed %u changed transaction outputs (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count); |
nothing calls this directly
no test coverage detected