CMU 15-445/645 fall2024 p1

在服务器内按照 bustub 文档完成开发环境配置后,P1 主要实现了 Buffer Pool 的核心路径:替换器、异步磁盘调度、页面 Guard,以及 BufferPoolManager 的页面生命周期管理。和 P0 一样,public 指模板仓库远程,origin 指我自己的远程仓库,日常开发在本地仓库完成。

Git 命令

git pull public master # 拉取模板更新
git push origin main   # 推送本地提交

lru_k_replacer.cpp

lru_k_replacer.cpp 实现了 LRU-K 替换器(按 backward k-distance 选择 victim):

  • LRUKReplacer(...) 在 src/buffer/lru_k_replacer.cpp:19 初始化容量、k 值和内部容器。
  • Evict 在 src/buffer/lru_k_replacer.cpp:21 选择可驱逐帧:优先处理访问次数不足 k 次的帧,否则比较 backward k-distance,最终移除 victim 并更新可驱逐数量。
  • RecordAccess 在 src/buffer/lru_k_replacer.cpp:75 记录访问时间戳,并维护每帧最近 k 次访问历史。
  • SetEvictable 在 src/buffer/lru_k_replacer.cpp:89 切换帧可驱逐状态,同步更新 size。
  • Remove 在 src/buffer/lru_k_replacer.cpp:112 删除指定帧(要求可驱逐)。
  • Size 在 src/buffer/lru_k_replacer.cpp:131 返回当前可驱逐帧数量。

disk_scheduler.cpp

disk_scheduler.cpp 实现了基于后台线程的异步磁盘调度:

  • DiskScheduler(...) 在 src/storage/disk/disk_scheduler.cpp:18 启动 worker 线程。
  • ~DiskScheduler 在 src/storage/disk/disk_scheduler.cpp:23 发送停止信号并 join,确保线程有序退出。
  • Schedule 在 src/storage/disk/disk_scheduler.cpp:31 将读写请求入队(请求里带 promise 用于完成通知)。
  • StartWorkerThread 在 src/storage/disk/disk_scheduler.cpp:33 循环取队列任务,调用 DiskManager::ReadPage/WritePage,完成后设置 promise。

page_guard.cpp

page_guard.cpp 用 RAII 管理页面 latch 与 pin/unpin,避免资源泄漏:

  • ReadPageGuard 构造在 src/storage/page/page_guard.cpp:30,接管读锁页面。
  • 读 Guard 的移动构造/赋值在 src/storage/page/page_guard.cpp:52、src/storage/page/page_guard.cpp:79,保证所有权安全转移。
  • ReadPageGuard::Drop 在 src/storage/page/page_guard.cpp:132 释放锁、减少 pin,并在合适时更新 replacer 状态。
  • WritePageGuard 构造在 src/storage/page/page_guard.cpp:173,接管写锁页面。
  • 写 Guard 的移动构造/赋值在 src/storage/page/page_guard.cpp:196、src/storage/page/page_guard.cpp:223。
  • WritePageGuard::Drop 在 src/storage/page/page_guard.cpp:284 做写路径释放,保证 dirty/pin/replacer 状态一致。

buffer_pool_manager.cpp

buffer_pool_manager.cpp 是 P1 主体,负责管理 frame/page 的完整生命周期:

  • FrameHeader::Reset 在 src/buffer/buffer_pool_manager.cpp:44 重置 frame 元数据(包括 page_id_)。
  • ScheduleDiskWrite/Read 在 src/buffer/buffer_pool_manager.cpp:109、src/buffer/buffer_pool_manager.cpp:116 封装异步 IO 与等待逻辑。
  • FetchPage 在 src/buffer/buffer_pool_manager.cpp:123 处理命中和缺页:命中则增加 pin 并记录访问;缺页则从 free list/replacer 选帧,必要时刷脏页,再读入目标页并更新页表。
  • NewPage 在 src/buffer/buffer_pool_manager.cpp:194 分配新页号并绑定 frame,初始化页面与元数据。
  • DeletePage 在 src/buffer/buffer_pool_manager.cpp:226 删除页面:被 pin 时返回失败;否则移除页表/replacer 项并回收 frame。
  • CheckedWritePage / CheckedReadPage 在 src/buffer/buffer_pool_manager.cpp:288、src/buffer/buffer_pool_manager.cpp:320 返回 WritePageGuard/ReadPageGuard(失败返回 std::nullopt)。
  • FlushPage 在 src/buffer/buffer_pool_manager.cpp:394 将单页写回磁盘并清除 dirty。
  • FlushAllPages 在 src/buffer/buffer_pool_manager.cpp:440 批量刷盘所有缓冲页。
  • GetPinCount 在 src/buffer/buffer_pool_manager.cpp:479 读取页面 pin 次数,便于测试与调试。

生成提交包

1.打包(与这次通过的文件列表一致) rm -f project1-submission.zip zip project1-submission.zip
src/include/buffer/lru_k_replacer.h
src/buffer/lru_k_replacer.cpp
src/include/buffer/buffer_pool_manager.h
src/buffer/buffer_pool_manager.cpp
src/include/storage/disk/disk_scheduler.h
src/storage/disk/disk_scheduler.cpp
src/storage/page/page_guard.cpp
src/include/storage/page/page_guard.h

2.把签名文件加进 zip(首次会交互生成 GRADESCOPE.md) python3 gradescope_sign.py

3.检查提交包内容 unzip -l project1-submission.zip