【CMU15-445 FALL 2022】Project #1 - Buffer Pool

About

  • 实验官网 Project #1 - Buffer Pool
  • 在线评测网站 gradescope

Lab

Task #1 - Extendible Hash Table

  • 详见——【CMU15-445 FALL 2022】Project #1 - Extendable Hashing
    • 如果链接失效,请查看当前平台我之前发布的文章。

Task #2 - LRU-K Replacement Policy

Concept

相关参考

  • LRU-K和2Q缓存算法介绍
  • LRU之预读失效和缓存污染
  • 什么是 LRU 算法?

什么是LRU?

  • 是一种缓存淘汰机制,全称为Least Recently Used,即最近最少使用算法。
  • 当缓存满了的时候,会将当前最久没被使用过的元素从缓存中踢出,给新进来的数据腾出空间。
  • 详见下示例

  • LRU缓存污染问题?
    • 因为LRU算法被将数据添加到缓存中的条件是最近访问一次即可, 如果当前有大量数据被访问,将缓存中我们高频访问的数据挤了出去,而这些数据在很长的一段事件内斗不会在被访问了,这就造成了缓存污染。

什么是LRU-K替换策略?

  • 在LRU基础上增加了K次的限制,为了解决缓存污染。
    • 相比与LRU算法,LRU-K需要两个队列来统计数据的访问,一个历史访问队列和一个缓存队列,只有当数据被访问了K次,才会被加入到缓存队列中。
    • 未到达K次访问的,按照LRU,FIFO淘汰,即最久没被访问过的先淘汰,如上面LRU图所示。
      • 但是在本实验的代码实现中,我们并不需要这样,对于未达到进入缓存队列次数的,仅仅更新访问次数即可, 无需变更在历史队列中的位置。

补充

  • 可以先做一下leetcode的这道题——146. LRU 缓存
    • 使用list存,unordered_map存list结点,用于快速查找定位。

Member

Member Var

  • curr_ size _
    • 可以驱逐出的帧的数量
  • replacer_ size _
    • frame_ id _的取值范围
  • k_
    • 进入缓存队列的访问次数限制
  • std::mutex latch_;
    • 互斥锁

下面是一些额外的辅助变量(不是必须得,需要根据你的具体实现来选择。)

  • m_is_evictable_;
    • 帧是否可被驱逐
  • m_access_count_
    • 帧的访问次数记录
  • m_cache_list _ && m_cache map
    • 缓存"队列"(实际上是链表,哈希表是为了快速定位链表中的指定结点)
  • m_history_list _&& m_history_map _
    • 历史"队列"。

Member Function

  • *auto Evict(frame_id_t frame_id) -> bool;
    • 尝试驱逐帧
      • 如果有可驱逐的,将驱逐帧存储到参数frame_id中,并返回true
      • 反之,返回false
    • 先从历史队列中尝试驱逐,然后再从缓存队列中尝试驱逐。

  • void RecordAccess(frame_id_t frame_id) ;
    • 记录当前帧的访问
      • 根据出现的次数进行之后的操作。注意更新当前帧的访问次数。
        • 等于k_次,即可将该帧从历史队列中放入缓存队列中,放在最新访问的位置(即,头或尾,这取决于你的实现,哪边是最久访问,哪边是最新访问。)
        • 大于k_次,将更新在缓存队列中的位置,即放在最新访问的位置。
        • 小于k_次,注意: 如果是第一次出现,

  • void SetEvictable(frame_id_t frame_id, bool set_evictable);
    • 设置可驱逐标志。
      • 判断给定frame_id是否合法 & 存在。
        • 根据原来的状态与要变更的状态,更新当前可驱逐帧的数量。
        • 最后更新该帧状态。

  • void Remove(frame_id_t frame_id);
    • 删除指定帧的访问记录。
      • 判断给定frame_id是否合法 & 存在。
        • 判断是否是可驱逐的,不可驱逐的,也不能删除。
        • 根据该帧的访问次数,判断从历史队列中删除还是在缓存队列中删除。
        • 更新可驱逐帧的数量。

  • auto LRUKReplacer::Size() -> size_t;
    • 返回当前可回收帧的数量。

