【CMU 15-445】Proj1 Buffer Pool Manager

news2024/12/26 23:32:13

Buffer Pool Manager

  • 通关记录
  • Task1 LRU-K Replacement Policy
  • Task2 Disk Scheduler
  • Task3 Buffer Pool Manager
    • FlushPage
    • FlushAllPages
    • UnpinPage
    • NewPage
    • FetchPage
    • DeletePage
  • Optimizations

CMU-15445汇总
本文对应的project版本为CMU-Fall-2023的project1
由于Andy要求,本博客只提供思路,不会公开任何代码

通关记录

在这里插入图片描述

在这里插入图片描述
目前的rank还比较低,lru-k后续会优化下

Task1 LRU-K Replacement Policy

LRU-KLRU一样,都属于缓冲区的页面置换算法,不同的是,LRU-K考虑的是页面的之前第K次访问时间戳与当前时间戳的差(若不足K次则优先驱逐,若有多个访问不足K次的页面,则按LRU规则驱逐),而LRU考虑的是页面最近一次访问时间戳与当前时间戳的差。一个具体的例子如下图所示,假设K=3buffer大小为3,访问序列为1 2 3 2 3 2 3 1 1 4,当访问4时,会将1驱逐掉,图中当页面访问不足K次时,时间戳为最新访问时间戳,否则为前第K次的时间戳(蓝色数字为时间戳)。
在这里插入图片描述
Task1的要求是实现src/buffer/lru_k_replacer.cpp文件中的如下几个函数:

  • Evict(frame_id_t* frame_id):使用LRU-K算法驱逐一个frame,并使用参数返回frame_id;返回值类型为bool,若驱逐成功返回true,若当前可驱逐frame数量为0,则返回false
  • RecordAccess(frame_id_t frame_id):记录给定frame的访问历史
  • Remove(frame_id_t frame_id):将给定framebuffer中移除
  • SetEvictable(frame_id_t frame_id, bool set_evictable):设置frame可驱逐不可驱逐,若设置前后该属性不一致,则需要修改类内维护的可驱逐frame数量属性
  • Size():返回当前可驱逐frame数量

个人建议的实现顺序为Size->SetEvictable->RecordAccess->Evict->Remove
主要的难点在于RecordAccessEvict中各frameLRU-K信息维护与驱逐算法实现,目前我实现的版本为暴力版本,即在RecordAccess为每个frame维护一个大小为K的访问时间戳队列;在Evict中,遍历所有可驱逐的frame,找出LRU-K timestamp最小的那个,将其驱逐。(这个做法明显太慢了,后续优化一下)

Task2 Disk Scheduler

此部分需要实现一个简单的磁盘调度器,接收BufferPoolManager发来的读写磁盘请求放入一个请求队列中;然后启动一个新线程,不断从请求队列中获取请求,根据请求类型调用对应DiskManager的读写函数进行磁盘读写。主要实现文件src/storage/disk/disk_scheduler.cpp中的两个函数:

  • Schedule(DiskRequest r):接收请求并放入请求队列
  • StartWorkerThread():线程函数,从请求队列中获取新请求,并根据请求类型调用磁盘读写函数

个人建议的实现顺序为Schedule->StartWorkerThread
不需要考虑队列的线程安全性,已经有一个Channel类帮忙实现了生产者消费者模型;关于std::promise的用法,可参考disk_scheduler_test.cpp文件。

Task3 Buffer Pool Manager

这一部分需要实现一个BufferPoolManager,结合前两部分实现的LRU-K ReplacerDisk Scheduler进行缓冲区的管理物理页的开辟、获取与释放BufferPoolManager类维护的数据结构中包含一个Page类的数组(在BufferPoolManager的构造函数中会开辟空间),数组中的每个元素即为一个一个的framePage类主要包含以下几个成员:

  • page_id_t page_id_:表示该frame指向的物理页面id
  • char* data_:用于储存对应物理页面中的真实数据
  • int pin_count_:故名思意,该framepin count,表示被多少个进程pin住,当pin_count_不为0时,该frame不能被驱逐
  • bool is_dirty_:该frame是否被写过,如果被写过则需要将内容写回磁盘

在这个任务中,我们需要实现文件src/buffer/buffer_pool_manager.cpp中的以下方法:

  • FetchPage(page_id_t page_id)
  • UnpinPage(page_id_t page_id, bool is_dirty)
  • FlushPage(page_id_t page_id)
  • NewPage(page_id_t* page_id)
  • DeletePage(page_id_t page_id)
  • FlushAllPages()

个人建议的实现顺序为:FlushPage->FlushAllPages->UnpinPage->NewPage->FetchPage->DeletePage
接下来我介绍下我每个函数的实现思路

FlushPage

