| 514 | } |
| 515 | |
| 516 | Status BufferPool::Client::StartMoveToPinned(ClientHandle* client, Page* page) { |
| 517 | unique_lock<mutex> cl(lock_); |
| 518 | DCHECK_CONSISTENCY(); |
| 519 | // Propagate any write errors that occurred for this client. |
| 520 | RETURN_IF_ERROR(write_status_); |
| 521 | |
| 522 | if (dirty_unpinned_pages_.Remove(page)) { |
| 523 | // No writes were initiated for the page - just move it back to the pinned state. |
| 524 | pinned_pages_.Enqueue(page); |
| 525 | return Status::OK(); |
| 526 | } |
| 527 | if (in_flight_write_pages_.Contains(page)) { |
| 528 | // A write is in flight. If so, wait for it to complete - then we only have to |
| 529 | // handle the pinned and evicted cases. |
| 530 | WaitForWrite(&cl, page); |
| 531 | RETURN_IF_ERROR(write_status_); // The write may have set 'write_status_'. |
| 532 | } |
| 533 | |
| 534 | // At this point we need to either reclaim a clean page or allocate a new buffer. |
| 535 | // We may need to clean some pages to do so. |
| 536 | RETURN_IF_ERROR(CleanPages(&cl, page->len)); |
| 537 | if (pool_->allocator_->RemoveCleanPage(cl, true, page)) { |
| 538 | // The clean page still has an associated buffer. Restore the data, and move the page |
| 539 | // back to the pinned state. |
| 540 | pinned_pages_.Enqueue(page); |
| 541 | DCHECK(page->buffer.is_open()); |
| 542 | DCHECK(page->write_handle != NULL); |
| 543 | // Don't need on-disk data. |
| 544 | cl.unlock(); // Don't block progress for other threads operating on other pages. |
| 545 | return file_group_->RestoreData( |
| 546 | move(page->write_handle), page->buffer.mem_range(), &counters_); |
| 547 | } |
| 548 | // If the page wasn't in the clean pages list, it must have been evicted. |
| 549 | return StartMoveEvictedToPinned(&cl, client, page); |
| 550 | } |
| 551 | |
| 552 | Status BufferPool::Client::StartMoveEvictedToPinned( |
| 553 | unique_lock<mutex>* client_lock, ClientHandle* client, Page* page) { |