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

news2024/11/28 0:36:22

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.coloradmin.cn/o/780044.html

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

相关文章

flink Mysql CDC(动态加表)、postgresqlCDC 和 CDC无锁算法

flinkCDC - 功能验证记录 flink 与cdc 版本使用搭配&#xff1a;flink cdc参数说明原理分析&#xff08;DBLog&#xff09;无锁算法论文 mysql cdccdc api 动态加表flink cdc sql 性能压测flink cdc api 性能压测 PostgreSqlCDC执行更新语句&#xff0c;会出现 2 种情况 cdc si…

【数据挖掘】bytewax 与 ydata工具可实时了解您的数据

一、说明 在这篇博文中&#xff0c;我们将介绍如何将开源流式处理解决方案 bytewax 与 ydata 分析相结合并加以利用&#xff0c;以提高流式处理流的质量。 STream 处理支持在传输中和存储之前对数据进行实时分析&#xff0c;并且可以是有状态的&#xff0c;也可以是无状态的。 …

[STL]vector使用介绍

[STL]vector使用介绍 注&#xff1a;文内代码均在Visual Studio 2013下进行测试&#xff0c;不同的编译器下在扩容大小等方面可能有所不同&#xff0c;但不影响各接口函数的使用。 文章目录 [STL]vector使用介绍1. vector介绍2. 构造函数3. 迭代器相关函数begin函数和end函数的…

实现点击复制到剪切板功能

该功能使用VueUse实现 什么是 VueUse VueUse不是Vue.use&#xff0c;它是为Vue 2和3服务的一套Vue Composition API的常用工具集&#xff0c;是目前世界上Star最高的同类型库之一。它的初衷就是将一切原本并不支持响应式的JS API变得支持响应式&#xff0c;省去程序员自己写相…

jmeter常用的提取器(正则表达式和JSON提取器)

jmeter常用的后置处理器有两种提取数据&#xff1a; 1、JSON提取器 获取后可以将变量token引用到其他所需要的地方 &#xff08;正则表达式和JSON提取器&#xff09;:2023接口自动化测试框架必会两大神器:正则提取器和Jsonpath提取器_哔哩哔哩_bilibilihttps://www.bilibili.…

uniapp实战

上面是tab栏&#xff0c;下面是swiper&#xff0c;&#xff0c;tab和swiper和 红色滑块 动态变化&#xff0c;&#xff0c; 遇到的问题&#xff1a; 往下滚动 tab栏 吸顶&#xff1a; position:sticky; z-index:99; top:0;swiper切换触发 change 事件&#xff0c; :current …

SOMEIP协议--第四节[ SOME/IP](someip概述与行为)

SOMEIP协议–第四节[ SOME/IP](someip概述与行为) 文章目录 SOMEIP协议--第四节[ SOME/IP](someip概述与行为)1、概述2、someip的行为2.1 基础传输2.2 SOME/IP-TP传输:2.3 someip参数(client)2.4 someip参数(server)1、概述 Method | Event | Field是上层设计的三个概念…

【C++】优先级队列和反向迭代器 模拟笔记

文章目录 优先级队列仿函数适配器模式堆知识储备 反向迭代器代码&#xff08;反向迭代器&#xff09;代码&#xff08;优先级队列&#xff09; 优先级队列 仿函数 仿函数&#xff0c;它不是函数&#xff08;其实是个类&#xff09;&#xff0c;但用法和函数一样。既然是个类&a…

子类化QThread来实现多线程,moveToThread函数的作用

子类化QThread来实现多线程&#xff0c; QThread只有run函数是在新线程里的&#xff0c;其他所有函数都在QThread生成的线程里。正确启动线程的方法是调用QThread::start()来启动。 一、步骤 子类化 QThread&#xff1b;重写run&#xff0c;将耗时的事件放到此函数执行&#…

轻量级Web报表工具ActiveReportsJS全新发布v4.0,支持集成更多前端框架!

