写在前面
总算是过了,以为之前已经reset回23fall的commit了,结果发现buffer_pool_manager.h
还是24spring的,估计还得抽时间为这个忙活一下。
task1对于不足k次的是采用FIFO的策略才能通过测试,一开始写的是LRU的策略结果LRUKReplacerTest.Evict (0/6)
。
接着是task3的笔误,auto BufferPoolManager::DeletePage(page_id_t page_id) -> bool
中的free_list_.emplace_back(fid);
写成了free_list_.emplace_back(page_id);
。
通关记录
首先是任务1要实现一个LRU-K算法。在网上查阅一些资料说要弄两个队列去维护?但仔细想了一下只需要一个就好了,正如课程页面写的:
The LRU-K algorithm
The LRU-K algorithm evicts a frame whose backward k-distance is maximum of all frames in the replacer. Backward k-distance is computed as the difference in time between current timestamp and the timestamp of kth previous access. A frame with fewer than k historical accesses is given +inf as its backward k-distance. When multiple frames have +inf backward k-distance, the replacer evicts the frame with the earliest overall timestamp (i.e., the frame whose least-recent recorded access is the overall least recent access, overall, out of all frames).
因为当前时间戳在比较时都是一致的,所以不满足k条访问的设为极小值,然后按顺序插入即可实现一个队列维护操作:
void LRUKReplacer::RecordAccess(frame_id_t frame_id, [[maybe_unused]] AccessType access_type) {
std::lock_guard<std::mutex> lock(latch_);
if (static_cast<size_t>(frame_id) > replacer_size_) {
throw Exception("The frame id is invalid!");
}
LRUKNode temp(k_, frame_id);
if (frame_umap_.count(frame_id) != 0U) {
auto it = frame_umap_.at(frame_id);
// FIFO以通过测试
if (it->Size() + 1 < k_) {
it->AddRecord(current_timestamp_);
current_timestamp_ += 1;
return;
}
temp = *it;
frame_.erase(it);
frame_umap_.erase(frame_id);
}
temp.AddRecord(current_timestamp_);
current_timestamp_ += 1;
auto dis = temp.CalKDis();
// 按顺序插入
auto it = std::upper_bound(frame_.begin(), frame_.end(), dis,
[](size_t dis, const LRUKNode &node) { return dis < node.CalKDis(); });
it = frame_.insert(it, temp);
frame_umap_[frame_id] = it;
}
其他的内容按照注释实现即可。
任务2和任务3是实现一个缓存池页面的管理和置换,这里要学一下std::promise
。
接下来也是跟着注释写,但是在auto BufferPoolManager::FlushPage(page_id_t page_id) -> bool
还是没按照注释不设置is_dirty_
标志符,感觉还是要设置的。