Project Page

Task 1 Adaptive Replacement Cache Replacement Policy

需要感性理解这个算法的流程。

RecordAccess 函数中,如果命中了 MRU ghost 或者 MFU ghost,我们都需要把它 移动到 MFU list 中。实现的过程中还是遇到了一个小 Bug,从 MRU ghost 或者 MFU ghost 移除 page_id 之后,还要记得把它从 ghost_map_ 中移除。这是我新加的数据结构,记录 当前在任意一个 ghost 列表中存在的 page_id

Task 2 Disk Scheduler

直接使用已经实现的 Channel 作为线程安全的任务队列。

Task 3 Buffer Pool Manager

这个部分最难。

需要注意死锁问题、数据竞争问题。

细节 一

下面是我遇到的一个 Bug,它导致 gradescope ParadiseLostTest 测试失败。 我在 NewPage 的时候,对新页分配了一个 frame。在 CheckedReadPage/CheckedWritePage 中, 如果没有 free frame,需要尝试 Evict,但是 Evict 的页有可能是当前请求的 page_id,此时 old_page_id == page_id,然后我把 old_page_id 从 page_table 中移除了,这就导致了 Bug。 正确做法应该检查 old_page_id != page_id。

细节二

  1. T1 线程:获取 bpm_latch,发现 page_id 不在 page_table 中,并且没有 free frame,此时我们需要 Evict,如果淘汰的页面是脏的,我们需要刷进磁盘,并且要是异步的。
  2. T2 线程:如果在 T1 进行异步刷盘的时候,尝试获取同一个 page_id,此时有两种情况:如果 T1 已经把 page_id 存入 page_table 中,T2 可能会读取到部分数据、空数据、全部数据。如果 T1 没有把 page_id 存入 page_table 中,T2 可能会给它分配一个 frame,也就是说一个 page_id 对应了两个 frame。这会造成数据不一致。

解决方法:我们需要维护 page_state,代表当前页的状态:不在 page_table 中,正在加载,加载成功。当 T2 发现要读取的页面正在加载,我们使用信号量等待,当 wait 被唤醒的时候,我们需要重新检查页面的状态,避免假唤醒的情况。也就是说,我们需要对每个页面维护一个单独的信号量。

总结

这个实验调试了很久,还好没有放弃,最终一点一点调试出来了,非常有成就感。目前 Rank 46,以后可以考虑优化思路。

buffer-pool-manager

AI 还不是万能的,它可以把这个实验做到 84 分,但是调试死锁问题、数据竞争问题还差的比较远。 但是可以借助 AI 来分析,例如让它提供排查思路,给它一些打印的调试日志,让它分析可能的原因,然后 再人工分析验证、使用 GDB 调试等。