| 112 | } |
| 113 | |
| 114 | Status BlockingPlanRootSink::GetNext(RuntimeState* state, QueryResultSet* results, |
| 115 | int num_results, bool* eos, int64_t timeout_us) { |
| 116 | // Used to track how long the consumer waits for RowBatches to be produced and |
| 117 | // materialized. |
| 118 | DCHECK_GE(timeout_us, 0); |
| 119 | MonotonicStopWatch wait_timeout_timer; |
| 120 | wait_timeout_timer.Start(); |
| 121 | |
| 122 | unique_lock<mutex> l(lock_); |
| 123 | |
| 124 | // Set the shared QueryResultSet pointer 'results_' to the given 'results' object and |
| 125 | // wake up the sender thread so it can add rows to 'results_'. |
| 126 | results_ = results; |
| 127 | num_rows_requested_ = num_results; |
| 128 | sender_cv_.NotifyAll(); |
| 129 | |
| 130 | // True if the consumer timed out waiting for the producer to send rows, false |
| 131 | // otherwise. |
| 132 | bool timed_out = false; |
| 133 | |
| 134 | // Wait while the sender is still producing rows and hasn't filled in the current |
| 135 | // result set. |
| 136 | while (sender_state_ == SenderState::ROWS_PENDING && results_ != nullptr |
| 137 | && !state->is_cancelled() && !timed_out) { |
| 138 | if (timeout_us == 0) { |
| 139 | consumer_cv_.Wait(l); |
| 140 | } else { |
| 141 | // It is possible for the timeout to expire, and for the QueryResultSet to still |
| 142 | // have some rows appended to it. This can happen if the producer acquires the lock, |
| 143 | // the timeout expires, and then the producer appends rows to the QueryResultSet. |
| 144 | // This does not affect correctness because the producer always sets 'results_' to |
| 145 | // nullptr if it appends any rows to the QueryResultSet and it always appends either |
| 146 | // an entire RowBatch, or as many rows as requested. |
| 147 | int64_t wait_duration_us = max(static_cast<int64_t>(1), |
| 148 | timeout_us - static_cast<int64_t>( |
| 149 | round(wait_timeout_timer.ElapsedTime() / NANOS_PER_MICRO))); |
| 150 | if (!consumer_cv_.WaitFor(l, wait_duration_us)) { |
| 151 | VLOG_QUERY << "Fetch timed out"; |
| 152 | timed_out = true; |
| 153 | |
| 154 | // If the consumer timed out, make sure results_ is set to nullptr because the |
| 155 | // consumer will destroy the current QueryResultSet and create a new one for the |
| 156 | // next fetch request. |
| 157 | results_ = nullptr; |
| 158 | } |
| 159 | } |
| 160 | } |
| 161 | |
| 162 | *eos = sender_state_ == SenderState::EOS; |
| 163 | return state->GetQueryStatus(); |
| 164 | } |
| 165 | } |
nothing calls this directly
no test coverage detected