CMU 15-445 Project 2 B+ Tree 技术总结

2024-05-08 14:18
文章标签 技术 总结 15 tree 445 project cmu

本文主要是介绍CMU 15-445 Project 2 B+ Tree 技术总结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

首先是教科书的伪代码

感觉基本都要按这个来写,不然(可能)写不出来的,PPT 的讲解也不够详细。Project 的代码结构的确是根据这个伪代码来设计的。不过我感觉这种写法的伪代码有点难看。

并发的要点

基本做 lab 的过程就是全程对着上面两个 guideline 来操作。

然后是我的一些技术总结踩坑的地方(可能会没有帮助 )

  1. 锁的顺序,死锁。
  2. 实现的方法是某些方法保证进来之前获取锁,谁用到锁谁释放。
  3. 学习了怎么用条件编译实现无虚函数继承的多态方法。
  4. 边界条件不知道怎么解决只想到用 bool 来暴力编程。
  5. 异常的问题,理论上不 unique 的应该正常返回,which 要求 release 所有的锁。

all tests passed 之后总结一下

首先是浪费时间 accidental 的事情

  • 这里感谢 discord 的一个主管人的解释以及discord上各位前人的探索,autograder fail 的情况可能是超时或者内存,部分前人提到与不兼容的C++17有关,我于是解决了第一个 auto [] 解包的不兼容,但是这里我的思考不够坚定,我看到了有人用 constexpr + NOLINT(这个 NOLINT 也感谢 discord 的小伙伴)还点赞的(说明他通过了),但是我还是纠结在 constexpr 导致花了一些时间去掉 constexpr 和尝试其他的语句会不会有不兼容,但是实际我也看到了有的人提到了 log 的问题,但是一开始我还是没有尝试 upload 我的 logger,最后还是靠  upload logger 来解决的。。还要感谢一个人说的从 base code 开始一点添加和修改直到不能通过(二分法)。我的思考方法还得提升 since 之前我 buffer pool 里面是改了 bug 才通过的,由此应该能够得到结论是 bufferpool 超时(deadlock) 了,和标准和 assert include 头无关。而 local test 的时候也的确发现了打 log 花的时间是几千倍。
  • 第一个是我没有去掉 log 然后就 上传,导致运行不了(花时间太长了)。
  • 而 autograder 的 logger 又是没用的, 他用 constexpr 定义了 logger 这个无法生效,需要改成 define 的,然后上传的时候避免超时必须禁用所有(默认开 debug 和 trace)。

第二个是一些错误点(解决 logger 问题后从35分到满分只花不到一个小时而且有 25 名在一堆没用 constexpr if 的情况下)

  • 我一开始因为有的地方(比如 root page)需要 acquire 到 latch 之后马上 enqueue,所以我把这两布写在一起了。然而实际是你 acquire 到 child  的 latch 之后要判断 ancestor 的之后保留自己的。所以必须先保存这个 latch,等判断玩 ancestor 的之后再 出que。
  • Unpin 的问题,我做的时候写了一个 PageResource RAII 类来进行 Page 的 unpin ,dirty 写回,删除等管理。当时出了问题。Debug 的时候我一开始把所有的 PageResource 都去掉了,导致 delete 的时候可能会有一些 pined 值大于等于 1 的情况,这个很明显是我搞错了。
  • 在 FindLeafPage 里面 enque 那些是不用 unpin 的,因为他们的 unpin 会延迟进行,但是其他函数比如 CoalesceOrRedistibute 和 Redistibute 都会 fetch parent 或者中间的 sibling,其实 sibling 可以加入到 queue 里也可以不加(因为有 parent 被锁了,安全),这些 pin 是没有对应的 unpin 的所以 RAII PageResource 还是要到位的。
  • 但是奇怪的是好像我拿满分的那个版本的确会去掉了部分 PageResource,我还认为这是正确方案。
  • 用了 constexpr if 的结果反而没有加快,(4.33->4.34),这一点不管了,不过可能是我 get value 改用了 统一返回 tuple 的 FindLeafPagePro 进行了更多数据相关引发的平衡了 constexpr 的效果?或者编译器本来就把我那些非 constexpr if 优化成 constexpr if。这个的确难讲)。
  • 然后还有一个多谢博客园大佬,于是我改了 FindLeafPage 的 return value 。主要是他对一个问题的分析:

我发现,在执行删除操作之间,有另一个线程,对需要被删除的叶子节点进行了Fetch、加锁、解锁,但并没有unpin

也就是说,问题的根源在于,解锁与Unpin不是原子的

要想解决这个问题,方案有两个:

  1. 让解锁与Unpin变成原子的。这需要引入一把新的锁。
  2. 在删除时,若发现Pin Count不为0,则sleep一段时间。等待另一个线程unpin。若苏醒后发现Pin Count仍不为0,则不断循环。

方案2比较简单,因此我选择了方案2。在这之后,问题迎刃而解,测试通过。

From <CMU15-445 Lab2 B+Tree全记录 - sun-lingyu - 博客园>

为了适合多核的情况,我没有修改 BufferPool (since 这个本来就不是 buffer pool 的问题),只需要在 remove 的函数里 delete 失败(根据 bufferpool 的API规定 pined 值大于 0 必须 return false 而不进行 deletee)的话就 spin 一定的次数,直到 delete 成功。这个能 work 是因为 spin 的话,多核如果执行到了 unpin 那么下一个循环过程马上就能 delete 成功。

其他总结

  • 这次总的时间花了挺长的,到现在也差不多半个月了,buffer pool 之后国庆节基本没动手,到 10 月 8日才开始做这个,checkpoint 1 通过是 10 月 12 日,之后一致拖到今天(10月22日)才全部完成。历时 16 天,checkpoint 2 历时 10 天,虽然其中学 Cmake 花了一些时间。总的来说压力还是不够大,接下来事情很多得加大压力才行了。同时马上开始了 query 的 project 3。
  • C++ 也重温了不少东西,一个是一开始我感觉那个不用虚函数的多态太坑了,当时是必要的不然虚函数表就能把on disk数据结构打乱,但是其实 C++ 也提供了 元编程的工具编译器生成代码,is_same_v 和 constexpr if 还是不错的,用上之后 runtime 应该没有这么多 if else 负担。所以通过 template 来实现多态(duck typing)其实也是一个方案。
  • 然后是 tuple,实际编程才体会到多返回值是有用的,虽然用参数也不是不行。之后多习惯 auto 解包吧(虽然445 编程不能用 auto 解包)。
  • RAII 的确很好,但是这里他的框框太多了,我有点难说怎么实现一个好的 PageResource 反而让这个 RAII 类很臃肿,所以我实际是简单问题复杂化了,实际如果可以手动管理所有的情况,上RAII包装类可能复杂化了,或者说我提供的选项不够多?除非修改他原有的函数的传参的方法。不过最终起码还是解决我忘记 unpin 的问题的,之后继续学习熟悉。
  • const 的理解,一定要用 clang-tidy 等静态分析工具,这次加深了 code review 的重要。我一开始以为 const & 是可以修改他本身的,但是我错了。必须加深这个记忆,即 const 和 非 const 函数也是搬过来的。总之就一定是修改对象本身的时候用 pointer,读取对象的话才用 const & 而永远不要单独使用 &。(虽然 effective c++ 看到过,但是果然不实践的话是记不住的)。
  • 对多线程的东西更加魔怔了,首先断点的不能用的,必须要打 log,因此也养成写 LOG 的好习惯,一开始我的 log 乱写,导致看起来很难受。然后是 thread id,这里我没办法(而且他的 logger 本身好像并不是线程安全的,有一些乱序,之后研究一下异步 logger 怎么写吧)。
  • 然后就是测试的 down scale 和找特征,不一定要很大规模才能复现,这里 B+ tree 的话主要就是和 page 支持的 size 和 插入的数量有关,多用二分法。
  • 数据结构体这个 debug 思路真的值得学习。
  • 对于原子性更加理解,就是博客园大佬说的那个情况,这个分析和情况都很值得记住。
  • 思考过程就是说怎么排除问题怎么分析问题,这个在 accidental 分析里说了,之后还要持续优化提高才行。
  • B+ tree 本身的话,我一开始没有理解为什么判断的时候用的条件不一样,我感觉 project 设计得的确有些不妥。这一种 B+ tree 本身的规定是
    • 每个结点至多有m 个键;
    • 除根结点外,每个结点至少有[m/2]个子女,根结点至少有两个子女;

