CMU15445 lab1 - BUFFER POOL

2023-05-16


本文为本人完成15445 2020fall(B+树版本)时的一些记录,仅作为备忘录使用。


TASK #1 - LRU REPLACEMENT POLICY

本任务为实现一个LRU页面置换策略,建立一个关于面向磁盘的数据库的基本的概念是很重要的,如下图:

截屏2022-10-01 20.45.06

从中可以看出,实际数据是持久化存储于磁盘之上的,执行引擎主要进行一些数据操作(读/写,也即对Page增删改查),而BufferPool则是介于执行引擎和磁盘之间,位于内存中,给执行引擎提供Page。由于存储器体系结构一般表现为内存容量远小于磁盘容量,因此BufferPool是无法加载整个db的所有Pages的,因此需要在合适的时机将Page写入磁盘中,LRU就决定了牺牲哪个Page(即将哪个Page写回到磁盘中),其中包含了局部性原理的思想。

在Buffer Pool中,Page是存放在frame中的,这是要注意的一个点(buffer pool就是一个能容放多个Page的vector)。

截屏2022-10-01 21.07.01

The size of the LRUReplacer is the same as buffer pool since it contains placeholders for all of the frames in the BufferPoolManager. However, not all the frames are considered as in the LRUReplacer. The LRUReplacer is initialized to have no frame in it. Then, only the newly unpinned ones will be considered in the LRUReplacer.

所要实现的接口主要是下面四个:

  • Victim(T*) : Remove the object that was accessed the least recently compared to all the elements being tracked by the Replacer, store its contents in the output parameter and return True. If the Replacer is empty return False.
  • Pin(T) : This method should be called after a page is pinned to a frame in the BufferPoolManager. It should remove the frame containing the pinned page from the LRUReplacer.
  • Unpin(T) : This method should be called when the pin_count of a page becomes 0. This method should add the frame containing the unpinned page to the LRUReplacer.
  • Size() : This method returns the number of frames that are currently in the LRUReplacer.

LRU的实现十分的简单,是经典的leetcode题,用list套一个unordered_map即可实现。

下面主要讲一下我对PinUnPin的理解:

  • Pin(T) : 将一个Page(frame)从LRU的list中剔除。即该Page(frame)被Buffer Pool所使用了,LRU不应该牺牲该页面。
  • Unpin(T) : 加入一个Page(frame)入LRU的list。即该页面Buffer Pool目前没人使用了,LRU根据策略决定该页面的去留。
  • Victim(T*) :意思很直接,LRU根据规则(最近最少使用)有选择性的牺牲一个页面(frame)。

并发的话,直接加大锁就好了。std::lock_guard是一种RAII的加锁方式,可以不用unlock(在析构的时候unlock),比较方便。给出Victim的实现方法,其他的应 Prof. Pavlo 要求就不放出来了。

bool LRUReplacer::Victim(frame_id_t *frame_id) {
  std::lock_guard<std::mutex> lock(latch_);
  if (id2iter_.empty()) {
    return false;
  }
  auto deleting_id = lru_list_.back();
  lru_list_.pop_back();
  id2iter_.erase(deleting_id);
  *frame_id = deleting_id;
  return true;
}

TASK #2 - BUFFER POOL MANAGER

第二个任务为构造一个Buffer Pool。

The BufferPoolManager is responsible for fetching database pages from the DiskManager and storing them in memory. The BufferPoolManager can also write dirty pages out to disk when it is either explicitly instructed to do so or when it needs to evict a page to make space for a new page.

实现以下几个接口:

  • FetchPageImpl(page_id)
  • NewPageImpl(page_id)
  • UnpinPageImpl(page_id, is_dirty)
  • FlushPageImpl(page_id)
  • DeletePageImpl(page_id)
  • FlushAllPagesImpl()

(其实可以先通过测试程序了解这几个接口怎么用的,然后再去实现会比较好!)

  • NewPageImpl(page_id):新建一个Page。
  • FetchPageImpl(page_id):获取一个Page。
  • UnpinPageImpl(page_id, is_dirty):解除对某个Page的使用(别的进程可能还在使用,pin_count为0的时候可以删除)
  • DeletePageImpl(page_id):删除一个Page。
  • FlushPageImpl(page_id):强制将某个Page写盘。
  • FlushAllPagesImpl():将所有Page写盘。

这个task其实本质上就是考验对下面两个点的理解,根据提示看看DiskManager 的API是比较好实现的:

  • Dirty Flag :当该flag为真时,该页被写过了,要写回磁盘。
  • Pin/Reference Counter:引用计数,当该计数为0时,将对应frame加入LRU中;当该计数不为0时,将对应frame从LRU中删除(即不参与LRU的替换)。

