| 734 | } |
| 735 | |
| 736 | Status GroupingAggregator::NextPartition() { |
| 737 | DCHECK(output_partition_ == nullptr); |
| 738 | |
| 739 | if (!is_in_subplan_ && spilled_partitions_.empty()) { |
| 740 | // All partitions are in memory. Release reservation that was used for previous |
| 741 | // partitions that is no longer needed. If we have spilled partitions, we want to |
| 742 | // hold onto all reservation in case it is needed to process the spilled partitions. |
| 743 | DCHECK(!buffer_pool_client()->has_unpinned_pages()); |
| 744 | Status status = reservation_manager_.ReleaseUnusedReservation(); |
| 745 | DCHECK(status.ok()) << "Should not fail - all partitions are in memory so there are " |
| 746 | << "no unpinned pages. " << status.GetDetail(); |
| 747 | } |
| 748 | |
| 749 | // Keep looping until we get to a partition that fits in memory. |
| 750 | Partition* partition = nullptr; |
| 751 | while (true) { |
| 752 | // First return partitions that are fully aggregated (and in memory). |
| 753 | if (!aggregated_partitions_.empty()) { |
| 754 | partition = aggregated_partitions_.front(); |
| 755 | DCHECK(!partition->is_spilled()); |
| 756 | aggregated_partitions_.pop_front(); |
| 757 | break; |
| 758 | } |
| 759 | |
| 760 | // No aggregated partitions in memory - we should not be using any reservation aside |
| 761 | // from 'serialize_stream_'. |
| 762 | DCHECK_EQ(serialize_stream_ != nullptr ? serialize_stream_->BytesPinned(false) : 0, |
| 763 | buffer_pool_client()->GetUsedReservation()) |
| 764 | << buffer_pool_client()->DebugString(); |
| 765 | |
| 766 | // Try to fit a single spilled partition in memory. We can often do this because |
| 767 | // we only need to fit 1/PARTITION_FANOUT of the data in memory. |
| 768 | // TODO: in some cases when the partition probably won't fit in memory it could |
| 769 | // be better to skip directly to repartitioning. |
| 770 | RETURN_IF_ERROR(BuildSpilledPartition(&partition)); |
| 771 | if (partition != nullptr) break; |
| 772 | |
| 773 | // If we can't fit the partition in memory, repartition it. |
| 774 | RETURN_IF_ERROR(RepartitionSpilledPartition()); |
| 775 | } |
| 776 | DCHECK(!partition->is_spilled()); |
| 777 | DCHECK(partition->hash_tbl.get() != nullptr); |
| 778 | DCHECK(partition->aggregated_row_stream->is_pinned()); |
| 779 | |
| 780 | output_partition_ = partition; |
| 781 | output_iterator_ = output_partition_->hash_tbl->Begin(ht_ctx_.get()); |
| 782 | COUNTER_ADD(this->ht_stats_profile_->num_hash_buckets_, |
| 783 | output_partition_->hash_tbl->num_buckets()); |
| 784 | return Status::OK(); |
| 785 | } |
| 786 | |
| 787 | Status GroupingAggregator::BuildSpilledPartition(Partition** built_partition) { |
| 788 | DCHECK(!spilled_partitions_.empty()); |
nothing calls this directly
no test coverage detected