Example

下面做一个简单示例

  • ①先依次访问A B C D E

  • ②再访问 A 2次

  • ③再访问 D 2次

  • ④再访问 B 1次

  • ⑤再访问 A 1次

  • ⑥尝试驱逐

  • ⑦尝试驱逐


Task #3 - Buffer Pool Manager Instance

Concept

相关视频

  • 我不是匠人——【CMU15-445/645】2022年Project 1缓冲池管理Buffer Pool Management

buffer pool的目的

  • 缓存池为了弥补磁盘和内存之间访问速度的巨大差异,提高数据库性能。
  • 把硬盘上的文件页读到内存池中,交够执行器进行后续的操作

内存与硬盘

  • Dircetory 几号页在文件的什么位置

缓存池的组成

  • page_table的key为物理存储页对应的value是缓存池中的页。

  • 磁盘上叫page,缓存池中叫frame
  • 使用ExtendebleHashTable将page_id映射到frame_id
  • 使用LRUKReplacer类跟踪页面对象何时被访问,以便在必须释放一个帧以腾出空间从磁盘复制新的物理页面时,它可以决定驱逐哪个对象。

page和frame是什么关系?

  • frame_id 与page_id
    • page_id是所对应的物理页id,frame_id是对应的内存中的缓冲池的页面id
  • free_list: 缓冲池中空闲的frame,如果没有可驱逐的,无法创建新页面。有可驱逐的,再检查是否有空闲的frame。
  • pages_数组中的索引即frame_id,每个Page即pages_[i]存储frame_id对应的page_id等信息。

Members

Member var

  • pool_size_
    • 缓冲池中的页数,即pages_的最大大小。
  • next_page_id_
    • 要分配的下一个page_id。
  • bucket_size_
    • 可扩展哈希中的每个桶的最大元素容量。
  • pages_
    • 缓冲池页数组,fame_id即为其下标索引。
  • page_table_
    • 用于跟踪缓冲池页面的页表。用于查询是否存在指定id
  • replacer_
    • 替换器,用于替换的未固定页面。
  • free_list_
    • 空闲页面链表。
  • latch_
    • 并发锁。

