Victim(frame_id_t*) : Remove the object that was accessed least recently compared to all the other elements being tracked by the Replacer, store its contents in the output parameter and return True. If the Replacer is empty return False.
Pin(frame_id_t) : This method should be called after a page is pinned to a frame in the BufferPoolManager. It should remove the frame containing the pinned page from the LRUReplacer.
Unpin(frame_id_t) : This method should be called when the pin_count of a page becomes 0. This method should add the frame containing the unpinned page to the LRUReplacer.
Size() : This method returns the number of frames that are currently in the LRUReplacer
Page *BufferPoolManagerInstance::NewPgImp(page_id_t *page_id){ // 0. Make sure you call AllocatePage! // 1. If all the pages in the buffer pool are pinned, return nullptr. // 2. Pick a victim page P from either the free list or the replacer. Always pick from the free list first. // 3. Update P's metadata, zero out memory and add P to the page table. // 4. Set the page ID output parameter. Return a pointer to P. std::lock_guard<std::mutex> lock(latch_); // step 1 bool all_pinned = true; for (size_t i = 0; i < pool_size_; ++i) { if (pages_[i].pin_count_ <= 0) { all_pinned = false; break; } } if (all_pinned) returnnullptr; // allocate a page on disk. *page_id = AllocatePage(); Page* p = nullptr; // pick a victim page P. frame_id_t fid; if (free_list_.empty()) { // pick from free list first. if (!replacer_->Victim(&fid)) { returnnullptr; } else { p = &pages_[fid]; if (p->is_dirty_) { disk_manager_->WritePage(p->page_id_, p->data_); p->is_dirty_ = false; } page_table_.erase(p->page_id_); } } else { fid = free_list_.front(); free_list_.pop_front(); p = &pages_[fid]; } // add P to the page table. page_table_[*page_id] = fid; // updata P's metadata. p->page_id_ = *page_id; p->pin_count_ = 1; replacer_->Pin(fid); // zeroes out the data that is held within the page p->ResetMemory(); // step 4 return p; }
Page *BufferPoolManagerInstance::FetchPgImp(page_id_t page_id){ // 1. Search the page table for the requested page (P). // 1.1 If P exists, pin it and return it immediately. // 1.2 If P does not exist, find a replacement page (R) from either the free list or the replacer. // Note that pages are always found from the free list first. // 2. If R is dirty, write it back to the disk. // 3. Delete R from the page table and insert P. // 4. Update P's metadata, read in the page content from disk, and then return a pointer to P. std::lock_guard<std::mutex> lock(latch_); // step 1 frame_id_t fid; Page* p = nullptr; if (page_table_.find(page_id) != page_table_.end()) { // find. fid = page_table_[page_id]; pages_[fid].pin_count_++; // pin it. replacer_->Pin(fid); return &pages_[fid]; } if (free_list_.empty()) { // pick from free list first. if (!replacer_->Victim(&fid)) { returnnullptr; } else { // the page placed in the lrureplacer need to be flushed. p = &pages_[fid]; if (p->is_dirty_) { disk_manager_->WritePage(p->page_id_, p->data_); p->is_dirty_ = false; } page_table_.erase(p->page_id_); } } else { fid = free_list_.front(); free_list_.pop_front(); p = &pages_[fid]; } // step 3 // insert p. page_table_[page_id] = fid; replacer_->Pin(fid); // update P's metadata. p->page_id_ = page_id; p->pin_count_ = 1; // read in the page content from disk. disk_manager_->ReadPage(page_id, p->data_); return p; }
boolBufferPoolManagerInstance::DeletePgImp(page_id_t page_id){ // 0. Make sure you call DeallocatePage! // 1. Search the page table for the requested page (P). // 1. If P does not exist, return true. // 2. If P exists, but has a non-zero pin-count, return false. Someone is using the page. // 3. Otherwise, P can be deleted. Remove P from the page table, reset its metadata and return it to the free list. std::lock_guard<std::mutex> lock(latch_); // P does not exist. if (page_table_.find(page_id) == page_table_.end()) { returntrue; } // P does exist. frame_id_t fid = page_table_[page_id]; Page* deletepage = &pages_[fid]; if (deletepage->pin_count_ != 0) { returnfalse; } // flush the page before deallocate it. if (deletepage->is_dirty_) { disk_manager_->WritePage(page_id, deletepage->data_); deletepage->is_dirty_ = false; } DeallocatePage(page_id); // remove P from the page table. page_table_.erase(page_id); // reset its metadata. // the page returned to freelist does not stores any page. deletepage->page_id_ = INVALID_PAGE_ID; deletepage->is_dirty_ = false; deletepage->pin_count_ = 0; // return it to free_list_. free_list_.push_back(fid); returntrue; }
UnpinPgImp
保留传入的dirty状态,在Victim时刷盘。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
boolBufferPoolManagerInstance::UnpinPgImp(page_id_t page_id, bool is_dirty){ std::lock_guard<std::mutex> lock(latch_); frame_id_t fid = page_table_[page_id]; Page* p = &pages_[fid]; p->is_dirty_ = is_dirty; // hold the state until victim. if (p->pin_count_ <= 0) returnfalse; --p->pin_count_; if (p->pin_count_ == 0) { replacer_->Unpin(fid); returntrue; } returnfalse; }
FlushPgImp
1 2 3 4 5 6 7 8
boolBufferPoolManagerInstance::FlushPgImp(page_id_t page_id){ // Make sure you call DiskManager::WritePage! std::lock_guard<std::mutex> lock(latch_); if (page_table_.find(page_id) == page_table_.end() || page_id == INVALID_PAGE_ID) returnfalse; disk_manager_->WritePage(page_id, pages_[page_table_[page_id]].data_); returntrue; }