功能:将给定的缓存页写回磁盘,无视is_dirty_标志
参数:page_id表示给定的想要flush到磁盘的物理页id
返回值:bool,若page_id不存在,返回false;否则true
实现:BufferPoolManager类中需要维护一个page_table_,存放着每个已分配物理页对应的frame,通过page_table_查找到给定page_id对应的frame_id,然后调用Disk Scheduler提供的scheduler方法发出写请求即可,最后清空frameis_dirty_标志。

FlushAllPages

功能:将所有有效的缓存页写回磁盘,无视is_dirty_标志
参数:无
返回值:void
实现:遍历整个buffer的所有frame,若frame上的page_id不为空,则使用与FlushPage类似方法写回磁盘即可。

UnpinPage

功能:将指定的物理页对应的framepin_count减1
参数:page_id表示给定的物理页id,is_dirty表示在pin住frame时是否发生了写操作
返回值:bool,若指定的物理页id不存在,返回false;否则true
实现:首先根据page_id找到对应的frame,将framepin_count减1,此时若pin_count为0,还需调用LRU-K Replacer提供的SetEvictable函数设置frame的状态为可驱逐。然后,根据is_dirty参数设置frameis_dirty_成员即可。

NewPage

功能:找到一个空闲frame新分配一个物理页,并将该物理页的内容读取到刚找到的这个frame
参数:page_id_t *page_id分配的物理页id以参数形式返回
返回值:Page*表示新分配的物理页最终存放的frame地址
实现:找到空闲的frame首先从一个free list里面找,如果free list为空表明现在的buffer已满,需要使用LRU-K Replacer驱逐一个frame并将其作为新物理页的承载体(若该frameis_dirty_true,那么需要先将frame中的内容写回对应的物理页)。接着,调用AllocatePage函数分配新物理页,并设置frame中的相关成员即可。最后,需要调用LRU-K Replacer提供的RecordAccess函数记录下访问历史,并调用SetEvictable函数pin住frame

FetchPage

功能:给定物理页id,获取该物理页所对应的frame
参数:page_id表示给定的物理页id
返回值:Page*表示给定物理页所在的frame地址
实现:首先从page_table_中寻找给定物理页对应的frame,若未找到,则需要驱逐缓存页,这一块的处理与NewPage函数中驱逐的处理一致,代码可以复用;若找到则进行下一步。然后,将最终确定的frame记录访问历史pin住操作,也与NewPage中的操作一致。

DeletePage

功能:给定物理页id,将物理页对应的framebuffer中删除
参数:page_id表示给定的物理页id
返回值:bool,物理页不在buffer中或删除成功则返回true;物理页存在且对应的frame仍然被pin住(pin_count不为0)时,则返回false
实现:查找物理页对应的frame,将page_idpage_table_中移除,调用LRU-K ReplacerRemove函数将frame_idbuffer中移除,并将frame_id加入free_list_中,重置frame的成员,最后调用DeallocatePage将物理页回收

Optimizations

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1193680.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

切换数据库的临时表空间为temp1 / 切换数据库的undo表空间为 undotbs01

目录 ​编辑 一、切换临时表空间 1、登录数据库 2、查询默认临时表空间 3、创建临时表空间temp1(我们的目标表空间) 4、修改默认temp表空间 5、查询用户默认临时表空间 6、命令总结: 二、切换数据库的undo表空间 1、查询默认undo表…

护眼台灯横评|书客、明基、松下品牌大测评告诉你谁才是最亮的星!

护眼台灯哪个牌子好?随着护眼台灯普及率的日渐提高,护眼台灯市场也是十分火爆,但很多商家为了盈利,总是把重心放在宣传和营销手段上,从而导致护眼台灯的产品质量不过关,在使用过后不仅没有起到缓解眼睛疲劳…

【CASS精品教程】cass 3d基于osgb三维模型生成等高线的两种方法

对于植被、房屋稀少的地方,可以基于osgb模型直接生成等高线。本文讲解在cass11.0 3d中基于osgb三维模型生成等高线的两种方法。 一、加载osgb三维模型 二、生成等高线 1. 绘制等高线 cass11版本提供了绘制单个等高线的功能。 点击【绘制等高线】,提示输入等高距。 输入固定…

JVM中jhat虚拟机堆转储快照分析工具

jhat虚拟机堆转储快照分析工具 1、jhat jhat也是jdk内置的工具之一。主要是用来分析java堆的命令,可以将堆中的对象以html的形式显示出来,包括对 象的数量,大小等等,并支持对象查询语言。 使用jmap等方法生成java的堆文件后&a…

【考研数据结构代码题3】用栈实现十进制数转为八进制数

题目:将十进制数m1348转换成八进制数 难度:★ 算法思路:十进制转八进制的核心原理是“用辗转相除法不断对8取余,最后将余数反向输出”,即先求出来的余数后输出,符合“先进后出”的栈的特性,故设…

七个优秀微服务跟踪工具

随着微服务架构复杂性的增加,在问题出现时确定问题的根本原因变得更具挑战性。日志和指标为我们提供了有用的信息,但并不能提供系统的完整概况。这就是跟踪的用武之地。通过跟踪,开发人员可以监控微服务之间的请求进度,从而使他们…

