| 503 | |
| 504 | template <bool CONVERT_OFFSET_TO_PTR> |
| 505 | Status Sorter::Run::GetNext(RowBatch* output_batch, bool* eos) { |
| 506 | // Var-len offsets are converted only when reading var-len data from unpinned runs. |
| 507 | // We shouldn't convert var len offsets if there are no pages, since in that case |
| 508 | // they must all be null or zero-length strings, which don't point into a valid page. |
| 509 | DCHECK_EQ(CONVERT_OFFSET_TO_PTR, HasVarLenPages() && !is_pinned_); |
| 510 | |
| 511 | if (end_of_fixed_len_page_ |
| 512 | && fixed_len_pages_index_ >= static_cast<int>(fixed_len_pages_.size()) - 1) { |
| 513 | // All pages were previously attached to output batches. GetNextBatch() assumes |
| 514 | // that we don't attach resources to the batch on eos. |
| 515 | DCHECK_EQ(NumOpenPages(fixed_len_pages_), 0); |
| 516 | DCHECK_EQ(NumOpenPages(var_len_pages_), 0); |
| 517 | |
| 518 | CloseAllPages(); |
| 519 | *eos = true; |
| 520 | DCHECK_EQ(num_tuples_returned_, num_tuples_); |
| 521 | return Status::OK(); |
| 522 | } |
| 523 | |
| 524 | // Advance the fixed or var len page if we reached the end in the previous call to |
| 525 | // GetNext(). |
| 526 | if (end_of_fixed_len_page_) { |
| 527 | RETURN_IF_ERROR(PinNextReadPage(&fixed_len_pages_, fixed_len_pages_index_)); |
| 528 | ++fixed_len_pages_index_; |
| 529 | fixed_len_page_offset_ = 0; |
| 530 | end_of_fixed_len_page_ = false; |
| 531 | } |
| 532 | if (end_of_var_len_page_) { |
| 533 | RETURN_IF_ERROR(PinNextReadPage(&var_len_pages_, var_len_pages_index_)); |
| 534 | ++var_len_pages_index_; |
| 535 | end_of_var_len_page_ = false; |
| 536 | } |
| 537 | |
| 538 | // Fills rows into the output batch until a page boundary is reached. |
| 539 | Page* fixed_len_page = &fixed_len_pages_[fixed_len_pages_index_]; |
| 540 | DCHECK(fixed_len_page != nullptr); |
| 541 | |
| 542 | // Ensure we have a reference to the fixed-length page's buffer. |
| 543 | RETURN_IF_ERROR(fixed_len_page->WaitForBuffer()); |
| 544 | |
| 545 | // If we're converting offsets into unpinned var-len pages, make sure the |
| 546 | // current var-len page is in memory. |
| 547 | if (CONVERT_OFFSET_TO_PTR && HasVarLenPages()) { |
| 548 | RETURN_IF_ERROR(var_len_pages_[var_len_pages_index_].WaitForBuffer()); |
| 549 | } |
| 550 | |
| 551 | while (!output_batch->AtCapacity() |
| 552 | && fixed_len_page_offset_ < fixed_len_page->valid_data_len()) { |
| 553 | DCHECK(fixed_len_page != nullptr); |
| 554 | Tuple* input_tuple = |
| 555 | reinterpret_cast<Tuple*>(fixed_len_page->data() + fixed_len_page_offset_); |
| 556 | |
| 557 | if (CONVERT_OFFSET_TO_PTR && !ConvertOffsetsToPtrs(input_tuple, *sort_tuple_desc_)) { |
| 558 | DCHECK(!is_pinned_); |
| 559 | // The var-len data is in the next page. We are done with the current page, so |
| 560 | // return rows we've accumulated so far along with the page's buffer and advance |
| 561 | // to the next page in the next GetNext() call. We need the page's reservation to |
| 562 | // pin the next page, so flush resources. |