CMU15-445 2022 Fall 通关记录 —— Project 2:B+ Tree(下篇)

news2024/9/24 2:04:36

Project 2:B+ Tree

Project #2 - B+Tree | CMU 15-445/645 :: Intro to Database Systems (Fall 2022)

NOTE:

记录完成该Pro中,一些可能会遇到的问题:

本实验中,有很多API是需要自己去实现的,因此,我推荐把逻辑梳理清楚后,再尝试去实现,函数设计是一门学问,我个人地原则是尽量避免出现重复代码段,即相同地处理置于一个函数中;

相较于Pro0和Pro1,本次指导书中的内容简略了许多,格外要注意到底是在哪实现代码,例如Task2是在src/include/storage/index/b_plus_tree.h和相应的CPP文件中实现(为什么会这么说?因为我就犯蠢了)

官方提供了一个可以正确打印实现的B+树的网页,可以用于检测与本地实现之间的差异,推荐在实现具体函数地时候可以先手动尝试一下插入、删除等操作。

BusTub B+Tree Printer (cmu.edu)

本次实验的实现中,涉及到了很多与迭代器相关的操作,包括但不限于std::prev\ std::next\ std::lower_bound \ std::move_backwrad(),所以我认为可以提前了解一下C++提供的这些语法糖,还能使你的code能力得到一定的提升。推荐网站:cppreference.com

每次用完Page后记得Unpin!

我在进行这次实验的时候,短暂地尝试了使用Copliot来辅助完成编写,可以省去很多简单逻辑的重复编写,但是有些细节逻辑处理的仍不是特别好,或者是有可能是我没有理解AI的意思。

虽然在我下文中地描述中使用了内部页和叶子页这种比较蹩脚地称呼,但是还是要意识到本质上依旧是树中地一个节点,为了方便,在代码中给变量取名地时候可以用page和node加以区分。

Task #3:Index Iterator

将叶子页迭代器化,近似于组织为链表(MySQL中就是如此),迭代器应当具有基本功能,例如运算符和for-each循环。

迭代器的操作仅需在src/include/storage/index/index_iterator.hsrc/index/storage/index_iterator.cpp中进行实现。

指导书中提供了以下几个成员函数,可以自行实现其他辅助函数

  • isEnd() :返回此迭代器是否指向最后一个键/值对。
  • operator++() :移至下一个键/值对。注意,形参为空的是前置++。
  • operator*() :返回该迭代器当前指向的键/值对。
  • operator==() :返回两个迭代器是否相等
  • operator!=() :返回两个迭代器是否不相等。

首先明确,迭代器中的元素应当为某个叶子页中的某元素,因此必然需要包含一个叶子页和当前叶子中的索引作为成员变量,以及为了能够在不同叶子页之间做到切换,也自然要把BufferPoolManager考虑进去,在发生切换时要记得Unpin前一个page。

本Task总体来说并不困难,相较于实现基础的B+树来说,就是做了一层封装。

但是实现完index_iterator中的内容后,不要忘记B+树中也是有对应的实现的(目的就是为了在B+树中使用):

image-20230701135457167

区别在于返回类型为迭代器类型。

Task #4:Concurrent Index

直接加一把大锁不是不可以,但是实验的初衷并非如此,由于项目中已经提供了页的锁,所以本Task的难点在于,何时、何处考虑加锁与解锁!

此处提供一篇详细讲述Task4的文章:

CMU 15445-2022 P2 B+Tree Concurrent Control - 知乎 (zhihu.com)

指导书中点明了一种名为latch crabbing的技术,基本思想是,遍历B+树的线程会在B+树页面上获取和释放锁(latch)。线程只能在子页面被认为是"安全的"时才能释放父页面上的锁。这里的"安全"的定义可以根据线程执行的具体操作而有所变化。在具体实现上,当一个线程需要访问一个页面时,它会首先获取该页面的锁。然后,线程会向上遍历树,逐级获取每个父页面的锁,直到达到根页面。在获取父页面的锁之前,线程需要判断其子页面是否被认为是"安全的",如果是,则可以释放子页面的锁,并继续向上获取父页面的锁。这种锁的获取和释放过程就像螃蟹在爬行时借助爪子一样,因此称为"latch crabbing"。