C#基于inpoutx64读写ECRAM硬件信息

inpoutx64.dll分享路径: 链接:https://pan.baidu.com/s/1rOt0xtt9EcsrFQtf7S91ag 提取码:7om1 1.InpOutManager: using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServi…

多级缓存之缓存同步

缓存数据同步的常见方式有三种: 设置有效期:给缓存设置有效期,到期后自动删除。再次查询时更新 优势:简单、方便缺点:时效性差,缓存过期之前可能不一致场景:更新频率较低,时效性要…

d3.js

D3:Data-Driven Documents • 通过D3提供的接口来基于数据操控文档的各个图元。 标题对于D3(本讲解)最为重要的标签,主要操作的对象(画布) HTML - 导入D3.js D3.js作为JavaScript的外库,必须先将其导入,如: Python的…

[autojs]用户界面GUI编程

用户界面: UI视图: View attr(name, value)attr(name)whidgravitylayout_gravitymarginmarginLeftmarginRightmarginTopmarginBottompaddingpaddingLeftpaddingRightpaddingToppaddingBottombgalphaforegroundminHeightminWidthvisibilityrotationtransformPivotXtransformPivo…

移位操作符 位操作符详解

hello hello&#xff0c;想我了吗? &#x1f604;&#x1f604;&#x1f604; 首先是移位操作符&#xff1a;<< 左移操作符 >> 右移操作符 注&#xff1a;移位操作符的操作数只能是整数。 << 左移操作符&#xff1a;移位规则&#xff1a; 左边抛弃、…

我的AIGC部署实践03

我的AIGC部署实践03 这会是AIGC部署实践的第三回&#xff0c;用免费的GPU部署自己的stable-diffusion下面我们就开始吧。 1.创建项目 创建项目的镜像及数据集如下&#xff1a; 选择完成后点击创建&#xff0c;代码选择暂不上传。 2.初始化开发环境实例 点击最右侧的“开发…

服务器往客户端发送字符串的网络编程

服务器主要就是能够打开命令行提供的网络端口&#xff0c;然后一有客户端连接上&#xff0c;就会向客户端发送Welcome to Our Server!这段话。 服务器代码serverSayWelcome.c的代码如下&#xff1a; #include <stdio.h> #include <stdlib.h> #include <string.…

【ARM Trace32(劳特巴赫) 使用介绍 3 - trace32 访问运行时的内存】

请阅读【ARM Coresight SoC-400/SoC-600 专栏导读】 文章目录 1.1 trace32 访问运行时的内存1.1.1 侵入式 运行时内存访问1.1.2 非侵入式运行时访问1.1.3 缓存一致性的非侵入式运行时访问 1.2 Trace32 侵入式和非侵入式 运行时访问1.2.1 侵入式访问1.2.2 非侵入式运行时访问 1…

C++:关联式容器map的使用

1、map的简介 map是关联容器&#xff0c;它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素。 在map中&#xff0c;键值key通常用于排序和惟一地标识元素&#xff0c;而值value中存储与此键值key关联的内容。键值key和值value的类型可能不同&#xff0c;并…

【数据结构】树与二叉树(八):二叉树的中序遍历(非递归算法NIO)

文章目录 5.2.1 二叉树二叉树性质引理5.1&#xff1a;二叉树中层数为i的结点至多有 2 i 2^i 2i个&#xff0c;其中 i ≥ 0 i \geq 0 i≥0。引理5.2&#xff1a;高度为k的二叉树中至多有 2 k 1 − 1 2^{k1}-1 2k1−1个结点&#xff0c;其中 k ≥ 0 k \geq 0 k≥0。引理5.3&…

【Linux系统化学习】冯诺依曼体系结构 | 操作系统

个人主页点击直达&#xff1a;小白不是程序媛 Linux专栏&#xff1a;Linux系统化学习 目录 冯诺依曼体系结构 组成介绍 CPU和内存 以使用微信发消息为例理解冯诺依曼体系结构 操作系统 冯诺依曼体系结构 随着世界上第一台计算机ENIAC&#xff08;埃尼阿克&#xff09;的…

2、鸿蒙开发工具首次运行时开发环境配置

请务必在第一次运行时配置好开发环境&#xff0c;如果取消了配置&#xff0c;后续再配置会比较麻烦 1、点击工具图标运行 2、在欢迎页中点击“Agree” 3、默认“Do not import setting”&#xff0c;点击“OK” 3、此片设置Nodejs和Ohpm的安装&#xff0c;其中&#xff0c; …

传来喜讯,优维又获奖了!!!

优维科技作为国内DevOps领域的行业领先企业&#xff0c;从诞生之日起&#xff0c;就一直致力于为中国企业提供一流的数字化运维服务&#xff0c;不断深耕核心技术&#xff0c;向客户提供专业强大的产品与服务。多年来&#xff0c;不仅获得了大量客户认可&#xff0c;更是屡次获…