Member Function

  • *auto NewPgImp(page_id_t page_id) -> Page * override;
    • 功能
      • 在缓冲池中创建新页面。将 page_id 设置为新页面的 id。
      • 首先,如果所有框架当前都在使用且不可逐出,直接返回nullptr
        • 之后,检查空闲列表中是否有可用的。
          • 没有则尝试开始驱逐,即没被引用的。
            • 并且这个要注意被驱逐的是否有脏页标记,有则写回硬盘。最后重置该块内存。
              • 同时更新相关信息,如pages_信息,LRU-K信息(添加访问记录,设置为不可驱逐),以及在哈希表中的映射信息。
    • 参数
      • page_id: 本次创建出的页面的id
    • 返回
      • 如果无法创建新页面,则return nullptr,否则指向新页面的指针。

  • auto FetchPgImp(page_id_t page_id) -> Page * override;
    • 功能
      • 从缓冲池拿一个页面。
        • 如果找到这个page_id对应的frame_id
          • 返回对应的page地址
        • 没找到则创建
          • 检查是否有可驱逐页面,如果所有框架当前都在使用且不可逐出,直接返回nullptr
          • 之后,检查空闲列表中是否有可用的。
            • 没有则尝试开始驱逐,即没被引用的。
            • 并这个要注意被驱逐的是否有脏页标记,有则写回硬盘。最后重置该块内存。
            • 调用disk_manager_->ReadPage()从磁盘读取页面,
            • 同时更新相关信息,如pages_信息,LRU-K信息(添加访问记录,设置为不可驱逐),以及在哈希表中的映射信息。
    • 参数
      • 指定的page_id,即frame_id对应的物理页id
    • 返回值
      • 找到返回指向指定页面的指针,反之尝试创建,无法创建返回nullptr,否则返回指向新页面的指针。

  • auto UnpinPgImp(page_id_t page_id, bool is_dirty) -> bool override;
    • 从缓冲池中取消固定目标页。
      • 如果page_id不在缓冲池中或其引用数已为 0,则返回 false。
      • 递减页面的引用数。如果引用数达到 0,设置该frame可以被驱逐。
      • 注意: 如果传进来的参数is_dirty为真,才赋值。
    • 参数
      • 要取消固定的页面的page_id ID
      • 脏页标记is_dirty
    • 返回
      • 如果页面不在此调用中或其引脚计数为 <= 0,则为 false,否则为 true

  • auto FlushPgImp(page_id_t page_id) -> bool override;
    • 功能
      • 将目标页刷新到磁盘。
      • 使用 DiskManager::WritePage() 方法将页面刷新到磁盘,而不考虑脏标志。
        • 刷新后取消设置页面的脏标志。
    • 参数
      • page_id要刷新的页面的 ID
        • 不能是INVALID_PAGE_ID
    • 返回
      • 如果该page_id为INVALID_PAGE_ID,或者在页表中找不到该页,返回false,否则返回 true

  • void FlushAllPgsImp() override;
    • 功能
      • 将缓冲池中的所有页面刷新到磁盘。

  • auto DeletePgImp(page_id_t page_id) -> bool override;
    • 功能
      • 从缓冲池中删除页面。
      • 如果page_id不在缓冲池中,则不执行任何操作并返回 true。如果页面已固定且无法删除(即被引用),请立即返回 false。
      • 删除在哈希表中的映射记录,删除LRU-K替换器中的记录,重置对应的page信息,将该frame_id放到空闲队列中。
    • 参数
      • page_id:要删除的页面的ID
    • 返回值
      • 如果页面存在但无法删除,则为 false。
      • 如果页面不存在或删除成功,则为 true。

Complement

scoped_lock

C++17新特性,RAII机制的并发编程技巧

  • 构造时获取锁,析构时释放锁。
  std::scoped_lock<std::mutex> lock(latch_);
  • 相关参考
    • C++编程技巧:Scoped Locking
    • std::scoped_lock

enable_if & constexpr if

enable_if

以下内容来源于ChatGPT

  • C++的enable_if是一个模板元编程工具,用于在编译时根据条件来选择是否启用或禁用特定的函数模板。它可以与函数模板、类模板和模板别名一起使用。
  • enable_if通过在函数模板的返回类型中使用模板参数作为条件来工作。
    • 当条件为true时,返回类型有效并启用函数模板;
    • 当条件为false时,enable_if会导致编译器选择其他重载或者删除该函数模板。

示例如下所示:

#include <iostream>
#include <type_traits>// 函数模板,仅当T是整数类型时才可用
template <typename T>
typename std::enable_if<std::is_integral<T>::value, void>::type
printNumber(T number) {std::cout << "Number: " << number << std::endl;
}// 函数模板,仅当T是浮点类型时才可用
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, void>::type
printNumber(T number) {std::cout << "Number: " << number << std::endl;
}int main() {printNumber(10);        // 调用第一个printNumber模板printNumber(3.14);      // 调用第二个printNumber模板printNumber("Hello");   // 错误,没有匹配的模板可用return 0;
}
  • 在上面的示例中,我们定义了两个重载的函数模板printNumber,分别处理整数和浮点数类型。enable_if用于在编译时选择正确的模板。
    • 对于整数类型,std::is_integral::value为true,因此第一个函数模板会被选择。
    • 对于浮点数类型,std::is_floating_point::value为true,因此第二个函数模板会被选择。
    • 如果我们尝试传递一个非数字类型(如字符串),则会导致编译错误,因为没有匹配的模板可用。
  • enable_if还可以与其他模板元编程技术结合使用,例如std::enable_if_t、std::conditional等,以实现更复杂的条件选择和类型推导。

