| 173 | /// @return The number of records deleted. |
| 174 | template <bool ParentDeleted, int MaxSplitPly = 4> |
| 175 | void recursiveDeleteChildren(DBStorage &storage, |
| 176 | Board &board, |
| 177 | Rule rule, |
| 178 | const std::function<DBClient::DelType(DBRecord &)> &deleteFilter, |
| 179 | int threadId, |
| 180 | int ply) |
| 181 | { |
| 182 | if (board.movesLeft() == 0) |
| 183 | return; |
| 184 | |
| 185 | static std::set<DBKey> deletingKeys[MaxSplitPly]; |
| 186 | static std::set<DBKey> checkingKeys; |
| 187 | static std::mutex mutex[MaxSplitPly + 1]; |
| 188 | |
| 189 | DBKey thisKey; |
| 190 | if constexpr (ParentDeleted) |
| 191 | thisKey = constructDBKey(board, rule); |
| 192 | |
| 193 | // Find all potential children of this board position |
| 194 | std::vector<Pos> toDeletePos; |
| 195 | toDeletePos.reserve(board.movesLeft()); |
| 196 | FOR_EVERY_EMPTY_POS(&board, pos) |
| 197 | { |
| 198 | toDeletePos.push_back(pos); |
| 199 | } |
| 200 | |
| 201 | // Do permutation based on thread id |
| 202 | if (threadId > 0) { |
| 203 | for (size_t i = 0; i < toDeletePos.size(); i += (threadId + 1) / 2) { |
| 204 | size_t swapIndex = (i * (threadId + 1)) % toDeletePos.size(); |
| 205 | std::swap(toDeletePos[i], toDeletePos[swapIndex]); |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | // Delete all children |
| 210 | DBKey key; |
| 211 | DBRecord record; |
| 212 | for (auto pos : toDeletePos) { |
| 213 | board.move(rule, pos); |
| 214 | |
| 215 | key = constructDBKey(board, rule); |
| 216 | |
| 217 | if (storage.get(key, record, deleteFilter ? RECORD_MASK_LVDB : RECORD_MASK_NONE)) { |
| 218 | switch (deleteFilter ? deleteFilter(record) : DBClient::DelType::DeleteRecursive) { |
| 219 | default: break; |
| 220 | case Database::DBClient::DelType::NoDeleteRecursive: { |
| 221 | bool recursiveCheck = true; |
| 222 | if (ply == MaxSplitPly) { |
| 223 | std::lock_guard lock(mutex[ply]); |
| 224 | if (checkingKeys.find(key) != checkingKeys.end()) |
| 225 | recursiveCheck = false; |
| 226 | } |
| 227 | |
| 228 | if (recursiveCheck) { |
| 229 | std::pair<std::set<DBKey>::iterator, bool> insertedResult; |
| 230 | if (ply == MaxSplitPly) { |
| 231 | std::lock_guard lock(mutex[ply]); |
| 232 | insertedResult = checkingKeys.insert(key); |
nothing calls this directly
no test coverage detected