CMU15-445-Spring-2023-Project #2 - B+Tree

前置知识:参考上一篇博文 CMU15-445-Spring-2023-Project #2 - 前置知识(lec07-010)

CHECKPOINT #1

Task #1 - B+Tree Pages

实现三个page class来存储B+树的数据。

  • B+Tree Page
    • internal page和leaf page继承的基类,只包含两个子类共享的信息;
    • image.png
    • Impl:
      • src/include/storage/page/b_plus_tree_page.h
      • src/storage/page/b_plus_tree_page.cpp
  • B+Tree Internal Page
    • 一个内部页面存储 m 个有序键和 m+1 个指向其他 B+Tree 页面的子指针(作为 page_id)。这些键和指针在内部表示为一个 key/page_id 对数组。由于指针的数量不等于键的数量,因此第一个键被设置为无效,查找应始终从第二个键开始
    • 在任何时候,每个内部页面都应至少满一半。在删除过程中,可以合并两个半满的页面,或者重新分配键和指针以避免合并。在插入过程中,可以将一个完整的页面分割成两个,也可以重新分配键和指针以避免分割;
    • Impl:
      • src/include/storage/page/b_plus_tree_internal_page.h
      • src/storage/page/b_plus_tree_internal_page.cpp
  • B+Tree Leaf Page
    • leaf page存储 m 个有序键及其 m 个相应的值。值应始终是tuple实际存储位置的 64 位 record_id;参阅 src/include/common/rid.h 中的 RID 类。leaf page对k/v对数量的限制与内部页面相同,并应遵循合并、拆分和重新分配键的相同操作;
    • Impl:
      • src/include/storage/page/b_plus_tree_leaf_page.h
      • src/storage/page/b_plus_tree_leaf_page.cpp

每个 B+Tree 的leaf/internal page都与缓冲池获取的内存页的内容(即 data_ 部分)相对应。每次读取或写入leaf/internal page时,必须先从缓冲池中获取该页(使用其唯一的 page_id),然后 reinterpret cast 成leaf/internal page,并在读取或写入该页后将其unpin。

Task #2a - B+Tree Insertion and Search for Single Values

Impl:
src/storage/index/b_plus_tree.cpp

如果插入改变了根页面的 ID,则必须更新 B+Tree 索引头页面中的 root_page_id。为此,可以访问在构造函数中给出的 header_page_id_ page。然后,通过使用 reinterpret cast,将该页面解释为 BPlusTreeHeaderPage(来自 src/include/storage/page/b_plus_tree_header_page.h),并从这里更新根页面 ID。实现 GetRootPageId(目前默认返回 0)。
使用 project 1 中的page guard类来帮助防止同步问题。在访问页面时使用 FetchPageBasic(定义于 src/include/storage/page/)。以后在task 4 中实施并发控制时,可以根据需要将其改为使用 FetchPageRead 和 FetchPageWrite。
可以选择使用 Context 类(定义于 src/include/storage/index/b_plus_tree.h)来跟踪已读取或写入的页面(通过 read_set_ 和 write_set_ 字段),或存储需要递归传递到其他函数的其他元数据。
只需要在插入或删除时使用 write_set_。可能不需要使用 read_set_,这取决于实现。
在context中存储根页面 id,并在修改 B+Tree 时获取头页面的写保护。
write_set_ 的尾部保存当前节点的父节点,它应该包含访问路径上的所有节点。
如果要拆分节点(根节点除外),要确保 write_set_ 中至少还有一个节点。
要解锁header page,只需将 header_page_ 设为 std::nullopt。要解锁其他页面,只需从 write_set_ 中弹出即可。
插入后,当值的数量达到 max_size 时,分割叶节点;插入前,当值的数量达到 max_size 时,分割内部节点。这将确保在进行 InsertIntoLeaf 等操作后再重新分配时,插入叶节点不会导致页面数据溢出;这也将防止内部节点只有一个子节点。
当叶页面无法获取同级页面的latch时,需要抛出一个 std::exception 异常,以避免潜在的死锁。
每个线程将始终从头页到底部获取锁存器。释放锁存器时,请确保以相同的顺序(从页眉到底部)释放。
在插入时,即使拥有父节点的锁,也应始终获取子节点的锁。想想这样一种情况:一些线程正在使用读锁从叶子页中获取值,而另一些线程正在更新页面(例如,在聚合时)。如果不加锁,就会出现race。

  • GetValue()
    • 使用ReadPageGuard访问页面。通过header_page_id_访问header page,header page的root_page_id_指向根节点的第一个k/v对;
    • 当获取了根节点的页面的latch后,释放header page的latch;
    • 通过二分搜索key在页面中的位置,迭代向下查找到leaf page,然后找到leaf page中相应的value(rid)。
  • Insert()
    • 同样,先获取根页面,若根为空,通过NewPageGuarded获取一个新页面,然后插入;
    • 若根节点不为空,通过write_set_维护向下搜索的path,直到到达leaf page,并且通过prev_和next_维护路径上节点的左右兄弟节点(插入分裂优化);
    • 若搜索过程中某个internal page的size小于max size,就可以将write_set_中的节点弹出,因为即使叶子节点需要分裂,internal page需要插入新k/v对,size也是够的;
    • 插入分裂优化:若leaf page插入后超过了max size,但是其兄弟节点没满,会将最左/右记录移动到其兄弟节点上,默认先向左移动;(参考InnoDB,充分利用索引页,还有一种方法就是在特定的递增key插入情况下,如果检测到三个连续递增的key,那么就不进行分裂,而是直接往右新建一个页面插入,避免频繁分裂)常规分裂就是50%。
    • leaf page分裂会产生新的k/v,继续向上往internal page插入(根据write_set_维护的path),同样进行插入分裂优化;
    • 若write_set_遍历完后还需要向上插入,那么通过NewPageGuarded获取新页面作为根节点,然后更新即可;