constexpr if

以下内容来源于ChatGPT

  • constexpr if 是 C++17 中引入的编译时条件分支语句,用于在编译时根据条件选择是否编译特定的代码块。它允许根据常量表达式的结果来进行静态分支,以在编译时执行不同的代码路径。
    • constexpr if 在编译时进行条件分支,并且不满足条件的分支将不会被编译。这意味着,不满足条件的代码块不会生成任何编译产物,包括生成的机器指令和相关的类型和符号。
  • constexpr if 的语法结构如下:
if constexpr (条件)
{// 编译时满足条件时执行的代码块
}
else
{// 编译时条件不满足时执行的代码块
}

以下是一个使用 constexpr if 的示例:

#include <iostream>template<typename T>
void printValue(T value)
{if constexpr (std::is_integral<T>::value){std::cout << "Integral value: " << value << std::endl;}else if constexpr (std::is_floating_point<T>::value){std::cout << "Floating point value: " << value << std::endl;}else{std::cout << "Other type value." << std::endl;}
}int main()
{printValue(42);          // 编译时选择第一个代码块printValue(3.14);        // 编译时选择第二个代码块printValue("Hello");     // 编译时选择第三个代码块return 0;
}
  • 在上述示例中,printValue 函数根据传递的值的类型使用 constexpr if 进行条件判断。
    • 如果类型是整数类型,则选择第一个代码块输出整数值;
    • 如果类型是浮点类型,则选择第二个代码块输出浮点值;
    • 否则选择第三个代码块输出其他类型的值。
    • 在编译时,只有符合条件的代码块会被编译,而不满足条件的代码块不会产生任何代码。
  • constexpr if 的好处是它可以在编译时进行静态分支,避免了运行时的开销。它还可以用于编写更加通用和灵活的模板代码,根据不同的条件生成不同的代码逻辑。

different

  • constexpr ifenable if 是两个不同的C++特性,用于在编译时根据条件选择代码路径,但它们在语法和使用上有一些区别。

  1. 语法差异:
    • constexpr if 是C++17引入的新特性,使用关键字 if constexpr。它允许在代码块中使用条件语句,并根据条件在编译时选择性地编译不同的代码路径。
    • enable if 是一个模板元编程工具,使用 typename std::enable_if<condition, T>::type 的形式将其应用于模板参数或函数返回类型。它用于在编译时基于类型或条件启用或禁用函数模板。
  2. 应用范围:
    • constexpr if 可以在任何函数中使用,包括普通函数和模板函数。它允许对常量表达式进行静态分支,并且可以在编译时决定不同的代码路径。
    • enable if 通常与模板函数一起使用,用于在编译时根据类型或条件启用或禁用特定的模板函数。它主要用于模板元编程和SFINAE(Substitution Failure Is Not An Error)技术。
  3. 使用场景:
    • constexpr if 适用于需要在编译时进行条件分支的情况,例如根据类型或常量表达式的值执行不同的代码路径。
    • enable if 适用于需要在模板函数中根据类型或条件启用或禁用特定实例化的情况。它通常用于模板函数的重载和模板参数的限制。
  • 总的来说,constexpr ifenable if 是两个不同的特性,适用于不同的场景。constexpr if 提供了在编译时进行条件分支的能力,而 enable if 是用于模板元编程和SFINAE技术的工具,用于在编译时选择特定的模板函数或模板参数。

补充

  • C++17 之 “constexpr if”
  • C++11 中 enable_if 的三种用法

Last

P1 拖了好久才完成,在公司实习时弄了一些,之后回学校实训弄了一些,最后还是参考了别人的代码,后面的内容要加速了。

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

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

相关文章

YOLOv5基础知识

