| 161 | } |
| 162 | |
| 163 | Status BufferedPlanRootSink::GetNext(RuntimeState* state, QueryResultSet* results, |
| 164 | int num_results, bool* eos, int64_t timeout_us) { |
| 165 | { |
| 166 | // Used to track how long the consumer waits for RowBatches to be produced and |
| 167 | // materialized. |
| 168 | DCHECK_GE(timeout_us, 0); |
| 169 | MonotonicStopWatch wait_timeout_timer; |
| 170 | wait_timeout_timer.Start(); |
| 171 | |
| 172 | unique_lock<mutex> l(lock_); |
| 173 | *eos = false; |
| 174 | |
| 175 | // Cap the maximum number of results fetched by this call to GetNext so that the |
| 176 | // resulting QueryResultSet does not consume excessive amounts of memory. |
| 177 | num_results = min(num_results, MAX_FETCH_SIZE); |
| 178 | |
| 179 | // Track the number of rows read from the queue and the number of rows to read. |
| 180 | int num_rows_read = 0; |
| 181 | // If 'num_results' <= 0 then by default fetch FETCH_NUM_BATCHES batches. |
| 182 | const int num_rows_to_read = |
| 183 | num_results <= 0 ? FETCH_NUM_BATCHES * state->batch_size() : num_results; |
| 184 | |
| 185 | // True if the consumer timed out waiting for the producer to send rows or if the |
| 186 | // consumer timed out while materializing rows, false otherwise. |
| 187 | bool timed_out = false; |
| 188 | |
| 189 | // Read from the queue until the query is cancelled or the sink is closed, eos is |
| 190 | // hit, all requested rows have been read, or the timeout has been hit. |
| 191 | while (!IsCancelledOrClosed(state) && !*eos && num_rows_read < num_rows_to_read |
| 192 | && !timed_out) { |
| 193 | // Wait for the queue to have rows in it. |
| 194 | while (!IsCancelledOrClosed(state) && IsQueueEmpty(state) |
| 195 | && sender_state_ == SenderState::ROWS_PENDING && !timed_out) { |
| 196 | if (timeout_us == 0) { |
| 197 | rows_available_.Wait(l); |
| 198 | } else { |
| 199 | // Wait fetch_rows_timeout_us_ - row_batches_get_wait_timer_ microseconds for |
| 200 | // rows to become available before returning to the client. Subtracting |
| 201 | // wait_timeout_timer ensures the client only ever waits up to |
| 202 | // fetch_rows_timeout_us_ microseconds before returning. |
| 203 | int64_t wait_duration_us = max(static_cast<int64_t>(1), |
| 204 | timeout_us - static_cast<int64_t>(round( |
| 205 | wait_timeout_timer.ElapsedTime() / NANOS_PER_MICRO))); |
| 206 | SCOPED_TIMER(row_batches_get_wait_timer_); |
| 207 | timed_out = !rows_available_.WaitFor(l, wait_duration_us); |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | // If the query was cancelled while the sink was waiting for rows to become |
| 212 | // available, or if the query was cancelled before the current call to GetNext, set |
| 213 | // eos and then return. The queue could be empty if the sink was closed while |
| 214 | // waiting for rows to become available, or if the sink was closed before the |
| 215 | // current call to GetNext. |
| 216 | if (!IsCancelledOrClosed(state) && !IsQueueEmpty(state)) { |
| 217 | // If current_batch_ is empty, then read directly from the queue. |
| 218 | if (current_batch_row_ == 0) { |
| 219 | // Debug action before GetBatch is called. |
| 220 | RETURN_IF_ERROR(DebugAction(state->query_options(), "BPRS_BEFORE_GET_BATCH")); |
nothing calls this directly
no test coverage detected