而“安全”的定义则是:节点在进行操作后,不会触发分裂或合并,影响父节点的指针。对插入操作,leafpage和internalpage的安全性应该分情况考虑,因为它们分裂的时机不同。对删除操作,节点要比minsize大。

这篇文章中还提到了一种测试多线程偶然出错的方式:

while xxxx/build/test/b_plus_tree_concurrent_test ; do echo 1; done;

指导书中对于加锁进行了简要的描述:

  • Search :从根页开始,抓住子页上的读(R)闩锁,然后在到达子页时立即释放父页上的闩锁。由于查询的性质是读,读锁是共享的。
  • Insert :从根页开始,抓住子页的写(W)锁存器。一旦子页被锁住,检查它是否安全,在这种情况下,不安全。如果子页安全,则释放对祖先的所有锁定。
  • Delete :从根页开始,抓住子页的写(W)锁存器。一旦子页被锁上,检查它是否安全,在这种情况下,至少是半满的。 (注意:对于根页,我们需要使用不同的标准进行检查)如果子页是安全的,则释放祖先上的所有锁。

有以下几个小点需要注意:

  • 有关锁的实现在src/include/common/rwlatch.h下。

    image-20230701214949439
  • 此前几乎没怎么被用到的transaction中也提供了遍历树时存储已获取的父节点锁的方法。

  • 要在Page上加锁,而非在节点上。

  • 需要在Leaf Page无法获取到兄弟页的锁时抛出异常以避免潜在的死锁。

  • 保护root_page_id在插入与删除时不会被并发更新(提示是使用std::mutex

无论是查找、插入还是删除,都需要通过FindLeaf函数找到对应的叶子页或者是对应的页,加锁的重点就在这个函数中实现

  • 如果是查找,FindLeaf时,每一次向下遍历都需要给子页加读锁,同时释放父页的读锁即可
  • 如果是插入,需要给遍历到的页加写锁,如果最终叶子页是安全的,既可以释放所有祖先的写锁
  • 如果是删除,与插入同理

在插入和删除的过程中,需要注意的是何时释放锁。

对于插入而言,有两个需要注意的点:

  • 如果造成分裂,此时待整个分裂过程完成前,叶子页和祖先的写锁是都不能被释放的,因为分裂时兄弟页的首索引需要上移至父页,父页也是有可能发生分裂的。
  • 当插入操作完成时,需要释放叶子页中的锁以及祖先上的所有锁

而对于移除而言,需要额外多提一个点:

  • 由于移除时涉及到借兄弟页元素的操作,因此也要记得给兄弟页加锁并且用完后即使释放。

测试记录

本地错误:b_plus_tree_insert_test 段错误

经测试,问题发生在如下代码段:

std::vector<int64_t> keys = {1, 2, 3, 4, 5};
  for (auto key : keys) {
    int64_t value = key & 0xFFFFFFFF;
    rid.Set(static_cast<int32_t>(key >> 32), value);
    index_key.SetFromInteger(key);
    tree.Insert(index_key, rid, transaction);
  }

当进行到第四次插入时,会发生错误如下:

Signal: SIGSEGV (Segmentation fault)

经定位,问题最终发生在InsertIntoParent函数的调用上,由于CheckPoint #1无需考虑transaction的问题,而InsertIntoParent本质上是一个递归的过程,在内部递归的该函数调用上缺少了transaction参量。

虽然这个问题看上去是一次疏忽,但是在排查过程中,也发现了另一个问题,即插入引起分裂后

本地错误:并发测试中的DeleteTest1未通过

当我把测试中的线程数改为1,就可以通过测试,说明问题确实发生在并发性上而非别的原因。

线上错误:

说实在的,没想到本地的测试通过后,线上依旧有这么多bug。唯一通过的测试案例是DeleteTest3

image-20230703195631812

看了一下输出的log,问题多在想要得到的值与实际得到的值不匹配,相比此前提交的一次多数超时的情况,已经好了很多了(此问题的起因源于IndexIterator在析构的时候,没有Unpin,主要也是因为我写完Task3之后,没有做insert和delete的本地测试)。

从头到尾检查了一番之后,发现出现了死锁问题:

问题可能发生在页的类型上,改日再进行排查。

编译指令&本地测试:

make b_plus_tree_insert_test -j4
make b_plus_tree_delete_test -j4
make b_plus_tree_contention_test -j4
make b_plus_tree_concurrent_test -j4

./test/b_plus_tree_insert_test
./test/b_plus_tree_delete_test
./test/b_plus_tree_contention_test
./test/b_plus_tree_concurrent_test

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

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

相关文章

Mycat【Mycat高可用(安装配置HAProxy、安装配置Keepalived)】(八)-全面详解(学习总结---从入门到深化)

目录 Mycat高可用_安装配置HAProxy Mycat高可用_安装配置Keepalived 复习&#xff1a; Mycat高可用_安装配置HAProxy 安装配置HAProxy 查看列表 yum list | grep haproxy yum安装 yum -y install haproxy 修改配置文件 $ vim /etc/haproxy/haproxy.cfg 启动HAProxy …

安全漏洞的检测利用

安全漏洞的检测&利用 一、安全漏洞的基本概念1.1、什么是漏洞1.2、漏洞的简单理解1.3、微软的RPC漏洞与蠕虫病毒1.4、微软经典的蓝屏漏洞1.5、Heartbleed&#xff08;心脏滴血&#xff09;漏洞1.6、破壳漏洞CVE-2014-62711.7、漏洞的危害1.8、漏洞的成因1.9、漏洞的信息的组…

mysql工具sequel pro

一、安装sequel pro 下载地址&#xff1a;https://www.sequelpro.com/ 需要翻墙 二、安装mysql 下载地址&#xff1a;https://www.mysql.com/ 傻瓜式安装即可 记得设置密码 三、配置环境变量 &#xff08;1&#xff09;打开终端 &#xff08;2&#xff09;open ~/.bash_profile…

【送书福利-第十五期】计算机全栈高手到底该怎么发展?

大家好&#xff0c;我是洲洲&#xff0c;欢迎关注&#xff0c;一个爱听周杰伦的程序员。关注公众号【程序员洲洲】即可获得10G学习资料、面试笔记、大厂独家学习体系路线等…还可以加入技术交流群欢迎大家在CSDN后台私信我&#xff01; 本文目录 一、前言二、书籍介绍1、《前端…

0代码训练GPT-5?MIT微软证实GPT-4涌现自我纠错能力迭代

我们都知道&#xff0c;大模型具有自省能力&#xff0c;可以对写出的代码进行自我纠错。 这种自我修复背后的机制&#xff0c;究竟是怎样运作的&#xff1f; 对代码为什么是错误的&#xff0c;模型在多大程度上能提供准确反馈&#xff1f; 近日&#xff0c;MIT和微软的学者发…

【数据分析 - 基础入门之NumPy①】Anaconda安装及使用

知识目录 前言一、 Anaconda是什么二、为什么使用Anaconda三、安装步骤3.1 下载安装3.2 配置conda源 结语 前言 大家好&#xff01;我是向阳花花花花&#xff0c;本期给大家带来的是 Anaconda 安装及使用。 每日金句分享&#xff1a;故事不长&#xff0c;也不难讲。』—— 「…

期望DP入门

期望DP一般步骤&#xff1a; 1.模拟过程&#xff0c;找出线性性质&#xff0c;作为阶段&#xff08;这本质上也是线性DP&#xff09; 2.涉及DP状态 原则&#xff1a; 体现线性性质 体现边权 根据对期望有无贡献来设计状态 一般在状态设计时需要倒着设计 3.转移 根据边…

如何将自定义字体添加到 iOS 应用程序(SwiftUI + 得意黑)

1. 工具 Xcode Version 14.3 (14E222b)SwiftUI得意黑 Smiley Sans 2. Download https://github.com/atelier-anchor/smiley-sans/releases 3. Add Files to xxx 4. Add Test Code Text("Less is more. 朱洪苇 123").font(.custom("SmileySans-Oblique",…

【电子量产工具】4. UI系统

文章目录 前言一、UI界面分析二、结构体描述按钮三、按钮初始化四、默认绘制按键事件函数五、默认按下按键事件函数六、测试程序实验效果总结 前言 最近看了 电子量产工具 这个项目&#xff0c;本专栏是对该项目的一个总结。 一、UI界面分析 UI 是用户界面&#xff08;User In…

GEE:提取地区 NDVI/LST/RVI 并进行时间序列线性插值和SG滤波

作者&#xff1a;CSDN _养乐多_ 本文将介绍使用Landsat数据集&#xff0c;构建时间序列&#xff0c;并使用线性插值算法填补缺失数据&#xff0c;或者去云空洞&#xff0c;并进一步对完整的时间序列数据进行SG滤波处理。 文章目录 一、代码二、代码链接三、需要请私聊 一、代…

OPCUA 的历史数据库/聚合服务器的实现细节

进入了AI 大数据时代&#xff0c;无论是工业自动化系统&#xff0c;还是物联网系统&#xff0c;对大数据的采集&#xff0c;存储和分析都十分重要。大数据被称为工业的石油&#xff0c;未来制造业的持续改善离不开大数据。 传统的应用中&#xff0c;历史数据的存储是特定的数据…

官方外设库SDA安装和验证

第一种方法 1.打开mobaxterm&#xff0c;通过windows浏览器打开https://github.com/orangepi-xunlong/wiringOP下载压缩包&#xff0c;点击上传外设库的压缩包 2.输入命令 unzip 解压 3.输入命令 sudo ./build 安装工具包 4.验证安装完毕用 输入gpio readall 显示下面图片 第二…

数据分析实战(基础篇):从数据探索到模型解释

前言 本文着重介绍数据分析实战的基础知识和技巧&#xff0c;探索从数据探索到建模再到模型解释的完整过程内容包含数据探索、模型建立、调参技巧、SHAP模型解释数据来源于kaggle平台&#xff0c;crab age prediction数据集&#xff0c;数据详情 数据说明 数据背景 螃蟹味道…

【性能设计篇】聊聊异步处理

在性能设计的时候&#xff0c;其实主要的三板斧就是数据库(读写分离、分库分表)&#xff0c;缓存&#xff08;提升读性能&#xff09;&#xff0c;异步处理&#xff08;提升写性能&#xff09;以及相关的秒杀设计以及边缘设计等。 本篇主要介绍异步处理的哪些事&#xff0c;我们…

6.2.1 网络基本服务---域名解析系统DNS

6.2.1 网络基本服务—域名解析系统DNS 因特网是需要提供一些最基本的服务的&#xff0c;今天我们就来讨论一下这些基本的服务。 域名系统&#xff08;DNS&#xff09;远程登录&#xff08;Telnet&#xff09;文件传输协议&#xff08;FTP&#xff09;动态主机配置协议&#x…

Day47

思维导图 练习 实现登录框中&#xff0c;当登录成功时&#xff0c;关闭登录界面&#xff0c;并跳转到其他界面 second.h #ifndef SECOND_H #define SECOND_H#include <QWidget>namespace Ui { class Second; }class Second : public QWidget {Q_OBJECTpublic:explicit …

Matlab绘图时的几个小技巧(修改刻度线长度、添加/去掉右边和上面的轴与刻度线、出图时去掉旁边的空白部分)

set(gca,TickLength,[0.005,0.035]); %修改坐标轴刻度线的长度 box on; %开启右面和上面的坐标轴 box off;%关闭右面和上面的坐标轴 set(gca, LooseInset, [0,0,0,0]);%删除掉图旁边多余的空白部分首先随便出一张图 我想让刻度线更长或更短一些&#xff1a; 我想让右侧和上面…

OpenCV的安装与配置指南(Windows环境,Python语言)

OpenCV 的安装与配置指南&#xff08;Windows环境&#xff0c;Python语言&#xff09; 导语一、安装 Python 二、安装 OpenCV 库三、配置 OpenCV 环境变量四、验证 OpenCV 安装总结 导语 OpenCV 是一个功能强大的计算机视觉库&#xff0c;广泛应用于图像处理和计算机视觉领域。…

第十二章 elk

1、ELK可以帮助我们解决哪些问题 日志分布在多台不同的服务器上,业务一旦出现故障,需要一台台查看日志 单个日志文件巨大,无法使用常用的文本工具分析,检索困难; 2、架构设计分析 Filebeat和Logstash ELK架构中使用Logstash收集、解析日志,但是Logstash对内存、cpu、i…

MySQL入门必备:Linux中部署MySQL环境的四种方式详解

目录 一、仓库安装 二、本地安装 三、Docker中安装 四、源码安装 一、仓库安装 首先需要下载mysql软件包&#xff1a; 1、进入MySQL官网 2、进入MySQL社区版下载 3、使用yum方式下载MySQL 4、下载对应版本的软件包 5、这里可以不登录直接下载软件包 6、复制下载链接 7、然…