| 234 | } |
| 235 | |
| 236 | ConcurrentHashJoin::~ConcurrentHashJoin() |
| 237 | { |
| 238 | try |
| 239 | { |
| 240 | if (!build_phase_finished || !hash_joins[0]->data->twoLevelMapIsUsed()) |
| 241 | return; |
| 242 | |
| 243 | updateStatistics(hash_joins, stats_collecting_params); |
| 244 | |
| 245 | for (size_t i = 0; i < slots; ++i) |
| 246 | { |
| 247 | // Hash tables destruction may be very time-consuming. |
| 248 | // Without the following code, they would be destroyed in the current thread (i.e. sequentially). |
| 249 | pool->scheduleOrThrow( |
| 250 | [join = hash_joins[0], i, this, thread_group = CurrentThread::getGroup()]() |
| 251 | { |
| 252 | ThreadGroupSwitcher switcher(thread_group, ThreadName::CONCURRENT_JOIN); |
| 253 | |
| 254 | auto clear_space_in_buckets = [&](auto & maps, HashJoin::Type type, size_t idx) |
| 255 | { |
| 256 | APPLY_TO_MAP( |
| 257 | INVOKE_WITH_MAP, |
| 258 | type, |
| 259 | maps, |
| 260 | [&](auto & map) |
| 261 | { |
| 262 | for (size_t j = idx; j < map.NUM_BUCKETS; j += slots) |
| 263 | map.impls[j].clearAndShrink(); |
| 264 | }) |
| 265 | }; |
| 266 | const auto & right_data = getData(join); |
| 267 | std::visit([&](auto & maps) { return clear_space_in_buckets(maps, right_data->type, i); }, right_data->maps.at(0)); |
| 268 | }); |
| 269 | } |
| 270 | pool->wait(); |
| 271 | } |
| 272 | catch (...) |
| 273 | { |
| 274 | tryLogCurrentException(__PRETTY_FUNCTION__); |
| 275 | pool->wait(); |
| 276 | } |
| 277 | } |
| 278 | |
| 279 | bool ConcurrentHashJoin::addBlockToJoin(const Block & right_block_, bool check_limits) |
| 280 | { |
nothing calls this directly
no test coverage detected