| 661 | } |
| 662 | |
| 663 | Status BufferPool::Client::CleanPages( |
| 664 | unique_lock<mutex>* client_lock, int64_t len, bool lazy_flush) { |
| 665 | DCHECK_GE(len, 0); |
| 666 | DCHECK_LE(len, reservation_.GetReservation()); |
| 667 | DCheckHoldsLock(*client_lock); |
| 668 | // If another thread is in CleanPages() for this client (and has dropped the lock while |
| 669 | // waiting on 'write_complete_cv_', wait for it to flush its pages before proceeding so |
| 670 | // that we don't overcommit memory. |
| 671 | while (cleaning_pages_) clean_pages_done_cv_.Wait(*client_lock); |
| 672 | |
| 673 | DCHECK_CONSISTENCY(); |
| 674 | // Work out what we need to get bytes of dirty unpinned + in flight pages down to |
| 675 | // in order to satisfy the eviction policy. |
| 676 | int64_t target_dirty_bytes = reservation_.GetReservation() - buffers_allocated_bytes_ |
| 677 | - pinned_pages_.bytes() - len; |
| 678 | if (VLOG_IS_ON(3)) { |
| 679 | VLOG(3) << "target_dirty_bytes=" << target_dirty_bytes |
| 680 | << " reservation=" << reservation_.GetReservation() |
| 681 | << " buffers_allocated_bytes_=" << buffers_allocated_bytes_ |
| 682 | << " pinned_pages_.bytes()=" << pinned_pages_.bytes() |
| 683 | << " len=" << len << "\n" |
| 684 | << DebugStringLocked(); |
| 685 | } |
| 686 | // Start enough writes to ensure that the loop condition below will eventually become |
| 687 | // false (or a write error will be encountered). |
| 688 | int64_t min_bytes_to_write = |
| 689 | max<int64_t>(0, dirty_unpinned_pages_.bytes() - target_dirty_bytes); |
| 690 | if (lazy_flush |
| 691 | && dirty_unpinned_pages_.bytes() + in_flight_write_pages_.bytes() |
| 692 | <= target_dirty_bytes) { |
| 693 | return Status::OK(); |
| 694 | } |
| 695 | cleaning_pages_ = true; |
| 696 | auto exit_trigger = MakeScopeExitTrigger([this, client_lock]() { |
| 697 | DCheckHoldsLock(*client_lock); |
| 698 | cleaning_pages_ = false; |
| 699 | clean_pages_done_cv_.NotifyAll(); |
| 700 | }); |
| 701 | WriteDirtyPagesAsync(min_bytes_to_write); |
| 702 | |
| 703 | // One of the writes we initiated, or an earlier in-flight write may have hit an error. |
| 704 | RETURN_IF_ERROR(write_status_); |
| 705 | |
| 706 | // Wait until enough writes have finished so that we can make the allocation without |
| 707 | // violating the eviction policy. I.e. so that other clients can immediately get the |
| 708 | // memory they're entitled to without waiting for this client's write to complete. |
| 709 | DCHECK_GE(in_flight_write_pages_.bytes(), min_bytes_to_write) << DebugStringLocked(); |
| 710 | while (dirty_unpinned_pages_.bytes() + in_flight_write_pages_.bytes() |
| 711 | > target_dirty_bytes) { |
| 712 | SCOPED_TIMER(counters().write_wait_time); |
| 713 | write_complete_cv_.Wait(*client_lock); |
| 714 | RETURN_IF_ERROR(write_status_); // Check if error occurred while waiting. |
| 715 | } |
| 716 | return Status::OK(); |
| 717 | } |
| 718 | |
| 719 | void BufferPool::Client::WriteDirtyPagesAsync(int64_t min_bytes_to_write) { |
| 720 | DCHECK_GE(min_bytes_to_write, 0) << DebugStringLocked(); |
nothing calls this directly
no test coverage detected