如果定义的时候用的是至多 m 个子女又另说了。所以这部分很歧义(主要是他计算一个 4096 bytes 的 page 内的数量又没有留空一个来 move)。

这篇关于CMU 15-445 Project 2 B+ Tree 技术总结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/970548

相关文章

Python中logging模块用法示例总结

《Python中logging模块用法示例总结》在Python中logging模块是一个强大的日志记录工具,它允许用户将程序运行期间产生的日志信息输出到控制台或者写入到文件中,:本文主要介绍Pyt... 目录前言一. 基本使用1. 五种日志等级2.  设置报告等级3. 自定义格式4. C语言风格的格式化方法

Spring 依赖注入与循环依赖总结

《Spring依赖注入与循环依赖总结》这篇文章给大家介绍Spring依赖注入与循环依赖总结篇,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. Spring 三级缓存解决循环依赖1. 创建UserService原始对象2. 将原始对象包装成工

MySQL中查询和展示LONGBLOB类型数据的技巧总结

《MySQL中查询和展示LONGBLOB类型数据的技巧总结》在MySQL中LONGBLOB是一种二进制大对象(BLOB)数据类型,用于存储大量的二进制数据,:本文主要介绍MySQL中查询和展示LO... 目录前言1. 查询 LONGBLOB 数据的大小2. 查询并展示 LONGBLOB 数据2.1 转换为十

Python中高级文本模式匹配与查找技术指南

《Python中高级文本模式匹配与查找技术指南》文本处理是编程世界的永恒主题,而模式匹配则是文本处理的基石,本文将深度剖析PythonCookbook中的核心匹配技术,并结合实际工程案例展示其应用,希... 目录引言一、基础工具:字符串方法与序列匹配二、正则表达式:模式匹配的瑞士军刀2.1 re模块核心AP

在Java中实现线程之间的数据共享的几种方式总结

《在Java中实现线程之间的数据共享的几种方式总结》在Java中实现线程间数据共享是并发编程的核心需求,但需要谨慎处理同步问题以避免竞态条件,本文通过代码示例给大家介绍了几种主要实现方式及其最佳实践,... 目录1. 共享变量与同步机制2. 轻量级通信机制3. 线程安全容器4. 线程局部变量(ThreadL

springboot自定义注解RateLimiter限流注解技术文档详解

《springboot自定义注解RateLimiter限流注解技术文档详解》文章介绍了限流技术的概念、作用及实现方式,通过SpringAOP拦截方法、缓存存储计数器,结合注解、枚举、异常类等核心组件,... 目录什么是限流系统架构核心组件详解1. 限流注解 (@RateLimiter)2. 限流类型枚举 (

Python实现PDF按页分割的技术指南

《Python实现PDF按页分割的技术指南》PDF文件处理是日常工作中的常见需求,特别是当我们需要将大型PDF文档拆分为多个部分时,下面我们就来看看如何使用Python创建一个灵活的PDF分割工具吧... 目录需求分析技术方案工具选择安装依赖完整代码实现使用说明基本用法示例命令输出示例技术亮点实际应用场景扩

Spring Boot 与微服务入门实战详细总结

《SpringBoot与微服务入门实战详细总结》本文讲解SpringBoot框架的核心特性如快速构建、自动配置、零XML与微服务架构的定义、演进及优缺点,涵盖开发环境准备和HelloWorld实战... 目录一、Spring Boot 核心概述二、微服务架构详解1. 微服务的定义与演进2. 微服务的优缺点三

PowerShell中15个提升运维效率关键命令实战指南

《PowerShell中15个提升运维效率关键命令实战指南》作为网络安全专业人员的必备技能,PowerShell在系统管理、日志分析、威胁检测和自动化响应方面展现出强大能力,下面我们就来看看15个提升... 目录一、PowerShell在网络安全中的战略价值二、网络安全关键场景命令实战1. 系统安全基线核查

Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式

《Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式》本文详细介绍如何使用Java通过JDBC连接MySQL数据库,包括下载驱动、配置Eclipse环境、检测数据库连接等关键步骤,... 目录一、下载驱动包二、放jar包三、检测数据库连接JavaJava 如何使用 JDBC 连接 mys