CHECKPOINT #2

Task #2b - B+Tree Deletions

支持key的删除,包括页面的合并或重新分配键。与插入一样,如果根页面发生变化,必须正确更新 B+Tree 的根页面 ID。
Impl:
src/storage/index/b_plus_tree.cpp

  • Remove()
    • 几乎与Insert同样的思路,进行合并优化,优先从兄弟节点拉取单个k/v到本节点;

Task #3 - An Iterator for Leaf Scans

添加一个 C++ 迭代器,以有效支持对leaf page中的数据进行顺序扫描。基本思路是存储同胞指针,以便高效地遍历leaf page,然后实现一个迭代器,按顺序遍历每个leaf page中的每个键值对。

  • C++17 style;
  • isEnd():返回此迭代器是否指向最后一个键/值对;
  • operator++():移动到下一个键/值对;
  • operator*():返回该迭代器当前指向的键/值对;
  • operator==():返回两个迭代器是否相等;
  • operator!=():返回两个迭代器是否不相等;
  • Begin() & End():返回最左/右的leaf page的迭代器;

Impl:
src/include/storage/index/index_iterator.h
src/index/storage/index_iterator.cpp
src/storage/index/b_plus_tree.cpp
IndexIterator内部维护三个值:bpm、page id、page内部index。

Task #4 - Concurrent Index

FetchPageWrite or FetchPageRead

实验结果

image.pngimage.png

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

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

相关文章

K8S的部署策略,重建更新和滚动更新

Deployment Strategies 部署战略 When it comes time to change the version of software implementing your service, a Kubernetes deployment supports two different rollout strategies: RecreateRollingUpdate 当需要更改实施服务的软件版本时,Kubernetes …

代码随想录刷题题Day29

刷题的第二十九天,希望自己能够不断坚持下去,迎来蜕变。😀😀😀 刷题语言:C Day29 任务 ● 01背包问题,你该了解这些! ● 01背包问题,你该了解这些! 滚动数组 …

WebGL在实验室方向的应用

WebGL在实验室方向的应用涉及到实验过程的可视化、数据分析、模拟等方面。以下是一些WebGL在实验室领域的应用示例,希望对大家有所帮助。北京木奇移动技术有限公司,专业的软件外包开发公司,欢迎交流合作。 1.分子模型和化学反应模拟&#xff…

element plus el-form双列布局及拓展任意布局

1 场景 一般表单我们直接默认布局&#xff0c;也就是单列布局&#xff0c;突然有个人员信息表单&#xff0c;需要双列布局的需求&#xff0c;简单实现并拓展下 2 思路 直接无脑divflex布局实现 3 代码 <template><el-form ref"formRef" :model"fo…

2024--Django平台开发-Django知识点(五)

day05 django知识点 今日概要&#xff1a; 中间件 【使用】【源码】cookie 【使用】【源码 - Django底层请求本质】session【使用】【源码 - 数据库请求周期中间件】 1.中间件 1.1 使用 编写类&#xff0c;在类型定义&#xff1a;process_request、process_view、process_…

基于JavaWeb+BS架构+SpringBoot+Vue校园一卡通系统的设计和实现

基于JavaWebBS架构SpringBootVue校园一卡通系统的设计和实现 文末获取源码Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 文末获取源码 Lun文目录 第一章 概述 4 1.1 研究背景 4 1.2研究目的及意义 4 1.3国内外发展现状 4 1…

最新出炉!知乎最牛最全JMeter+Ant+Jenkins接口自动化测试框架(Windows)

一:简介 大致思路&#xff1a;Jmeter可以做接口测试&#xff0c;也能做压力测试&#xff0c;而且是开源软件&#xff1b;Ant是基于Java的构建工具&#xff0c;完成脚本执行并收集结果生成报告&#xff0c;可以跨平台&#xff0c;Jenkins是持续集成工具。将这三者结合起来可以搭…

数据结构及单链表例题(下)

上次我们已经了解了单链表的数据结构定义以及创建单链表的两种方法,这节介绍几道例题. 文章目录 前言 一、已知L为带头结点的单链表,请依照递归思想实现下列运算 二、单链表访问第i个数据节点 三、在第i个元素前插入元素e 四、删除第i个结点 五、查找带头结点单链表倒数第…

