This function gets the next RequestRange to work on for this RequestContext and disk combination this disk. It checks for cancellation and: a) Updates ready_to_start_ranges if there are no scan ranges queued for this disk. b) Adds an unstarted write range to in_flight_ranges_. The write range is processed immediately if there are no preceding scan ranges in in_flight_ranges_
| 603 | // b) Adds an unstarted write range to in_flight_ranges_. The write range is processed |
| 604 | // immediately if there are no preceding scan ranges in in_flight_ranges_ |
| 605 | RequestRange* RequestContext::GetNextRequestRange(int disk_id) { |
| 606 | PerDiskState* request_disk_state = &disk_states_[disk_id]; |
| 607 | // NOTE: no locks are held, so other threads could have modified the state of the reader |
| 608 | // and disk state since this context was pulled off the queue. Only one disk thread can |
| 609 | // be in this function for this reader, since the reader was removed from the queue and |
| 610 | // has not be re-added. Other disk threads may be operating on this reader in other |
| 611 | // functions though. |
| 612 | unique_lock<mutex> request_lock(lock_); |
| 613 | VLOG_FILE << "Disk (id=" << disk_id << ") reading for " << DebugString(); |
| 614 | |
| 615 | // Check if reader has been cancelled |
| 616 | if (state_ == RequestContext::Cancelled) { |
| 617 | request_disk_state->DecrementDiskThread(request_lock, this); |
| 618 | return nullptr; |
| 619 | } |
| 620 | DCHECK_EQ(state_, RequestContext::Active) << DebugString(); |
| 621 | if (request_disk_state->next_scan_range_to_start() == nullptr && |
| 622 | !request_disk_state->unstarted_scan_ranges()->empty()) { |
| 623 | // We don't have a range queued for this disk for what the caller should |
| 624 | // read next. Populate that. We want to have one range waiting to minimize |
| 625 | // wait time in GetNextUnstartedRange(). |
| 626 | ScanRange* new_range = request_disk_state->unstarted_scan_ranges()->Dequeue(); |
| 627 | num_unstarted_scan_ranges_.Add(-1); |
| 628 | ready_to_start_ranges_.Enqueue(new_range); |
| 629 | request_disk_state->set_next_scan_range_to_start(new_range); |
| 630 | |
| 631 | if (num_unstarted_scan_ranges_.Load() == 0) { |
| 632 | // All the ranges have been started, notify everyone blocked on |
| 633 | // GetNextUnstartedRange(). Only one of them will get work so make sure to return |
| 634 | // nullptr to the other caller threads. |
| 635 | ready_to_start_ranges_cv_.NotifyAll(); |
| 636 | } else { |
| 637 | ready_to_start_ranges_cv_.NotifyOne(); |
| 638 | } |
| 639 | } |
| 640 | |
| 641 | // Always enqueue a WriteRange to be processed into in_flight_ranges_. |
| 642 | // This is done so in_flight_ranges_ does not exclusively contain ScanRanges. |
| 643 | // For now, enqueuing a WriteRange on each invocation of GetNextRequestRange() |
| 644 | // does not flood in_flight_ranges() with WriteRanges because the entire |
| 645 | // WriteRange is processed and removed from the queue after GetNextRequestRange() |
| 646 | // returns. |
| 647 | if (!request_disk_state->unstarted_write_ranges()->empty()) { |
| 648 | WriteRange* write_range = request_disk_state->unstarted_write_ranges()->Dequeue(); |
| 649 | request_disk_state->in_flight_ranges()->Enqueue(write_range); |
| 650 | } |
| 651 | |
| 652 | // Do remote temporary files related work. |
| 653 | if (!request_disk_state->unstarted_remote_file_oper_ranges()->empty()) { |
| 654 | RemoteOperRange* oper_range; |
| 655 | if (!request_disk_state->unstarted_remote_file_oper_ranges()->empty()) { |
| 656 | oper_range = request_disk_state->unstarted_remote_file_oper_ranges()->Dequeue(); |
| 657 | request_disk_state->in_flight_ranges()->Enqueue(oper_range); |
| 658 | } |
| 659 | } |
| 660 | |
| 661 | // Get the next scan range to work on from the reader. Only in_flight_ranges |
| 662 | // are eligible since the disk threads do not start new ranges on their own. |
nothing calls this directly
no test coverage detected