CMU 15-445 Project #1 - Buffer Pool(Task #3 - Buffer Pool Manager Instance)

news2024/11/26 8:49:30

Task #3 - Buffer Pool Manager Instance

  • 一、题目链接
  • 二、准备工作
  • 三、部分实现

在这里插入图片描述

一、题目链接


二、准备工作

见 CMU 15-445 Project #0 - C++ Primer 中的准备工作。


三、部分实现

首先要区分缓冲池中 PageFrame ,这个其实和操作系统分页管理中页面页框的关系是类似的。页框是内存中一个个实际的空间,但它只是空间,没有内容。而页面则是被放置在页框中的实际内容,同时每一个内存中的页面都有它的外存映像,他们共用同一个 page_id,并通过脏位标识数据回写。

此外,还有几个问题在实现时要注意:

  1. FetchPgImp 中不管页面是已经存在与缓冲池,还是通过LRU-K置换得到,都需要
  2. UnpinPgImp 中的脏位修改仅限于 false -> true 的单向修改,因为一个页面脏位 true -> false 的修改必须与外存回写 WritePage 配合。
  3. DeletePgImp 中在进行删除前也要通过脏位判断是否需要回写。

NewPgImp

auto NewPgImp(page_id_t *page_id) -> Page * override {
    std::scoped_lock<std::mutex> locker(latch_);

    frame_id_t frame_id = 0;  // 用于记录分配给新页面的页框号

    /* 如果空闲链表不为空,直接从空闲链表中获取一个空的页框来初始化页面;
     * 否则需要通过LRU-K淘汰现有page,然后在对应frame中新建page。 */
    if (!free_list_.empty()) {
        /* 从空闲链表中获取frame_id */
        frame_id = free_list_.front();
        free_list_.pop_front();
    } else {
        /* 通过LRU-K获取应该被淘汰的页框 */
        if (!replacer_->Evict(&frame_id)) {
            *page_id = INVALID_PAGE_ID;
            return nullptr;
        }

        /* 如果脏位为true需要进行回写 */
        if (pages_[frame_id].IsDirty()) {
            disk_manager_->WritePage(pages_[frame_id].GetPageId(), pages_[frame_id].GetData());
        }

        /* 从page_table_删除页面和页框之间的映射 */
        page_table_->Remove(pages_[frame_id].GetPageId());
    }

    /* 获取页面编号 */
    *page_id = AllocatePage();

    /* 初始化页面元数据 */
    pages_[frame_id].page_id_ = *page_id;
    pages_[frame_id].pin_count_++;
    pages_[frame_id].is_dirty_ = false;

    /* 在可扩展哈希表中建立page_id与frame_id的编号 */
    page_table_->DoInsert(*page_id, frame_id);

    /* 记录指定页框的访问并将该页框设置为不可驱逐 */
    replacer_->RecordAccess(frame_id);
    replacer_->SetEvictable(frame_id, false);

    return pages_ + frame_id;
}

FetchPgImp

auto FetchPgImp(page_id_t page_id) -> Page * override {
    std::scoped_lock<std::mutex> locker(latch_);

    int frame_id;  // 待操作的页框号

    /* 如果待查找页面位于缓冲池,直接返回即可 */
    if (page_table_->Find(page_id, frame_id)) {
        /* 增加页面访问次数 */
        pages_[frame_id].pin_count_++;

        /* 记录指定页框的访问并将该页框设置为不可驱逐 */
        replacer_->RecordAccess(frame_id);
        replacer_->SetEvictable(frame_id, false);

        return pages_ + frame_id;
    }

    /* 如果空闲链表不为空,直接从空闲链表中获取一个空的页框来初始化页面;
     * 否则需要通过LRU-K淘汰现有page,然后在对应frame中新建page。 */
    if (!free_list_.empty()) {
        /* 从空闲链表中获取frame_id */
        frame_id = free_list_.front();
        free_list_.pop_front();
    } else {
        /* 通过LRU-K获取应该被淘汰的页框 */
        if (!replacer_->Evict(&frame_id)) {
            return nullptr;
        }

        /* 如果脏位为true需要进行回写 */
        if (pages_[frame_id].IsDirty()) {
            disk_manager_->WritePage(pages_[frame_id].GetPageId(), pages_[frame_id].GetData());
        }

        /* 从page_table_删除页面和页框之间的映射 */
        page_table_->Remove(pages_[frame_id].GetPageId());
    }

    /* 初始化页面元数据 */
    pages_[frame_id].page_id_ = page_id;
    pages_[frame_id].is_dirty_ = false;
    pages_[frame_id].pin_count_++;

    /* 写入页面的数据 */
    disk_manager_->ReadPage(page_id, pages_[frame_id].GetData());

    /* 在可扩展哈希表中建立page_id与frame_id的编号 */
    page_table_->DoInsert(page_id, frame_id);

    /* 记录指定页框的访问并将该页框设置为不可驱逐 */
    replacer_->RecordAccess(frame_id);
    replacer_->SetEvictable(frame_id, false);

    return pages_ + frame_id;
}

