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类:

  1. free: 存放在free_list_中, 内部的页都是初始状态, 页内数据(data_)为无效数据, 通过free_list_查找.
  2. pinned: 存放着有线程访问的页, 通过page_table_查找.
  3. 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_dirtytrue时, 将对应pageis_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, 该pagepin_count_为1(有一个线程正在使用).
  • DeletePageImpl(page_id_t page_id):
    • page_table_中找到对应page, 只有当pin_count_为0时才能删除, 并从page_table_擦除, 在free_list_末尾插入.

一些坑:

  • Replacer需要单独用锁保护.
  • UnpinPageImpl中, 只有当is_dirtytrue时, 才修改对应pageis_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实验代码,已满分)

CMU15445

CMU 15445 9. 排序和聚合算法

CMU15-445 Lecture #05 Buffer Pools

CMU15-445 Lecture #05 Buffer Pools