【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.mfbz.cn/a/43193.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Hadoop——DataGrip连接MySQL|Hive

1、下载 DataGrip下载&#xff1a;DataGrip: The Cross-Platform IDE for Databases & SQL by JetBrains 2、破解 破解链接&#xff1a;https://www.cnblogs.com/xiaohuhu/p/17218430.html 3、启动环境 启动Hadoop&#xff1a;到Hadoop的sbin目录下右键管理员身份运行…

计算机服务器被devos勒索病毒攻击怎么解决,数据库解密恢复方式

科学技术的发展为企业的生产运行提供了极大的便利性&#xff0c;但随之而来的网络安全也应该引起人们的重视。近期&#xff0c;我们收到很多企业的求助&#xff0c;企业的计算机服务器内的数据库被devos后缀勒索病毒攻击&#xff0c;导致企业许多工作无法正常运行。Devos后缀勒…

每天五分钟计算机视觉:单卷积层的前向传播过程

什么是单卷积层? 一张图片(输入)经过多个卷积核卷积就会得到一个输出,而这多个卷积核的组合就是一个单卷积层。 这些卷积核可能大小是不一样的,但是他们接收同样大小是输入,他们的输出必须是一般大小,所以不同的卷积核需要具备不同的步长和填充值。 单层卷积网络前向传…

大数据分析案例-基于LightGBM算法构建乳腺癌分类预测模型

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

微服务如何治理

微服务远程调用可能有如下问题&#xff1a; 注册中心宕机&#xff1b; 服务提供者B有节点宕机&#xff1b; 服务消费者A和注册中心之间的网络不通&#xff1b; 服务提供者B和注册中心之间的网络不通&#xff1b; 服务消费者A和服务提供者B之间的网络不通&#xff1b; 服务提供者…

安装redis,适配阿里云服务器,Liunx安装redis

下载redis以及编译安装 下载redis文件 wget http://download.redis.io/releases/redis-6.0.8.tar.gz #下载redis压缩文件 tar xzf redis-6.0.8.tar.gz #解压缩 cd redis-6.0.8 make 查看是否安装了gcc编译输入gcc --version如果没有…

数据仓库表设计理论

数据仓库表设计理论 数仓顾名思义是数据仓库&#xff0c;其数据来源大多来自于业务数据(例如:关系型数据库)&#xff0c;当设计数仓中表类型时(拉链表、增量表、全量表、流水表、切片表)时&#xff0c;应先观察业务数据的特点再设计数仓表结构 首先业务数据是会不断增长的-即…

STM32外设系列—TB6612FNG

本文涉及到定时器和串口的知识&#xff0c;详细内容可见博主STM32速成笔记专栏。 文章目录 一、TB6612简介二、TB6612使用方法2.1 TB6612引脚连接2.2 控制逻辑2.3 电机调速 三、实战项目3.1 项目简介3.2 初始化GPIO3.3 PWM初始化3.3 电机控制程序3.4 串口接收处理函数 一、TB66…

基于SPDK-vhost的云原生Kubevirt虚拟化存储IO的优化方案

摘要 本文主要介绍针对云原生kubernetes虚拟化IO的应用场景&#xff0c;在Kubevirt中引入SPDK-vhost的支持&#xff0c;来加速虚机中IO存储性能。同时基于Intel开源的Workload Service Framework[1]平台集成部署一套端到端虚拟化IO的应用场景做基本的性能对比测试。 云原生Kube…

Hadoop——Windows系统下Hadoop单机环境搭建

为了便于开发&#xff0c;我在本地Windows系统进行Hadoop搭建。 我使用的版本&#xff1a;hadoop-2.7.0。其他版本也可&#xff0c;搭建流程基本一样&#xff0c;所以参考这个教程一般不会有错。 1、下载安装包和插件 安装包hadoop-2.7.0.tar.gz 必要插件winutils-master 2、…

RocketMQ教程-安装和配置

Linux系统安装配置 64位操作系统&#xff0c;推荐 Linux/Unix/macOS 64位 JDK 1.8 Maven3.0 yum 安装jdk8 yum 安装maven 1.下载安装Apache RocketMQ RocketMQ 的安装包分为两种&#xff0c;二进制包和源码包。 点击这里 下载 Apache RocketMQ 5.1.3的源码包。你也可以从这…

详细介绍Matlab中线性规划算法的使用

Matlab中提供了用于线性规划的优化工具箱&#xff0c;其中包含了多种算法&#xff0c;如单纯形法、内点法等。线性规划是一种优化问题&#xff0c;旨在找到一组变量的最佳值&#xff0c;以最大化或最小化线性目标函数&#xff0c;同时满足一组线性约束条件。 下面将详细介绍Ma…

【Spring Boot】事务的隔离级别与事务的传播特性详解:如何在 Spring 中使用事务?不同隔离级别的区别?

文章目录 1 事务1.1 事务简介与 mysql 中的事务使用1.2 Spring 编程式事务&#xff08;手动操作&#xff09;1.3 Spring 声明式事务&#xff08;自动操作&#xff09;1.4 Transactional 的工作原理 2 事务的隔离级别2.1 事务的四大特性及事务的隔离级别回顾2.2 Spring 事务的隔…

python web开发之WSGI/uwsgi/uWSGI详解

1. 三者的定义 WSGI是一种通信协议。uwsgi是一种传输协议。uWSGI是实现了uwsgi和WSGI两种协议的Web服务器。 2.三者的使用场景 WSGI&#xff0c;全称 Web Server Gateway Interface&#xff0c;是为 Python 语言定义的 Web 服务器和 Web 应用程序或框架之间的一种简单而通用的接…

MySQL之索引(入门级讲解)

目录 一.索引的概念 1.1索引的简介 1.2.索引的优缺点 二.MySQL索引语法 2.1查看索引 2.2创建索引 2.2.1 创建表时创建索引 2.2.2存在的表上创建索引 2.3删除索引 三.索引的数据结构 3.1Btree索引 3.2Hash索引 3.4Hash索引和Btree索引的对比 &#x1f381;个…

文本预处理——文本张量表示方法

目录 文本张量表示one-hot编码word2vecword embedding 文本张量表示 one-hot编码 word2vec word embedding

代码随想录算法训练营第二十一天 | 读PDF复习环节1

读PDF复习环节1 本博客的内容只是做一个大概的记录&#xff0c;整个PDF看下来&#xff0c;内容上是不如代码随想录网站上的文章全面的&#xff0c;并且PDF中有些地方的描述&#xff0c;是很让我疑惑的&#xff0c;在困扰我很久后&#xff0c;无意间发现&#xff0c;其网站上的讲…

使用rknn-toolkit2把YOLOV5部署到OK3588上

使用rknn-toolkit2把YOLOV5部署到OK3588上 虚拟环境搭建软件包安装在PC机上运行yolov5目标检测 虚拟环境搭建 首先在PC的ubuntu系统安装虚拟环境&#xff1a; 我的服务器是ubuntu18.04版本&#xff0c;所以安装python3.6 conda create -n ok3588 python3.6 需要键盘输入y&…

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

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

Day 61-62 决策树(ID3)

代码&#xff1a; package dl;import java.io.FileReader; import java.util.Arrays; import weka.core.*;/*** The ID3 decision tree inductive algorithm.*/ public class ID3 {/*** The data.*/Instances dataset;/*** Is this dataset pure (only one label)?*/boolean …