定位和检测: 定位是找到检测图像中带有一个给定标签的单个目标 检测是找到图像中带有给定标签的所有目标 图像分割和目标检测的区别&#xff1a; 图像分割即为检测出物体的完整轮廓&#xff0c;而目标检测则是检测出对应的目标。&#xff08;使用框框把物体框出来&#xff…

SAP客制化区域菜单和IMG配置清单

1. 自定义区域菜单 事务代码 SE43&#xff0c;操作如下 添加菜单对象 展示效果 输入区域菜单名称并回车&#xff0c;效果如下 2. 自定义IMG配置 事务代码 SIMGH IMG structure 示例-事务代码入口 示例-表格维护入口 示例-自定义代码控制对象 需要创建dummy表并设置表维护 页面设…

Progressive Dual-Branch Network for Low-Light Image Enhancement 论文阅读笔记

这是22年中科院2区期刊的一篇有监督暗图增强的论文 网络结构如下图所示&#xff1a; ARM模块如下图所示&#xff1a; CAB模块如下图所示&#xff1a; LKA模块其实就是放进去了一些大卷积核&#xff1a; AFB模块如下图所示&#xff1a; 这些网络结构没什么特别的&#xf…

分布式光伏监控系统运维系统实时查看数据分布式光伏电站监控管理

光伏电站是一种利用太阳能发电的设施&#xff0c;随着人们对可再生能源的需求不断增加&#xff0c;光伏电站的建设也越来越普遍。但是&#xff0c;光伏电站的运营和管理需要高质量的监控系统来确保其正常运行。本文将介绍光伏电站监控系统的组成及其原理。 详细软件具体需求可…

【二等奖方案】基于人工智能的漏洞数据分类赛题「道可道,非常道」团队解题思路

2022 CCF BDCI 大赛 数字安全公开赛「基于人工智能的漏洞数据分类」赛题二等奖团队「道可道&#xff0c;非常道」战队获奖方案&#xff0c;赛题地址&#xff1a; http://go.datafountain.cn/s57 团队简介 本团队具有丰富的比赛和项目经验。在AI大赛上多次拿到Top成绩&#xf…

线性表之链表

1、链表概述 链表是一种物理存储结构上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 顺序表的存储位置可以用一个简单直观的公式表示&#xff0c;它可以随机存取表中任意一个元素&#xff0c;但插入和删除需要移动大量元素。链式…

深入理解 PostgreSQL 的架构和内部工作原理

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

Postman怎么做接口测试-以简单的登录接口为例

我们就以登录某测试系统为例子&#xff0c;实现在Postman上做接口测试 一、首先打开系统首页首页&#xff0c;做一个登录操作&#xff08;目的是获取接口url及参数&#xff09;&#xff1a;一般在公司做接口测试的时候页面还没有出来&#xff0c;我们需要根据接口文档进行接口…

kafka第三课-可视化工具、生产环境问题总结以及性能优化

一、可视化工具 https://pan.baidu.com/s/1qYifoa4 密码&#xff1a;el4o 下载解压之后&#xff0c;编辑该文件&#xff0c;修改zookeeper地址&#xff0c;也就是kafka注册的zookeeper的地址&#xff0c;如果是zookeeper集群&#xff0c;以逗号分开 vi conf/application.conf 启…

Python 逻辑回归:理论与实践

文章目录 1. 介绍1.1 什么是逻辑回归&#xff1f;1.2 逻辑回归的应用领域 2. 逻辑回归的原理2.1 Sigmoid 函数2.2 决策边界2.3 损失函数 3. 逻辑回归的实现3.1 数据准备3.2 创建逻辑回归模型3.3 模型训练3.4 模型预测3.5 模型评估 4. 可视化决策边界4.1 绘制散点图4.2 绘制决策…

基于SaaS模式的Java基层卫生健康云HIS系统源码【运维管理+运营管理+综合监管】