UnpinPgImp

auto UnpinPgImp(page_id_t page_id, bool is_dirty) -> bool override {
    std::scoped_lock<std::mutex> locker(latch_);

    int frame_id;  // 待操作的页框号

    /* 查询并修改缓冲池中指定页面的信息 */
    if (page_table_->Find(page_id, frame_id)) {
        /* 如果当前页面pin_count_已经为0直接返回false */
        if (pages_[frame_id].GetPinCount() == 0) {
            return false;
        }

        /* 这里的脏位变换只支持从false到true,从true到false需要与回写配合 */
        if (!pages_[frame_id].IsDirty() && is_dirty) {
            pages_[frame_id].is_dirty_ = true;
        }

        /* 如果当前操作使得pin_count_值为0,需要将对应页面设置为可驱逐。 */
        if (--pages_[frame_id].pin_count_ == 0) {
            replacer_->SetEvictable(frame_id, true);
        }

        return true;
    }

    return false;
}

FlushPgImp

auto FlushPgImp(page_id_t page_id) -> bool override {
    std::scoped_lock<std::mutex> locker(latch_);

    int frame_id;  // 待操作的页框号

    /* 如果指定页面存在且脏位为true需要进行回写 */
    if (page_table_->Find(page_id, frame_id)) {
        if (pages_[frame_id].IsDirty()) {
            disk_manager_->WritePage(pages_[frame_id].GetPageId(), pages_[frame_id].GetData());
            pages_[frame_id].is_dirty_ = false;
        }

        return true;
    }

    return false;
}

FlushAllPgsImp

void FlushAllPgsImp() override {
    std::scoped_lock<std::mutex> locker(latch_);

    /* 依次回写所有的脏页 */
    for (int frame_id = 0; frame_id < static_cast<int>(pool_size_); frame_id++) {
        if (pages_[frame_id].GetPageId() != INVALID_PAGE_ID && pages_[frame_id].IsDirty()) {
            disk_manager_->WritePage(pages_[frame_id].GetPageId(), pages_[frame_id].GetData());
            pages_[frame_id].is_dirty_ = false;
        }
    }
}

DeletePgImp

auto DeletePgImp(page_id_t page_id) -> bool override {
    std::scoped_lock<std::mutex> locker(latch_);

    int frame_id;  // 待操作的页框号

    if (page_table_->Find(page_id, frame_id)) {
        /* 无法删除被固定的页面 */
        if (pages_[frame_id].GetPinCount() > 0) {
            return false;
        }

        /* 如果脏位为true需要进行回写 */
        if (pages_[frame_id].IsDirty()) {
            disk_manager_->WritePage(pages_[frame_id].GetPageId(), pages_[frame_id].GetData());
        }

        /* 从page_table_和replacer_中删除页面的相关信息 */
        page_table_->Remove(page_id);
        replacer_->Remove(frame_id);

        /* 重置页面的在内存中的缓存和元数据 */
        pages_[frame_id].ResetMemory();
        pages_[frame_id].page_id_ = INVALID_PAGE_ID;
        pages_[frame_id].is_dirty_ = false;
        pages_[frame_id].pin_count_ = 0;

        /* 将页框归还给空闲链表 */
        free_list_.emplace_back(frame_id);

        /* 重置页面在外存中的数据 */
        DeallocatePage(page_id);

        return true;
    }

    return true;
}

提交后的结果如下,所有测试用例全部通过,由于没有对并发性能进行优化,所以执行效率一般。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

