通過110/160的測試,還有少量問題需要解決。
理解什麼是Page的pin, unpin和LRU的pin,unpin含義不同
page的pin,count++, page的unpin count--
LRU的pin表示從Replace取出,unpin表示加入到LRU
FlushPageImpl 給定page_id,將對應的頁寫到磁盤上,這個沒什麼問題。FlushPageImpl不加鎖,而保證在調用的時候加鎖。
bool BufferPoolManager::FlushPageImpl(page_id_t page_id) {
// Make sure you call DiskManager::WritePage!
if(page_table_.find(page_id)==page_table_.end()){
return false;
}
auto frame_id = page_table_[page_id];
auto page = pages_ + frame_id;
disk_manager_->WritePage(page_id,page->GetData());
page->is_dirty_ = false;
return true;
}
DeletePage操作,記住當引用計數爲0時,執行Replace的Pin操作。
bool BufferPoolManager::DeletePageImpl(page_id_t page_id) {
// 0. Make sure you call DiskManager::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::scoped_lock bpm_slk{latch_};
//disk_manager_->DeallocatePage(page_id);
if(page_table_.find(page_id)==page_table_.end()) { return true;}
auto frame_id = page_table_[page_id];
auto page = pages_ + frame_id;
if(page->pin_count_>0){
return false;
}
replacer_->Pin(frame_id);
page_table_.erase(page_id);
page->page_id_ = INVALID_PAGE_ID;
free_list_.push_back(frame_id);
disk_manager_->DeallocatePage(page_id);
return true;
}
UnpinPageImpl
bool BufferPoolManager::UnpinPageImpl(page_id_t page_id, bool is_dirty) {
std::scoped_lock bpm_slk{latch_};
if(page_table_.find(page_id)==page_table_.end()){return false;}
auto frame_id = page_table_[page_id];
auto page = pages_ + frame_id;
if(is_dirty){
FlushPageImpl(page_id);
}
if(page->pin_count_>0) {
page->pin_count_--;
}
if(page->pin_count_==0){
replacer_->Unpin(frame_id);
}
return true;
}
FetchPageImpl操作,注意在table中找到,pin以後,Replacer也要pin一次。
Page *BufferPoolManager::FetchPageImpl(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::scoped_lock bpm_slk{latch_};
if(page_table_.find(page_id)!=page_table_.end()) {
auto frame_id = page_table_[page_id];
auto page = pages_ + frame_id;
page->pin_count_++; // pin it
replacer_->Pin(frame_id); // replacer 也要pin
return page;
}
if(free_list_.empty()&&replacer_->Size()==0) {
return nullptr;
}
frame_id_t frame_id = -1;
Page *page = nullptr;
if(!free_list_.empty()){
frame_id = free_list_.front();
free_list_.pop_back();
page = pages_ + frame_id;
}else{
replacer_->Victim(&frame_id);
page = pages_ + frame_id;
page_table_.erase(page->GetPageId()); // 淘汰
}
if(page->is_dirty_){ // 把舊數據寫到磁盤上
disk_manager_->WritePage(page->GetPageId(),page->GetData());
}
page_table_[page_id] = frame_id;
page->page_id_ = page_id;
page->ResetMemory();
page->pin_count_ = 1;
page->is_dirty_ = false;
disk_manager_->ReadPage(page_id,page->data_); // 讀取新的數據
return page;
}
創建新的一頁
Page *BufferPoolManager::NewPageImpl(page_id_t *page_id) {
// 0. Make sure you call DiskManager::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::scoped_lock bpm_slk{latch_};
frame_id_t frame_id = -1;
Page *page = nullptr;
if(free_list_.empty()&&replacer_->Size()==0){
return nullptr;
}
if(!free_list_.empty()){
frame_id = free_list_.front();
free_list_.pop_front();
page = pages_ + frame_id;
}else{
replacer_->Victim(&frame_id);
page = pages_ + frame_id;
page_table_.erase(page->page_id_);
if(page->is_dirty_){
disk_manager_->WritePage(page->page_id_,page->data_);
}
}
auto new_page_id = disk_manager_->AllocatePage();
page_table_[new_page_id] = frame_id;
page->ResetMemory();
page->page_id_ = new_page_id;
*page_id = page->page_id_;
page->is_dirty_ = true;
page->pin_count_ = 1;
return page;
}
Flush All
void BufferPoolManager::FlushAllPagesImpl() {
// You can do it!
for(size_t i=0;i<pool_size_;i++){
FlushPageImpl(pages_[i].page_id_);
}
}