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 dirtyFlushPage(page_id_t page_id)
FlushAllPages()
Flush对应的PageDeletePage(page_id_t page_id)
在buffer中删除对应的page,归还给freelist
Task #3 - Read/Write Page Guards
类似于std::lock_guard
,对page实现一个RAII的封装
实现对应的拷贝构造/赋值,析构函数
还有ReadPageGuard
和WritePageGuard
,调用对应的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再来搞
- Buffer Manager一把大锁,没法做到并行的从磁盘读取,恰好读取/写入的时候延迟比较高,可以考虑每个frame(buffer slot)有单独的锁,在disk_manager read/write时放掉大锁(注意下不能先放掉大锁,会有race)
- (By ChatGPT)优先替换扫描线程访问的页面:由于 get 线程的工作负载是倾斜的,你可能希望在缓冲区管理器中保留那些更频繁地被访问的页面。因此,当需要替换页面时,你可以首先考虑那些由扫描线程访问的页面。——在LRUKNode中记录访问模式,第一遍从SCAN的Node中做LRU,找不到再去Get的Node中找
- LRU-K: 可以用Heap,但是替换后RecordAccess的操作就从$O(1)$变成了$O(logn)$,