0%

15-445 Project 1 - Buffer Pool Manager

Task #1 - LRU-K Replacement Policy

实现一个 LRU-K 替换算法,如果用堆的话,在 RecordAccess 时需要先删除在插入 $O (logn)$,所以先直接用 $O (n)$ 暴力

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).

说明中当多个 frame 最后一次有 + inf 时,evict 掉最早访问时间最早的 (不是最近一次访问)

Task #2 - Buffer Pool Manager

  • NewPage(page_id_t* page_id) 如果 page 在 buffer 中,直接返回该 page。如果不在 buffer 中,分配一个 AllocatePage()
  • FetchPage(page_id_t page_id) 如果该 page 已经存在 buffer 中,那么应该增加引用计数并且记录访问,如果不在 buffer 中那么分配一个并执行相同操作(我一开始理解成了如果在 buffer 中直接返回)
  • UnpinPage(page_id_t page_id, bool is_dirty) 减少对应 page 的引用计数,设定 is dirty
  • FlushPage(page_id_t page_id) FlushAllPages() Flush 对应的 Page
  • DeletePage(page_id_t page_id) 在 buffer 中删除对应的 page,归还给 freelist

Task #3 - Read/Write Page Guards

类似于 std::lock_guard,对 page 实现一个 RAII 的封装
实现对应的拷贝构造 / 赋值,析构函数
还有 ReadPageGuardWritePageGuard,调用对应的 Latch 就好 concurrency - What is the difference between a lock and a latch in the context of concurrent access to a database? - Stack Overflow

Leaderboard

先记录下可能的思路,后续做完 Project 再来搞

  1. Buffer Manager 一把大锁,没法做到并行的从磁盘读取,恰好读取 / 写入的时候延迟比较高,可以考虑每个 frame (buffer slot) 有单独的锁,在 disk_manager read/write 时放掉大锁(注意下不能先放掉大锁,会有 race)
  2. (By ChatGPT) 优先替换扫描线程访问的页面:由于 get 线程的工作负载是倾斜的,你可能希望在缓冲区管理器中保留那些更频繁地被访问的页面。因此,当需要替换页面时,你可以首先考虑那些由扫描线程访问的页面。—— 在 LRUKNode 中记录访问模式,第一遍从 SCAN 的 Node 中做 LRU,找不到再去 Get 的 Node 中找
  3. LRU-K: 可以用 Heap,但是替换后 RecordAccess 的操作就从 $O (1)$ 变成了 $O (logn)$,

Reading List