| 373 | } |
| 374 | |
| 375 | Status Sorter::Run::UnpinAllPages() { |
| 376 | DCHECK(is_sorted_); |
| 377 | DCHECK(initial_run_); |
| 378 | DCHECK(is_pinned_); |
| 379 | DCHECK(is_finalized_); |
| 380 | // A list of var len pages to replace 'var_len_pages_'. Note that after we are done |
| 381 | // we may have a different number of pages, because internal fragmentation may leave |
| 382 | // slightly different amounts of wasted space at the end of each page. |
| 383 | // We need to be careful to clean up these pages if we run into an error in this method. |
| 384 | vector<Page> sorted_var_len_pages; |
| 385 | sorted_var_len_pages.reserve(var_len_pages_.size()); |
| 386 | |
| 387 | vector<StringValue*> string_values; |
| 388 | vector<pair<CollectionValue*, int64_t>> collection_values_and_sizes; |
| 389 | int total_var_len; |
| 390 | string_values.reserve(sort_tuple_desc_->string_slots().size()); |
| 391 | collection_values_and_sizes.reserve(sort_tuple_desc_->collection_slots().size()); |
| 392 | Page* cur_sorted_var_len_page = nullptr; |
| 393 | if (HasVarLenPages()) { |
| 394 | DCHECK(var_len_copy_page_.is_open()); |
| 395 | sorted_var_len_pages.push_back(move(var_len_copy_page_)); |
| 396 | cur_sorted_var_len_page = &sorted_var_len_pages.back(); |
| 397 | } else if (has_var_len_slots_) { |
| 398 | // If we don't have any var-len pages, clean up the copy page. |
| 399 | DCHECK(var_len_copy_page_.is_open()); |
| 400 | var_len_copy_page_.Close(sorter_->buffer_pool_client_); |
| 401 | } else { |
| 402 | DCHECK(!var_len_copy_page_.is_open()); |
| 403 | } |
| 404 | |
| 405 | Status status; |
| 406 | for (auto& fixed_len_page : fixed_len_pages_) { |
| 407 | Page* cur_fixed_page = &fixed_len_page; |
| 408 | // Skip converting the pointers if no var-len slots, or if all the values are null |
| 409 | // or zero-length. This will possibly leave zero-length pointers pointing to |
| 410 | // arbitrary memory, but zero-length data cannot be dereferenced anyway. |
| 411 | if (HasVarLenPages()) { |
| 412 | for (int page_offset = 0; page_offset < cur_fixed_page->valid_data_len(); |
| 413 | page_offset += sort_tuple_size_) { |
| 414 | Tuple* cur_tuple = reinterpret_cast<Tuple*>(cur_fixed_page->data() + page_offset); |
| 415 | CollectNonNullNonSmallVarSlots(cur_tuple, *sort_tuple_desc_, &string_values, |
| 416 | &collection_values_and_sizes, &total_var_len); |
| 417 | DCHECK(cur_sorted_var_len_page->is_open()); |
| 418 | if (cur_sorted_var_len_page->BytesRemaining() < total_var_len) { |
| 419 | bool added; |
| 420 | status = TryAddPage(UNPIN_PREV, &sorted_var_len_pages, &added); |
| 421 | if (!status.ok()) goto cleanup_pages; |
| 422 | DCHECK(added) << "TryAddPage() with UNPIN_PREV should not fail to add"; |
| 423 | cur_sorted_var_len_page = &sorted_var_len_pages.back(); |
| 424 | } |
| 425 | uint8_t* var_data_ptr = cur_sorted_var_len_page->AllocateBytes(total_var_len); |
| 426 | DCHECK_EQ(&sorted_var_len_pages.back(), cur_sorted_var_len_page); |
| 427 | CopyVarLenDataConvertOffset(string_values, collection_values_and_sizes, |
| 428 | sorted_var_len_pages.size() - 1, cur_sorted_var_len_page->data(), |
| 429 | var_data_ptr); |
| 430 | } |
| 431 | } |
| 432 | cur_fixed_page->Unpin(sorter_->buffer_pool_client_); |
no test coverage detected