尚硅谷微信小程序开发 防网易云音乐App 小程序 后端接口服务器搭建

小程序学习 尚硅谷微信小程序开发 项目网易云小程序学习地址&#xff1a; 01-尚硅谷-小程序-课程介绍_哔哩哔哩_bilibili 视频相关的教程文档与笔记分享 链接&#xff1a;https://pan.baidu.com/s/1aq7ks8B3fJ1Wahge17YYUw?pwd7oqm 提取码&#xff1a;7oqm 配套服务器 老师…

C语言总结

C语言 预处理&#xff08;以#开头&#xff09; 宏定义 宏可以理解为替换&#xff0c;替换过程不会进行语法检查&#xff0c;语法检查在编译时进行。只替换只替换只替换 1.不带参数的宏定义&#xff1a; 宏定义又称为宏代换、宏替换&#xff0c;简称“宏”。实质为直接替换&…

java面经03-虚拟机篇-jvm内存结构垃圾回收、内存溢出类加载、引用悲观锁HashTable、引用finalize

文章目录 虚拟机篇1. JVM 内存结构2. JVM 内存参数3. JVM 垃圾回收4. 内存溢出5. 类加载6. 四种引用7. finalize 虚拟机篇 1. JVM 内存结构 要求 掌握 JVM 内存结构划分尤其要知道方法区、永久代、元空间的关系 结合一段 java 代码的执行理解内存划分 执行 javac 命令编译源…

力扣 2719. 统计整数数目

题目地址&#xff1a;https://leetcode.cn/problems/count-of-integers/ 递归核心是枚举统计&#xff0c;结合记忆化搜索节省时间。 以数字 3216 为例&#xff0c;从 [0, 0, 0, 0] 开始枚举&#xff0c;到 [2, 1, 6, X] 时&#xff0c;i 2&#xff0c;sum 2 1 6 9&#x…

Meta语音达LLaMA级里程碑!开源MMS模型可识别1100+语言

【新智元导读】Meta的大规模多语言语音 &#xff08;MMS&#xff09; 项目将彻底改变语音技术&#xff0c;使用wav2vec 2.0的自监督学习&#xff0c;MMS将语音技术扩展到1100到4000种语言。 在语音方面&#xff0c;Meta又达到了另一个LLaMA级的里程碑。 今天&#xff0c;Meta推…

Linux驱动:I2C驱动看这一篇就够了

I2C驱动看这一篇就够了 一、前言二、Linux 的 I2C 体系结构2.1 Linux I2C 核心2.2 Linux I2C 适配器驱动2.3 Linux I2C 设备驱动2.4 Linux I2C驱动总结 三、具体设备驱动分析3.1 Probe函数3.2 读写函数 四、I2C驱动中几个重要的结构体4.1 i2c_adapter 结构体4.2 i2c_client 结构…

管理类联考——英语——技巧篇——必考高频词组

考研英语必考高频词组 【介词名词形式】 第一组 by accident 偶然 on account of 因为&#xff0c;由于 in addition 另外 in addition to 除……之外 in the air 在流行中&#xff0c;在传播中 on (the/an) average 平均&#xff0c;一般来说 on the basis o…

华为的数通认证考试难不难?考试费用是多少?

自从网络出现在我们的世界后&#xff0c;人类社会发生了巨大的变化&#xff0c;我们每个人的生活和网络息息相关&#xff0c;传统的购物、出行、社交方式发生了巨大的变化&#xff0c;这一切都离不开数通技术的支持&#xff0c;数通一般是指计算机通信网络中数据信号的基带传输…

春招面了个字节拿 36K 出来的,让我见识到了基础的天花板

今年的春招基本已经进入大规模的开奖季了&#xff0c;很多小伙伴收获不错&#xff0c;拿到了心仪的 offer。 各大论坛和社区里也看见不少小伙伴慷慨地分享了常见的面试题和八股文&#xff0c;为此咱这里也统一做一次大整理和大归类&#xff0c;这也算是划重点了。 俗话说得好…

Unity中Camera参数—Culling Mask详解

Culling Mask 如下图所示&#xff1a; 显示层级如下&#xff1a; 应用&#xff1a; Culling Mask &#xff1a;主要是相机针对不同层级的物体进行渲染的操作&#xff08;想让相机渲染哪个层就勾选哪个层&#xff09; 层级介绍&#xff1a; unity中的层前7个被unity锁定&#…

