| 374 | } |
| 375 | |
| 376 | Status PhjBuilder::FinalizeBuild(RuntimeState* state) { |
| 377 | int64_t num_build_rows = 0; |
| 378 | for (const unique_ptr<PhjBuilderPartition>& partition : hash_partitions_) { |
| 379 | num_build_rows += partition->build_rows()->num_rows(); |
| 380 | partition->build_rows()->DoneWriting(); |
| 381 | } |
| 382 | |
| 383 | if (num_build_rows > 0) { |
| 384 | double largest_fraction = 0.0; |
| 385 | for (const unique_ptr<PhjBuilderPartition>& partition : hash_partitions_) { |
| 386 | largest_fraction = max(largest_fraction, |
| 387 | partition->build_rows()->num_rows() / static_cast<double>(num_build_rows)); |
| 388 | } |
| 389 | COUNTER_SET(largest_partition_percent_, static_cast<int64_t>(largest_fraction * 100)); |
| 390 | } |
| 391 | |
| 392 | if (VLOG_IS_ON(2)) { |
| 393 | stringstream ss; |
| 394 | ss << Substitute("PHJ(node_id=$0) partitioned(level=$1) $2 rows into:", join_node_id_, |
| 395 | hash_partitions_[0]->level(), num_build_rows); |
| 396 | for (int i = 0; i < hash_partitions_.size(); ++i) { |
| 397 | PhjBuilderPartition* partition = hash_partitions_[i].get(); |
| 398 | double percent = num_build_rows == 0 ? 0.0 : partition->build_rows()->num_rows() |
| 399 | * 100 / static_cast<double>(num_build_rows); |
| 400 | ss << " " << i << " " << (partition->is_spilled() ? "spilled" : "not spilled") |
| 401 | << " (fraction=" << fixed << setprecision(2) << percent << "%)" << endl |
| 402 | << " #rows:" << partition->build_rows()->num_rows() << endl; |
| 403 | } |
| 404 | if (null_aware_partition_ != nullptr) { |
| 405 | ss << " Null-aware partition: " << null_aware_partition_->DebugString(); |
| 406 | } |
| 407 | VLOG(2) << ss.str(); |
| 408 | } |
| 409 | |
| 410 | if (ht_ctx_->level() == 0) { |
| 411 | PublishRuntimeFilters(num_build_rows); |
| 412 | non_empty_build_ |= (num_build_rows > 0); |
| 413 | |
| 414 | if (join_op_ == TJoinOp::NULL_AWARE_LEFT_ANTI_JOIN) { |
| 415 | if (null_aware_partition_->is_spilled()) { |
| 416 | // Free up memory for the hash tables of other partitions by unpinning the |
| 417 | // last block of the null aware partition's stream. |
| 418 | RETURN_IF_ERROR(null_aware_partition_->Spill(BufferedTupleStream::UNPIN_ALL)); |
| 419 | } else { |
| 420 | // Invalidate the write iterator so we can safely do concurrent reads later. |
| 421 | null_aware_partition_->build_rows()->DoneWriting(); |
| 422 | } |
| 423 | } |
| 424 | } |
| 425 | |
| 426 | HashJoinState next_state; |
| 427 | if (state_ == HashJoinState::PARTITIONING_BUILD) { |
| 428 | next_state = HashJoinState::PARTITIONING_PROBE; |
| 429 | } else { |
| 430 | DCHECK_ENUM_EQ(state_, HashJoinState::REPARTITIONING_BUILD); |
| 431 | next_state = HashJoinState::REPARTITIONING_PROBE; |
| 432 | } |
| 433 | RETURN_IF_ERROR(BuildHashTablesAndReserveProbeBuffers(next_state)); |
nothing calls this directly
no test coverage detected