ActiveReportsJS 是一款基于 JavaScript 和 HTML5 的轻量级Web报表工具&#xff0c;采用拖拽式设计模式&#xff0c;不需任何服务器和组件支持&#xff0c;即可在 Mac、Linux 和 Windows 操作系统中&#xff0c;设计多种类型的报表。ActiveReportsJS 同时提供跨平台报表设计、纯…

18.背景轮播

背景轮播 html部分 <div class"container"><div class"slide active" style"background-image: url(./static/20180529205331_yhGyf.jpeg);"></div><div class"slide " style"background-image: url(./s…

vue3+taro+Nutui 开发小程序(二)

上一篇我们初始化了小程序项目&#xff0c;这一篇我们来整理一下框架 首先可以看到我的项目整理框架是这样的&#xff1a; components:这里存放封装的组件 custom-tab-bar:这里存放自己封装的自定义tabbar interface&#xff1a;这里放置了Ts的一些基本泛型&#xff0c;不用…

AtcoderABC238场

A - Exponential or QuadraticA - Exponential or Quadratic 题目大意 给定一个整数 n&#xff0c;判断是否满足 2n >n 2。 思路分析 根据数学知识可知n 的取值在 2 到 4 之间&#xff08;包括 2 和 4&#xff09;&#xff0c;不满足条件 。 时间复杂度 O(1) AC代码 …

MyBatis学习笔记——4

MyBatis学习笔记——4 一、MyBatis的高级映射及延迟加载1.1、多对一1.1.1、第一种方式&#xff1a;级联属性映射1.1.2、第二种方式&#xff1a;association1.1.3、第三种方式&#xff1a;分步查询 1.2、一对多1.2.1、第一种方式&#xff1a;collection1.2.1、第二种方式&#x…

Linux Ubuntu crontab 添加错误 提示:no crontab for root - using an empty one 888

资料 错误提示&#xff1a; no crontab for root - using an empty one 888 原因剖析&#xff1a; 第一次使用crontab -e 命令时会让我们选择编辑器&#xff0c;很多人会不小心选择默认的nano&#xff08;不好用&#xff09;&#xff0c;或则提示no crontab for root - usin…

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

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

【N32L40X】学习笔记11-ADC规则通道采集+dma数据传输

ADC规则通道转换 概述 支持 1 个 ADC&#xff0c;支持单端输入和差分输入&#xff0c;最多可测量 16 个外部和 3 个内部源。支持 12 位、10 位、8 位、6 位分辨率。ADC 时钟源分为工作时钟源、采样时钟源和计时时钟源 仅可配置 AHB_CLK 作为工作时钟源。可配置 PLL 作为采样时…

【安全】Sqllabs(1-4) 多种情况浅析

目录 环境⭐ 先要 ⭐⭐⭐⭐⭐ Less - 1 (information_shcema) Less - 2 (假设没有information_schema) Less - 3 (无列名注入) Less - 4 环境⭐ MySQL8.0.12 Nginx1.15.11 先要 ⭐⭐⭐⭐⭐ MySQL5.0以上有这几个数据库mysql, sys&#xff0c;information_schema informa…

前端性能优化——图片优化

一、图片优化措施 优化图片是 Web 前端优化的重要一环&#xff0c;因为图片是 Web 页面中最耗费带宽和加载时间的资源之一。以下是一些通过优化图片来优化 Web 前端的方法&#xff1a; 压缩图片&#xff1a;压缩图片可以减少图片的文件大小&#xff0c;从而减少加载时间。 使…

【数学建模】相关是一个距离指标吗?

一、说明 本文探讨最平凡的数学模型--距离模型。我们知道&#xff0c;任何数学模型如果是个距离模型&#xff0c;那么它是&#xff1a;放心的、自动的、不加任意条件的指标项目。然而另一些度量参数不是距离空间&#xff0c;因此&#xff0c;使用起来必须外加若干条件&#xff…