$project\ 0$
编写一个可持久化 $Trie$,完成在多线程情况下…。主要是学习数据结构和 $modren\ C++$
$project\ 1$
任务目标:设计一个 $Buffer\ Pool\ Manager$,维护内存 $frame$,以支持对磁盘 $page$ 的读写操作。
一些概念和说明:
- 因为 $CPU$ 不能直接对磁盘($disk$)读写,而必须要读入内存中才能进行操作,而数据都存放在 $disk$ 中。所以需要维护一个内存管理机构 $Buffer\ Pool\ Manager$,将 $disk$ 数据根据 $CPU$ 读写要求放入内存和回写到 $disk$ 中。
- 内存 $frame$ 和 $disk page$:两者都可以视为一片存储区域且大小相等。它们的中文翻译都是“页”,但是在本任务中需要区分二者的区别,因而本文中直接使用 $frame$ 和 $page$ 来表示它们。 缓冲池里面有多个 $frame$,$frame$里面存放的就是$page$。
任务一:$\ LRU–K\ Replacement\ Policy$
- $LRU$ 是每次逐出最后未被访问的页面,而$LRU–K$则是分类讨论:如果存在某些页面的访问次数未到
次,则优先从这些页面中选取最后未被访问的页面逐出;否则都访问了次,回归正常的 $LRU$ 算法。 - 还要多考虑一种情况- 是否可逐出。这是因为在运行中,某些页面可能正在被读写,此时哪怕访问次数不够多也不能逐出正在被访问的页面。所以使用
SetEvictable
方法来调整页面的可逐出性。 - 怎么判断是否在被读写只需要加一个变量维护即可
pin_count
,如果不为0
,则不能被驱逐。 - 每个线程在访问缓存池时都需要一把大锁将缓存池锁住,保持线程同步。
任务二:$Disk\ Scheduler$
- $Diskscheduler$ 类的构造函数中启动了一个线程,这个线程一直执行一个工作函数,不断从消息队列中取出 $request$,完成对磁盘的读写请求。
- $DiskManager$ 类。它是对 $disk$ 进行读写的工具,包含两个方法:$WritePage$ 和 $ReadPage$。$DiskScheduler$ 类是对 $DiskManager$ 类的一次封装。
- $Request$ 包含需要读写的页面 $id$,读写任务,$future$等。其他线程将 $request$ 传递给 $Diskscheduler$ 类,通过 $dist\_mannager$ 完成后通过
futurt.set_value()
通知任务完成。
任务三:$BufferPoolManager$
- $Buffer\ Pool\ Manager(bpm)$ 管理若干个 $frame$,同时附带维护一个 $replacer$ 供页面替换,$disk\_scheduler$ 进行 $disk$ 读写操作以及空闲的
frame
,frameid
和pageid
的映射。 - 在取 $page$ 的时候
- 如果
page
存在缓冲区中,直接返回 - $page$不在缓冲池里面,先看空闲$frame$链表是否不为空,若为空则驱逐一个旧
page
,然后调用diskscheduler
线程将磁盘中的page
数据读入到这个$frame$。这需要使用到一个future
来异步读取。(如果被驱逐的page
脏了也要用diskscheduler
将数据写回磁盘)。 - 缓存池不满,直接从磁盘读取。
- 如果