该task有几个坑需要注意一下:

  1. 重复UnpinPageImpl,但is_dirty标志不同。

    • 不是简单的赋值设置is_dirty标志,而是累计,即或一下。
    • page->is_dirty_ |= is_dirty;
  2. New完一个Page后,其pin_count为1,因此不要将这个Page放入LRU。

    • replacer_->Pin(fid);
  3. New完一个Page后,要立即刷盘。可能会有new完以后unpin(false)的情况,不刷盘这一页就丢失了

    • disk_manager_->WritePage(new_page->GetPageId(), new_page->GetData());
  4. 获取frame时,先从free list获取,再从lru中获取。

    • /**
       * @brief get a free page from free_list or lru_list
       *
       * @return frame_id_t frame id, -1 is error
       */
      frame_id_t BufferPoolManager::get_free_frame() {
        frame_id_t frame_id = -1;
        if (!free_list_.empty()) {
          frame_id = free_list_.front();
          free_list_.pop_front();
      
        } else {
          replacer_->Victim(&frame_id);
        }
        return frame_id;
      }
  5. 删除一个Page时,要保证free list和LRU中只存在一个fid,而不是两边都有。

    • replacer_->Pin(fid);
    • free_list_.emplace_back(fid);

由于是多线程的程序,可以多跑几次测试一下,通过日志排查出错的原因。

#!/usr/bin/env bash

trap 'exit 1' INT

echo "Running test $1 for $2 iters"
for i in $(seq 1 $2); do
    echo -ne "\r$i / $2"
    LOG="$i.txt"
    # Failed go test return nonzero exit codes
    $1 &> $LOG
    if [[ $? -eq 0 ]]; then
        rm $LOG
    else
        echo "Failed at iter $i, saving log at $LOG"
    fi
done

