首先为LRUReplacer添加成员变量,这里直接使用STL的unordered_map和list,为了保证线程完全,直接在函数外面加互斥锁。
private:
using ListIterator = typename std::list<frame_id_t>::const_iterator;
using CacheMap = std::unordered_map<frame_id_t,ListIterator>;
std::list<frame_id_t> m_lruList;
CacheMap m_lruMap;
std::mutex m_lock;
注意,这几个函数的描述不是特别清楚,去test中找测试例子搞清楚这几个方法的含义。
Victim(T*)
找到替换的最久使用的对象,返回T*。
Pin(T) 从LRUReplacer删除对象T。
Unpin(T) 插入T到LRUReplacer中。注意当没有位置时,要进行淘汰掉最久没有使用的。
Size()就没有什么好说的。
Victim(T*)
: Remove the object that was accessed the least recently compared to all the elements being tracked by theReplacer
, store its contents in the output parameter and returnTrue
. If theReplacer
is empty returnFalse
.Pin(T)
: This method should be called after a page is pinned to a frame in theBufferPoolManager
. It should remove the frame containing the pinned page from theLRUReplacer
.Unpin(T)
: This method should be called when thepin_count
of a page becomes 0. This method should add the frame containing the unpinned page to theLRUReplacer
.Size()
: This method returns the number of frames that are currently in theLRUReplacer
.
接下来实现这六个函数
FetchPageImpl(page_id)
NewPageImpl(page_id)
UnpinPageImpl(page_id, is_dirty)
FlushPageImpl(page_id)
DeletePageImpl(page_id)
FlushAllPagesImpl()
这几个函数在文档中描述不是特别清楚。要结合注释揣摩,其中UnpinPage的实现需要特别注意
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];
if(pages_[frame_id].pin_count_ > 0){
pages_[frame_id].pin_count_--;
}
if(pages_[frame_id].pin_count_ == 0){
replacer_->Unpin(frame_id);
}
if(is_dirty){
pages_[frame_id].is_dirty_ = true;
}
return true;
}
Fetch和New都涉及到页面置换算法,所以为了简单,封装一个统一的页面置换操作
frame_id_t BufferPoolManager::find_replace() {
frame_id_t replace_id = -1;
if (!free_list_.empty()) {
replace_id = free_list_.front();
free_list_.pop_front();
} else if (replacer_->Size() > 0) {
replacer_->Victim(&replace_id);
page_table_.erase(pages_[replace_id].page_id_);
if (pages_[replace_id].IsDirty()) {
disk_manager_->WritePage(pages_[replace_id].page_id_, pages_[replace_id].GetData());
}
}
return replace_id;
}
另外对Page结构也做一个初始化操作
void BufferPoolManager::init_new_page(frame_id_t frame_id, page_id_t page_id) {
pages_[frame_id].page_id_ = page_id;
pages_[frame_id].pin_count_ = 1;
pages_[frame_id].is_dirty_ = false;
}
另外还需要注意C++ 互斥锁的操作。在所有方法最开始都加上。
std::scoped_lock bpm_slk{latch_};