C++学习笔记(三十二):c++ 堆内存与栈内存比较

本节对堆和栈内存进行描述。 应用程序启动后&#xff0c;操作系统将整个程序加载到内存&#xff0c;分配相应的物理ram&#xff0c;确保程序可以正常运行。堆和栈是ram中存在的两个区域。栈通常是一个预定义大小的内存区域&#xff0c;一般是2M字节左右。堆也是预定了默认值的…

固乔快递查询助手:批量、快速、全面的快递信息查询软件

在快递行业飞速发展的今天&#xff0c;如何高效、准确地掌握快递信息成为了很多人的需求。而固乔快递查询助手正是解决这一难题的利器。 固乔快递查询助手是一款专注于快递信息查询的软件&#xff0c;支持多家主流快递公司查询。用户只需输入单号&#xff0c;即可快速查询到实时…

RIP复习实验

条件: R1为外网&#xff0c;R8和r9的环回分别是172.16.1.0/24和172.16.2.0/24 中间使用78.1.1.0/24 剩下的路由器2-6使用172.16.0.0/16 要求: R1为运营商 r1远程登录r2实际登录r7 R2访问r7要求走r5去访问 全网可达 实现流程: 首先配置好各接口ip address 然后r2-r7使用rip…

vue2使用文件上传读取本地照片并转化base64格式进行展示

创建个vue2项目,直接把代码放到一个vue2页面内运行就好,下面代码拿来即用 <template><div><div class"replace_menu_mask" click"closeMenu"><img :src"replaceImg" alt"" style"width: 100%;">&l…

PandoraNext—一个让你呼吸顺畅的ChatGPT

博客地址 PandoraNext—一个让你呼吸顺畅的ChatGPT-雪饼 (xue6ing.cn)https://xue6ing.cn/archives/pandora--yi-ge-rang-ni-hu-xi-shun-chang-de-chatgpt 项目 项目地址 pandora-next/deploy 项目介绍 支持多种登录方式&#xff1a; 账号/密码 Access Token Session To…

探索Shadowsocks-Android:保护你的网络隐私

探索Shadowsocks-Android&#xff1a;保护你的网络隐私 I. 引言 在数字时代&#xff0c;网络隐私和安全变得愈发重要。我们越来越依赖互联网&#xff0c;但同时也面临着各种网络限制和监控。在这个背景下&#xff0c;Shadowsocks-Android应用程序应运而生&#xff0c;为用户提…

文心大模型融入荣耀MagicOS!打造大模型“端云协同”创新样板

2024年1月10日&#xff0c;在荣耀MagicOS 8.0发布会及开发者大会上&#xff0c;荣耀终端有限公司CEO赵明宣布了“百模生态计划”&#xff0c;并与百度集团执行副总裁、百度智能云事业群总裁沈抖共同宣布&#xff0c;百度智能云成为荣耀大模型生态战略合作伙伴。 沈抖在现场演讲…

前端导出Excel文件,部分数字前面0消失处理办法

详细导出可以看之前的文章 js实现导出Excel文档_js 通过 接口 导出 xlsx 代码-CSDN博客 今天的问题是导出一些数据时&#xff0c;有些字段是前面带有0的字符串&#xff0c;而导出后再excel中就被识别成了数字 如图本来字符串前面的0 都没了 解决方案 1. 导出的时候在前面加单…

第86讲:MySQLDump与Binlog日志实现企业级数据备份恢复案例

文章目录 1.企业级数据备份恢复案例描述2.第一环节&#xff1a;周三凌晨进行数据全量备份3.第二环节&#xff1a;模拟周三凌晨备份完之后到下午3点前的业务操作4.第三环节&#xff1a;模拟数据库异常数据丢失导致平台无法使用5.第四环节&#xff1a;发布停服公告全员进入数据恢…

PCL 计算异面直线的距离

目录 一、算法原理二、代码实现三、结果展示四、相关链接本文由CSDN点云侠原创,PCL 计算异面直线的距离,爬虫自重。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫与GPT。 一、算法原理 设置直线 A B AB A

【Linux】通过两台linux主机配置ssh实现互相免密登陆

以下是通过两台Linux主机配置SSH实现互相免密登录的代码及操作流程&#xff1a; node1主机IP&#xff1a;192.168.48.129 server主机IP&#xff1a;192.168.48.130 1、在node1主机上生成密钥对&#xff1a; ssh-keygen -t rsa 2、将node1主机的公钥发送到server主机&#x…

Visual Studio 新特性:对 include 指令进行智能诊断

今天&#xff0c;我们很高兴地宣布新功能&#xff1a;#include 语言智能诊断。 此功能自 Visual Studio 2022 v17.9 预览版2 中可用。通过此新功能&#xff0c;您可以获取到有关每个 include 的引用和生成时间的详细信息&#xff0c;从而更好地了解 #include 指令的行为。 &g…