(gradescope上测试要是失败了可以直接偷测试文件,逃

若有概念不理解的可以翻翻课件。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CMU15445 lab1 - BUFFER POOL 的相关文章

  • 为什么Java NIO专门引入Buffer类而不是使用数组?

    有人问我一个问题 为什么字节数组不够用 NIO专门引入了一个类Buffer 这个问题的好答案是什么 它只是一种简化读 写操作的包装类吗 如果可能的话 请给我们举个例子来说明我们如何从中受益Buffer不能 很难用数组完成的类 None
  • NodeJS将64位无符号整数写入缓冲区

    我想以大端格式将 64 位 8 字节 大整数存储到 nodejs 缓冲区对象中 此任务的问题是 nodejs 缓冲区仅支持写入 32 位整数作为最大值 使用 buf write32UInt32BE value offset 所以我想 为什么
  • 如何刷新 Windows 中的所有文件缓冲区?

    有FlushFileBuffers Windows 中的 API 用于刷新缓冲区直至硬盘驱动器single文件 有sync Linux 中用于刷新文件缓冲区的 APIall files 但是 是否也有 WinAPI 用于刷新所有文件 即sy
  • JavaScript:以整数形式读取 3 个字节缓冲区

    假设我有一个十六进制数据流 我想将其分为 3 字节块 我需要将其作为整数读取 例如 给定一个十六进制字符串01be638119704d4b9a我需要读取前三个字节01be63并将其读取为整数114275 这就是我得到的 var sample
  • “未知”PHP 错误 - 这是什么意思? [复制]

    这个问题在这里已经有答案了 可能的重复 如何修复 PHP 中的 标头已发送 错误 https stackoverflow com questions 8028957 how to fix headers already sent error
  • 如何确定分配的 C 缓冲区的大小? [复制]

    这个问题在这里已经有答案了 我有一个缓冲区 想要进行测试以查看缓冲区是否有足够的容量 即找到可以添加到缓冲区的元素数量 char buffer char malloc sizeof char 10 Doing a int numElemen
  • 刷新jsp文件时线程锁定

    在重负载下 当 GZipping 和解压缩 JSP 文件时 我看到很多线程被锁定 线程转储如下所示 似乎来自大小为 14Kb 的 header jsp http 0 0 0 0 8080 304 daemon prio 3 tid 0x00
  • 从 ostream 获取 char* 而不进行复制

    我有一个ostream并且数据已写入其中 现在我想要该数据的形式char大批 有没有办法在不复制所有字节的情况下获取字符缓冲区及其大小 我的意思是 我知道我可以使用ostringstream并打电话str c str 但会产生一个临时副本
  • 保护字符串缓冲区免受两个线程的影响?

    我正在通过 Indy 套接字处理流数据包字符串 在客户端 我有一个线程从TIdTCPClient并将这些数据连续附加到单个字符串缓冲区的末尾 我有另一个线程从头开始连续读取该缓冲区 根据需要复制 和删除 数据 一次一个完整的数据包 我知道在
  • 字符串池:“Te”+“st”比“Test”快?

    我正在尝试一些有关字符串池的性能基准 然而 结果并不令人期待 我做了3个静态方法 Perform0 方法 每次都会创建一个新对象 Perform1 方法 字符串文字 Test Perform2 方法 字符串常量表达式 Te st 我的期望是
  • 有什么办法可以查看标准输入缓冲区吗?

    我们知道stdin默认情况下是缓冲输入 证明这一点的证据是使用任何 留下数据 的机制stdin 例如scanf int main char c 10 0 scanf 9s c printf s and left is d n c getch
  • 如果 CGImageCreate 的数据提供者使用应用程序创建的数组,那么正确的调用会是什么样子?

    我试图在内存中创建一个位图 作为 drawLayer inContext 方法 此方法是 CALayer 委托协议的一部分 将调用的模式函数的一部分 模式函数看起来与此类似 static const size t kComponentsPe
  • 在Python中将多个参数传递给pool.map()函数[重复]

    这个问题在这里已经有答案了 我需要某种方法来使用 pool map 中接受多个参数的函数 根据我的理解 pool map 的目标函数只能有一个可迭代作为参数 但有没有一种方法可以传递其他参数 在这种情况下 我需要传递一些配置变量 例如我的
  • BufferedWriter在java中如何工作

    我经常将文本输出到文件中 我想知道一件事 怎么办BufferedWriterwork 当我打电话时它会在文件中写入文本吗writer write text 如果不写文本 我需要使用flush函数来写数据吗 例如 File file new
  • UTF-16 十六进制解码 NodeJS

    我正在尝试将 UTF 16 十六进制 Hello 世界 解码为 NodeJS 中的字符串 我尝试通过从十六进制创建缓冲区来做到这一点 let vari new Buffer from 00 48 00 65 00 6C 00 6C 00 6
  • 将响应缓冲区转换为 JSON

    在 AWS 中 我使用 https 模块通过 Lambda 发出 get 请求 我能够返回数据 但当我调用时它是缓冲区格式的callback null obj https get options res gt res on data d g
  • 并行处理的ThreadPool和Pool

    有没有办法在 python 中同时使用 ThreadPool 和 Pool 来通过指定您希望使用的 CPU 和内核的数量来并行循环 例如 我将循环执行为 from multiprocessing dummy import Pool as T
  • 多处理池 - 如果一个进程返回所需的结果,如何取消所有正在运行的进程?

    给出以下 Python 代码 import multiprocessing def unique somelist return len set somelist len somelist if name main somelist 1 2
  • Emacs 退出终端

    在 Emacs 中运行终端模式时使用M x term using C x C o我无法切换到另一个缓冲区来继续处理事情 我知道这是可能的M x shell但使用此命令时 shell 的某些方面不起作用 less more 手册页等 我想知道
  • 推荐的增长缓冲区的方法?

    假设我正在 Node js 中构造一个可变长度的字符串或一系列字节 buf write 的文档说 https nodejs org api buffer html buffer buf write string offset length

随机推荐

  • react ant Design pro Umi 项目左上角icon不显示

    今天本地运行项目没有问题 xff0c 打包发到远端发现logo icon不显示了 然后找了找资料说 LayoutSettings 哪里logo用链接图片可以本地图片有时候会加载异常 解决方法 xff1a 找到 app tsx 加个logo
  • ZeroMQ发布-订阅模式的应用(C++)

    我使用的ZeroMQ版本是4 2 0 xff0c 应用的是其发布 订阅模式 应该知道的细节 xff1a PUB SUB套接字是慢连接 xff0c 你无法得知SUB是何时开始接收消息的 就算你先打开了SUB套接字 xff0c 后打开PUB发送
  • Ubuntu 问题记录(1)| 关于卸载以源码方式安装的库

    Ubuntu 使用源码安装 lib 后 xff0c 如果要卸载 xff0c 则在 lib build 路径下使用 sudo make uninstall 之后再用 sudo updatedb 更新一下 lib 库 xff0c 再使用 loc
  • 注意字符数组最后会自动加\0

    今天做了一道考研题 规定数组大小为200 但是我没注意到后尾需要加 0 后来果断没有A过去 很伤心 反复不断地尝试怎么都不行 后来经一位仁兄点拨 瞬间豁然 include lt iostream gt include lt cstdio g
  • 在TypeScript中使用parseInt()

    在使用angular写一些东西的时候 xff0c 需要用到parseInt 方法来将时间戳转换成时分秒 xx时 xx分 xx秒 的格式 xff0c 但是因为angular所使用的是Typescript xff0c 而 parseInt st
  • CAS6.2.x ~ 准备(1)

    前言 CAS 企业单点登录 xff0c 目前最新版本是6 2 x Apereo 的 Central Authentication Service xff0c 通常称为CAS CAS是用于web的企业多语言单点登录解决方案 xff0c 并试图
  • MySql 安装,root初始化密码设置

    MySQL下载地址 xff1a https dev mysql com downloads mysql 2 解压MySQL压缩包 将以下载的MySQL压缩包解压到自定义目录下 我的解压目录是 C mysql 8 0 12 winx64 34
  • Python游戏项目--外星人入侵(一)

    一 安装Pygame 在终端输入 xff1a pip install user pygame 二 开始游戏项目 xff08 1 xff09 创建Pygame窗口及响应用户输入 创建一个名为alien invasion py 的文件 xff0
  • SpringSecurity OAuth2 获取Token端点TokenEndpoint、Token授权TokenGranter接口 详解

    1 前言 在 授权服务器是如何实现授权的呢 xff1f 中 xff0c 我们可以了解到服务端实现授权的流程 xff0c 同时知道 xff0c 当授权端点AuthorizationEndpoint生成授权码时 xff0c 就会重定向到客户端的
  • Make文件中赋值等号的几种类型(:=,?=,=)

    今天有一位以前仅做过Android APP开发的同学突然间问我 xff0c 说Makefile中经常可以看见 xff1a 冒号等号 61 问号等号 61 和直接等号 61 这究竟有什么区别呢 xff1f 欢迎转载 xff0c 但是请注明原出
  • 支持nvidia GPU 的硬件编解码的ffmpeg编译记要

    支持nvidia GPU 的硬件编解码的ffmpeg编译记要 中间目录 xff1a out 1 x264 下载x264 stable zip unzip x264 stable zip cd x264 stable configure en
  • 软件工程学习笔记——第三周:结构化分析方法-1

    结构化分析方法的概念 结构化分析模型 结构化分析过程
  • GBK编码表

    说明 xff1a 比如第一个 34 顿号 34 的编码就是A1A2 GBK 汉字内码扩展规范 编码表 二 全国信息技术标准化技术委员会 汉字内码扩展规范 GBK Chinese Internal Code Specification 1 0
  • SSH 使用过程中,出现的问题以及解决办法

    1 ssh登陆提示 server unexpectedly closed network connection 在使用ssh登入Linux時 xff0c 卻發生了serverunexpectedly closed network conne
  • CentOS7安装vncserver

    1 关闭防火墙和selinux systemctl stop firewalld service setenforce 0 2 安装图形支持 yum groups install 34 GNOME Desktop 34 或yum group
  • Echarts tooltip加上单位并带着图例颜色

    模仿腾讯疫情地图 xff0c Y轴有个百分比 xff0c 也就是Y轴有单位 xff0c 使用JS代码如下 xff1a tooltip trigger 39 axis 39 formatter function params var relV
  • xv6调试

    窗口1作为xv6的运行窗口 make CPUS 61 1 qemu gdb 窗口2作为gdb调试窗口 gdb multiarch kernel kernel 进入gdb后执行 set confirm off set architecture
  • mit6.s081-21-Lab1/ Xv6 and Unix utilities

    sleep Implement the UNIX program sleep for xv6 your sleep should pause for a user specified number of ticks A tick is a
  • Python+scrcpy+pyminitouch实现自动化(四)——实现语音识别自动打卡机器人

    首先要去网上下载一个想要实现自动化的软件 xff0c 下载对应的apk后拖拉到虚拟器的页面即可实现自动下载 以上是对于AS打开的模拟器进行的下载安装 xff0c 由于我找不到关于x86的企业微信 xff0c 所以我就换了逍遥模拟器 xff0
  • CMU15445 lab1 - BUFFER POOL

    本文为本人完成15445 2020fall B 43 树版本 时的一些记录 xff0c 仅作为备忘录使用 TASK 1 LRU REPLACEMENT POLICY 本任务为实现一个LRU页面置换策略 xff0c 建立一个关于面向磁盘的数据