CMU15445 PROJECT #1
Posted 彩虹狗
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CMU15445 PROJECT #1相关的知识,希望对你有一定的参考价值。
CMU15445 PROJECT #1 - BUFFER POOL
第一个编程项目是在存储管理器中实现缓冲池. 缓冲池负责将物理页面从主内存来回移动到磁盘. 它允许 DBMS 支持大于系统可用内存量的数据库. 缓冲池的操作对系统的其他部分是透明的. 例如, 系统使用其唯一标识符(page_id_t
)向缓冲池询问页面, 它不知道该页面是否已处于内存状态, 也不知道系统是否必须从磁盘中取回该页面.
需要处理并发的情况, 需要用到latches也就是os中的lock.
本实验分为两个子任务:
TASK #1 - LRU REPLACEMENT POLICY
缓冲池中有一些页正在被读写(pinned
), 而有一些虽然缓存在缓冲池但没有线程在使用它们, 这些页(unpinned
)就存放在Replacer, 通过frame_id
索引. 当需要从磁盘取出页到缓冲池, 但是缓冲池满了, 就要从Replacer中移除一些页.
使用unordered_map
和双链表可以在\\(O(1)\\)内完成以下操作:
Victim
: 通过链表的尾节点找到要被换出的页, 将该节点删除并在unordered_map
中删除.Pin
: 通过unordered_map
可以快速找到frame_id
对应的页, 并将该节点删除. 当找不到该节点时就不处理直接返回.Unpin
: 如果已经在Replacer中存在, 就不处理, 如果不存在就将其加入链表第一个, 并判断是否溢出(capacity<size), 如果溢出了, 就将最后一个页换出.
TASK #2 - BUFFER POOL MANAGER
几个重要参数:
-
page_id
: 用于索引磁盘上的页(page). 系统给BPM想要读取的页id(page_id
), BPM在page_table_
中可以将page_id
转换为缓冲池中的frame, 从而减少读盘. -
frame_id
: 用于索引从磁盘中获取的页, 存储在缓冲池中的帧(frame). -
pages_
: 保存page, 通过(pages_ + frame_id)
访问对应page
地址. -
free_list_
: 保存所有free frame的索引(frame_id
). -
page_table_
: 保存所有pinned frame和unpinned frame, 通过page_id
来查找对应的frame_id
. -
page
内参数:data_
: 页内数据.pin_count
: 多少个线程正在使用该页, 如果pin_count_
为0, 说明该页存放在Replacer中.is_dirty_
: 是否有线程写过该页.
以下这张图可以很好解释frame和page的区别, 以及frame_id
索引frame, page_id
索引page.
BPM从磁盘取出一些页, 放入缓冲池中, 这些页被称为frame, 对于内存池中所有frame, BPM可以将其分为3类:
free
: 存放在free_list_
中, 内部的页都是初始状态, 页内数据(data_
)为无效数据, 通过free_list_
查找.pinned
: 存放着有线程访问的页, 通过page_table_
查找.unpinned
: 存放在Replacer中的页, 没有线程访问, 但保留有有效数据(data_
), 通过page_table_
查找.
通过一个状态机可以很好的观察frame的三种状态, 以及其中的转换.
需要实现以下几个接口:
FetchPageImpl(page_id_t page_id)
:- 寻找
page_table_
, 如果通过page_id
可以在page_table_
找到对应的frame_id
, 就通过pages_
找到对应的page
, 此时使用该page
的进程多了一个, 就将pin_count_++
, 并从Replacer中取出. - 如果在
page_table_
中找不到, 就在free_list_
中找, 通过free_list_
找到frame_id
并在链表中删除, 得到相应的page
. 在page_table_
中映射该frame. 为该page
赋予page_id
并从磁盘读取data_
, 将pin_count_++
后返回. - 如果在
free_list_
还是找不到, 就在Replacer中Victim一个页. 当该页dirty时, 写入磁盘. 在page_table_
中擦去此页并用新page_id
映射, 此时页的pin_count_
为1, 同样读取磁盘后返回. - 如果上述都不成立就返回
nullptr
.
- 寻找
UnpinPageImpl(page_id_t page_id, bool is_dirty)
:- 如果在
page_table_
中找不到对应的页就直接返回. - 当
is_dirty
为true
时, 将对应page
的is_dirty_
设置为true
. 此处是手动改, 也就是说和is_dirty_
的原先状态无关. pin_count_
为0时将frame放入Replacer.
- 如果在
FlushPageImpl(page_id_t page_id)
:- 不管
pin_count_
, 但凡能在page_table_
找到就刷盘
- 不管
NewPageImpl(page_id_t *page_id)
:- 如果能从
free_page_
中找到, 就分配一个新page
, 通过AllocatePage
获得page_id
, 更新一下page
状态并映射到page_table_
. - 否则就从Replacer中找一个Victim页, 剩余操作和
FetchPageImpl
类似. - new完一个
page
, 该page
的pin_count_
为1(有一个线程正在使用).
- 如果能从
DeletePageImpl(page_id_t page_id)
:- 在
page_table_
中找到对应page
, 只有当pin_count_
为0时才能删除, 并从page_table_
擦除, 在free_list_
末尾插入.
- 在
一些坑:
- Replacer需要单独用锁保护.
UnpinPageImpl
中, 只有当is_dirty
为true
时, 才修改对应page
的is_dirty_
标志为true
(不用管is_dirty_
标志的原先状态).page
中的锁暂时不需要.
todo: 跑完3s+, 距离第一个1s还有很大差距, 有空在优化下吧.
以上是关于CMU15445 PROJECT #1的主要内容,如果未能解决你的问题,请参考以下文章
CMU15-445 PROJECT #1 - BUFFER POOL(Fall2020实验代码,已满分)
CMU15-445 PROJECT #1 - BUFFER POOL(Fall2020实验代码,已满分)