云HIS综合管理平台 一、模板管理 模板分为两种&#xff1a;病历模板和报表模板。模板管理是运营管理的核心组成部分&#xff0c;是基层卫生健康云中各医疗机构定制电子病历和报表的地方&#xff0c;各医疗机构可根据自身特点特色定制电子病历和报表&#xff0c;制作的电子病历…

Docker 容器生命周期:创建、启动、暂停与停止----从创建到停止多角度分析

&#x1f337;&#x1f341; 博主 libin9iOak带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33…

代码随想录| 图论04 查并集 ●查并集理论知识 ●1971.寻找图中是否存在路径 ●684.冗余连接 ●685.冗余连接II

#查并集理论知识 并查集用处&#xff1a;解决连通性问题 将两个元素添加到一个集合中。判断两个元素在不在同一个集合 思路&#xff1a;将三个元素A&#xff0c;B&#xff0c;C &#xff08;分别是数字&#xff09;放在同一个集合&#xff0c;其实就是将三个元素连通在一起&a…

Python 算法基础篇:插入排序和希尔排序

Python 算法基础篇&#xff1a;插入排序和希尔排序 引言 1. 插入排序算法概述2. 插入排序算法实现实例1&#xff1a;插入排序 3. 希尔排序算法概述4. 希尔排序算法实现实例2&#xff1a;希尔排序 5. 插入排序与希尔排序的对比总结 引言 插入排序和希尔排序是两种常用的排序算法…

017-从零搭建微服务-系统服务(四)

写在最前 如果这个项目让你有所收获&#xff0c;记得 Star 关注哦&#xff0c;这对我是非常不错的鼓励与支持。 源码地址&#xff08;后端&#xff09;&#xff1a;https://gitee.com/csps/mingyue 源码地址&#xff08;前端&#xff09;&#xff1a;https://gitee.com/csps…

【NLP】如何使用Hugging-Face-Pipelines?

一、说明 随着最近开发的库&#xff0c;执行深度学习分析变得更加容易。其中一个库是拥抱脸。Hugging Face 是一个平台&#xff0c;可为 NLP 任务&#xff08;如文本分类、情感分析等&#xff09;提供预先训练的语言模型。 本博客将引导您了解如何使用拥抱面部管道执行 NLP 任务…

超详细图文教程:3DS Max 中创建低多边形游戏长剑模型

推荐&#xff1a; NSDT场景编辑器助你快速搭建可二次开发的3D应用场景 在此&#xff0c;由两部分组成的教程的第一部分中&#xff0c;我将向您展示如何&#xff1a; 对剑柄进行建模剑的护手模型剑刃建模 1. 如何制作剑柄 步骤 1 在本教程中使用正交视图。要更改视图&#x…

AI时代带来的图片造假危机,该如何解决

一、前言 当今&#xff0c;图片造假问题非常泛滥&#xff0c;已经成为现代社会中一个严峻的问题。随着AI技术不断的发展&#xff0c;人们可以轻松地通过图像编辑和AI智能生成来篡改和伪造图片&#xff0c;使其看起来真实而难以辨别&#xff0c;之前就看到过一对硕士夫妻为了骗…

Flink-端到端精确一次(End-To-End Exactly-Once)

1.总结 目的&#xff1a;想要在故障恢复后不丢数据 输入端 保证可以重复发送数据如果是kafka&#xff0c;Flink负责维护offset&#xff0c;不用kafka维护设置kafka的隔离级别为&#xff1a;读已提交flink 开启检查点采用对齐或者不对齐的精确一次输出端 kafka 幂等事务两阶段…

一文了解Python中的while循环语句

目录 &#x1f969;循环语句是什么 &#x1f969;while循环 &#x1f969;遍历猜数字 &#x1f969;while循环嵌套 &#x1f969;while循环嵌套案例 &#x1f990;博客主页&#xff1a;大虾好吃吗的博客 &#x1f990;专栏地址&#xff1a;Python从入门到精通专栏 循环语句是什…