第三篇:分治算法

第三篇&#xff1a;分治算法 1. 分治算法简介2. 递归算法框架模板3. 分治演示代码4. 递归算法经典案例 分治算法的思想是将大问题分解成小问题&#xff0c;解决完一个一个小问题便解决了大问题。比如&#xff0c;我们想从杭州出发到徐州&#xff0c;可以分解成杭州到南京&#…

科技云报道:济南公交热线96190背后的“数字力量”

科技云报道原创。 “喂&#xff0c;公交公司吗&#xff1f;我的手提包落在63路车上了&#xff0c;能帮我找一下吗&#xff1f;” “我们小区距离公交站比较远&#xff0c;能增加个公交线路吗&#xff1f;” “等了半天车都不来&#xff0c;公交车为啥这么难等&#xff1f;”…

计算机网络实验---思科模拟器

文章目录 1. 组建小型局域网2. 交换机的配置与管理实验3&#xff1a;交换机划分 Vlan实验4&#xff1a;路由器的基本配置实验5&#xff1a;静态路由实验7&#xff1a;动态路由 1. 组建小型局域网 需要一台交换机&#xff0c;两台PC&#xff0c;连线连起来 配置 PC0 和 PC1 配置…

【大数据之Hive】十二、Hive-HQL查询之分组、join、排序

一、分组 1 group by 语句 group by 通常和聚合函数一起使用&#xff0c;按照一个或多个列的结果进行分组&#xff0c;任何对每个租执行聚合操作。   用group by时&#xff0c;select中只能用在group by中的字段和聚合函数。 --计算emp每个部门中每个岗位的最高薪水&#x…

C++ 设计模式----“单一职责“模式

二、“单一职责”模式 在软件组件的设计中&#xff0c;如果责任划分的不清晰&#xff0c;使用继承得到的结果往往是随着需求的变化&#xff0c;子类急剧膨胀&#xff0c;同时充斥着重复代码&#xff0c;这时候的关键是划清责任。  典型模式 • Decorator • Bridge 【1】D…

RabbitMQ高阶使用延时任务

目录 1 从打车开始说起1.1 需要解决的问题1.1.1 打车超时 2 延时任务2.1 什么是延时任务2.1.1 和定时任务区别 2.2 延时队列使用场景2.3 常见方案2.3.1 数据库轮询2.3.1 JDK的延迟队列2.3.3 netty时间轮算法2.3.4 使用消息队列 2.4 延时队列2.4.1 TTL(消息过期时间) 2.4.1.1 配…

第七十五天学习记录:高等数学:定积分(宋浩板书)

定积分是微积分中的一个重要概念&#xff0c;表示在给定区间上函数曲线下的面积或有向曲线与坐标轴围成的面积。定积分通常用符号 ∫ 来表示&#xff0c;具体形式为 ∫f(x) dx。 对于给定的函数 f(x) 和区间 [a, b]&#xff0c;定积分的计算可以通过求函数 f(x) 在该区间上的原…

【C++】STL的vector容器

目录 2、vector容器 1.1模板实例化 1.2定义与初始化vector对象 2.1vector构造函数 2.2vector赋值操作 2.2vector的容量和大小 2.4vector的插入 2.5vector的删除 2.6vector数据存取 2.7vector互换容器 2.8vector预留空间 2、vector容器 vector是C最常用的容器之一&a…

深度学习(神经网络)

文章目录 神经网络历史形式神经元模型&#xff08;M-P模型&#xff09;感知器多层感知器 误差反向传播算法误差函数和激活函数误差函数二次代价函数交叉熵代价函数 激活函数sigmoid函数RELU函数 似然函数softmax函数 随机梯度下降法批量学习方法在线学习小批量梯度下降法 学习率…

<Linux开发>驱动开发 -之-阻塞、非阻塞IO和异步通知

&#xff1c;Linux开发&#xff1e;驱动开发 -之-阻塞、非阻塞IO和异步通知 交叉编译环境搭建&#xff1a; &#xff1c;Linux开发&#xff1e; linux开发工具-之-交叉编译环境搭建 uboot移植可参考以下&#xff1a; &#xff1c;Linux开发&#xff1e; -之-系统移植 uboot移…