CMU15-445-Spring-2023-Project #4 - Concurrency Control

前置知识,参考上一篇博客:CMU15-445-Spring-2023-Project #4 - 前置知识(lec15-20)

通过添加一个锁管理器在 BusTub 中支持事务,然后将其用于并发查询执行。锁管理器将支持五种锁模式下的表锁和元组锁:intention-shared、intention-exclusive、shared-intention-exclusive、shared、exclusive。锁管理器将处理来自事务的锁请求,向事务授予锁,并根据事务的隔离级别检查锁是否被适当释放。
image.png

Task #1 - Lock Manager

为确保事务操作的正确交错,DBMS 使用锁管理器(LM)来控制何时允许事务访问数据项。锁管理器的基本原理是维护一个内部数据结构,其中包含活动事务当前持有的锁。事务在访问数据项之前向 LM 发出锁请求,LM 要么授予锁,要么阻止事务直到锁可用,要么中止事务。
BusTub 系统将有一个全局 LM。当事务尝试访问或修改元组时,TableHeap 和 Executor 类将使用 LM 获取tuple record(通过 RID)上的锁。
LM 必须实现分层表级和元组级意向锁以及三个隔离级别:READ_UNCOMMITED、READ_COMMITTED 和 REPEATABLE_READ。LM 应根据事务的隔离级别授予或释放锁。

Isolation Levels (Strongest to Weakest)

  • SERIALIZABLE: 无幻读,所有读取均可重复,并且无脏读
    • Possible implementation: Index locks + Strict 2PL
  • REPEATABLE READS:可能会有幻读
    • Possible implementation: Strict 2PL
  • READ-COMMITTED:可能会发生幻读和不可重复读
    • Possible implementation: Strict 2PL for exclusive locks, immediate release of shared locks after a read
  • READ-UNCOMMITTED:所有异常情况都可能发生
    • Possible implementation: Strict 2PL for exclusive locks, no shared locks for reads

代码实现:
image.png

提供了一个事务上下文句柄(include/concurrency/transaction.h),该句柄带有隔离级别属性(即 READ_UNCOMMITED、READ_COMMITTED 和 REPEATABLE_READ)及其获取的锁的相关信息。LM 需要检查事务的隔离级别,并在lock/unlock请求中表现正确的行为。任何无效的加锁操作都会导致 ABORTED 事务状态(隐式终止)并引发异常。锁定尝试失败(如死锁)不会导致异常,但 LM 应对锁定请求返回 false。
Impl:
concurrency/lock_manager.cpp
include/concurrency/lock_manager.h

  • LockTable(Transaction, LockMode, TableOID)
    • 检查隔离级别,输出 LOCK_ON_SHRINKING 和 LOCK_SHARED_ON_READ_UNCOMMITTED 错误;
    • 获得对应 table oid 的 lock request queue;
    • 遍历 queue 看是否可以进行 lock upgrade;
    • 若当前请求的 lock 与持有的 lock 相同,返回 true;
    • 若多个 lock upgrade 并发,返回 UPGRADE_CONFLICT;
    • 检查升级是否兼容,若兼容,则 drop 当前持有的锁,然后将其插入等待 granted。如果是新的锁请求,直接将其追加到 queue 的末尾。
    • 使用 conditional variable 在 lock request queue 等待,直到拿到锁或者被abort(如果发生了死锁,task2中实现的死锁检测时有可能将该请求abort)
    • 等待的条件是:
      • 对于 granted 的 request,检查 compatibility table 是否兼容(升级兼容是指同一事务的,而这边的兼容检查是对于该 table 持有的 lock);
      • 因为条件变量的 notify 通知的是所有等待的事务,需要确保 upgrade 的请求被优先处理,即有 upgrading 标记则优先 grant(事务即真正持有锁,通过set分类别存储)
    • 将 granted 置为true。
  • UnlockTable(Transction, TableOID)
    • 只有当该事务不持有该表的任一row的锁,才能释放表粒度锁;
    • 需要确保当前事务持有锁;
    • 只有 unlock S 或 X 锁才能更新事务状态至 shrinking;
    • 事务释放锁(set进行erase),条件变量通知阻塞的 upgrade;
  • LockRow(Transaction, LockMode, TableOID, RID)
    • 基本一致,除个别规则;
  • UnlockRow(Transaction, TableOID, RID, force)
    • 基本一致,除个别规则;
    • force 参数:因为执行器实现可能需要先确定一个元组是否可访问,然后再决定是否包含它。如果 force 设为 true,操作将绕过所有 2PL 检查,就像元组没有被锁定一样,在代码中表现为不更新 txn 的状态为 shrinking;

note:request_queue_修改为共享指针类型的list。

Task #2 - Deadlock Detection

锁管理器应在后台线程中运行死锁检测,定期构建等待图(Waits-for graph),并根据需要中止事务以消除死锁。

  • AddEdge(txn_id_t t1, txn_id_t t2): Adds an edge in your graph from t1 to t2, representing that t1 is waiting for t2. If the edge already exists, you don’t have to do anything.
  • RemoveEdge(txn_id_t t1, txn_id_t t2): Removes edge t1 to t2 from your graph. If no such edge exists, you don’t have to do anything.
  • HasCycle(txn_id_t& txn_id): Looks for a cycle by using depth-first search (DFS). If it finds a cycle, HasCycle should store the transaction id of the **youngest **transaction in the cycle in txn_id and return true. Your function should return the first cycle it finds. If your graph has no cycles, HasCycle should return false.
  • GetEdgeList(): Returns a list of tuples representing the edges in your graph. We will use this to test correctness of your graph. A pair (t1,t2) corresponds to an edge from t1 to t2.
  • RunCycleDetection(): Contains skeleton code for running cycle detection in the background. You should implement your cycle detection algorithm here.

note:将 waits_for_修改为 map 类型,因为 unordered_map 是无序的。
关于GraphTest测试,discord上的解释:
image.png

Task #3 - Concurrent Query Execution

为支持并发查询执行,执行器必须根据需要锁定和解锁表和元组,以实现事务中指定的隔离级别。为了简化这项工作,可以忽略并发索引执行,只关注堆文件中存储的数据。
更新 project 3 中实施的 executors(顺序扫描、插入和删除)的 Next() 方法。请注意,事务应在 lock/unlock 失败时中止。如果事务中止,则需要撤销先前的写操作;为此,需要维护每个事务中的 write_set,事务管理器的 Abort() 方法会使用该write_set。如果执行器无法获取锁,则应抛出 ExecutionException,以便执行引擎告知用户查询失败。
不应假设一个事务只包含一个查询。具体来说,这意味着一个元组可能在一个事务中被不同的查询访问不止一次。请考虑在不同隔离级别下应如何处理。(notes:这也就是为什么在遍历lock request queue时使用迭代器,因为remove删除了所有,而erase只删除当前迭代器指向的元素)
Impl:

  • src/execution/seq_scan_executor.cpp
  • src/execution/insert_executor.cpp
  • src/execution/delete_executor.cpp
  • src/concurrency/transaction_manager.cpp

隔离级别

一般来说在获取表粒度的锁时,遵守 Multilevel Locking 的规范,统一先获取意向锁

  • 无论隔离级别如何,事务都应为所有写操作加 X 锁,直到提交或终止。
  • 对于 REPEATABLE_READ,事务应为所有读操作加 S 锁,直到提交或终止。
  • 对于 READ_COMMITTED,事务应为所有读操作加 S 锁,但可以立即释放。
  • 对于 READ_UNCOMMITTED,事务无需为读操作加任何 S 锁。

SeqScan Executor

  • 在 Init 中,获取一个表锁。使用 MakeEagerIterator 而不是 MakeIterator 来获取迭代器(在 Project 3 的 UpdateExecutor 中引入了 MakeIterator 以避免万圣节问题,但现在不需要)。
  • 在 Next 中:
    1. 获取表迭代器的当前位置。
    2. 根据隔离级别的需要锁定元组。
    3. 抓取元组。检查元组元,如果已执行过滤推送扫描,则检查谓词。
    4. 如果元组不应被该事务读取,则强制解锁该行。否则,根据隔离级别的需要解锁该行。
    5. 如果当前操作是删除(通过检查执行器上下文 IsDelete(),对于 DELETE 和 UPDATE,IsDelete() 将设为 true),则应假定扫描的所有元组都将被删除,并在第 2 步中根据需要对表和元组加 X 锁。

Insert Executor

  • 在 Init 中获取表锁
  • 在 Next 中将锁管理器、事务对象和表 id 传递给 InsertTuple,以便原子插入并锁定一个元组。请确保根据需要维护write set。

Delete Executor

  • 如果在执行器上下文中基于 IsDelete() 正确实现了 SeqScanExecutor,则无需在此执行器中使用任何锁。
  • 请确保在 Next 中维护 write set。

Transaction Manager

  • 在 Commit 中,除了释放所有锁外,一般不需要做任何事情。
  • 在 Abort 中,应根据write set还原该事务的所有更改(table和index)。

实验结果

image.png

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

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

相关文章

「解析」Jetson配置 git服务

这两天感冒了在家休养,想着把之前买的 Jetson 开发板用起来,买Jetson的初衷就是用来学习Linux系统,顺道可以部署算法,以及一些其他需求,相比树莓派而言,Jetson开发相对更贵,但是其配备了英伟达的…

电子学会C/C++编程等级考试2023年09月(八级)真题解析

C/C++编程(1~8级)全部真题・点这里 第1题:最短路径问题 平面上有n个点(n<=100),每个点的坐标均在-10000~10000之间。其中的一些点之间有连线。 若有连线,则表示可从一个点到达另一个点,即两点间有通路,通路的距离为两点间的直线距离。现在的任务是找出从一点到另一…

详细讲解Python中的aioschedule定时任务操作

目录 前言1. 基本概念2. 基本API3. Demo 前言 如果下面的函数库无法执行&#xff0c;出现类似&#xff1a;&#xff08;前提是python3.7以上&#xff09; AttributeError: module ‘asyncio‘ has no attribute ‘run‘请检查run是否可跳转&#xff0c;如果无法跳转&#xff…

element plus 可选择树形组件(el-tree) 怎样一键展开/收起?实现方法详解

实现代码&#xff1a; 按钮&#xff1a; <el-button click"takeall" style"height: 24px">{{zhanstatus % 2 ! 0 ? "收起所有" : "展开所有"}} </el-button> 组件&#xff1a; <el-form-item label"可选择菜单…

harbor https

harbor https部署 准备docker-compose安装https 证书harbor安装访问harbor推镜像到harbor 准备 192.168.112.99&#xff0c;harbor&#xff0c;centos7 192.168.112.3&#xff0c;测试机&#xff0c;centos7 docker版本&#xff1a;docker-ce 20.10.16&#xff08;部署参考&a…

Redis主从+哨兵集群(基于CentOS-8.0)高可用部署方案

目录 一、环境描述 二、Redis 主从集群部署 2.1 Redis下载 2.2 Redis解压 和移动文件 2.4 编译、安装Redis 2.6 新建 bin 和 etc 文件夹 2.7 分发Redis 2.8 配置 2.8.1 主节点配置 2.8.2 从节点配置 2.9 启动Redis服务 2.10 验证主从服务 2.11 查看节点角色信息 2…

有序矩阵中第 K 小的元素

题目链接 有序矩阵中第 K 小的元素 题目描述 注意点 每行和每列元素均按升序排序找到一个内存复杂度优于 O(n) 的解决方案 解答思路 使用二分查找&#xff0c;思路为&#xff1a; &#xff08;1&#xff09;因为左上角的元素值更小&#xff0c;右下角的元素值更大&#xf…

初识 Elasticsearch 应用知识,一文读懂 Elasticsearch 知识文集(5)

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

【Mybatis】说一下 mybatis 的一级缓存和二级缓存

​ &#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Mybatis ⛳️ 功不唐捐&#xff0c;玉汝于成 ​ 目录 前言 正文 一级缓存&#xff08;Local Cache&#xff09;&#xff1a; 范围&#xff1a; 生命周期&#xff1a; 默认开启&…

C++实战Opencv第一天——win11下配置vs,opencv环境和运行第一个c++代码(从零开始,保姆教学)

OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个开源的计算机视觉和机器学习软件库&#xff0c;它提供了大量的通用算法和功能&#xff0c;用于处理图像和视频数据。C 通常提供比 Python 更高的执行速度&#xff0c;对于需要高性能处理的任务&#x…

QT 文本框的绘制与复选框组键

.cpp文件 #include "widget.h" #include "ui_widget.h"#include<QDebug> Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//更改窗口标题setWindowTitle("我爱xyy");//更改图标setWindow…

使用VSCode内的jupyter编写R语言:绘制中国省份地区热力图

R语言绘制中国省份地区热力图教程 1、R语言的安装和编辑器的选择 对于一门从未接触过的编程语言&#xff0c;相信大家的吐槽点和我一样&#xff1a;又要安装软件&#xff0c;配置环境&#xff01;其实R语言的安装和环境配置并不复杂&#xff0c;只需要安装两部分内容&#xf…

IC验证——perl脚本ccode_standard——c代码寄存器配置标准化

目录 1 脚本名称 2 脚本路径 3 脚本参数说明 4 脚本操作说明 5 脚本代码 1 脚本名称 ccode_standard 2 脚本路径 /scripts/bin/ccode_standard 3 脚本参数说明 次序 参数名 说明 1 address (./rfdig&#xff1b;.&#xff1b;..&#xff1b;./boot) 指定脚本执行路…

【小笔记】用tsai库实现Rocket家族算法

2024.1.16 Rocket家族算法是用于时间序列分类的强baseline&#xff08;性能比较参考【小笔记】时序数据分类算法最新小结&#xff09;&#xff0c;Rocket/MiniRocket/MultiRocket官方都有开源实现&#xff0c;相比较而言&#xff0c;用tsai来实现有三个好处&#xff1a;1是快速…

WPF应用程序生存期以及相关事件

WPF 应用程序的生存期会通过 Application 引发的几个事件来加以标记&#xff0c;相关事件对应着应用程序何时启动、激活、停用和关闭。 应用程序生存期事件 • 独立应用程序(传统风格的 Windows 应用程序&#xff0c;这些应用程序作为要安装到客户端计算机并从客户端计算机运…

VitePress-01-从零开始的项目创建(npm版)

说明 本文介绍一下 VitePress的项目创建的步骤。 主要用到的命令工具是 npm。 本文的操作步骤是从无到有的创建一个完整的基本的【VitePress】项目。 环境准备 根据官方文档的介绍&#xff0c;截止本文发稿时&#xff0c;需要使用node.js 18 的版本。 可以使用node -v 的命令查…

关于java的封装

关于java的封装 我们在前面的文章中&#xff0c;了解到了类和对象的知识&#xff0c;以及做了创建对象的时候对内存的分析&#xff0c;我们本篇文章来了解一下面向对象的三大基本特征之一&#xff0c;封装&#x1f600;。 一、初识封装 封装就好比&#xff0c;我们把一些物品…

【操作系统】1. 操作系统概述

文章目录 【 1. 什么是操作系统 】【 2. 操作系统软件的分类 】【 3. 操作系统内核的抽象和特征 】3.1 操作系统内核的抽象3.2 操作系统内核的特征 【 1. 什么是操作系统 】 操作系统是管理硬件资源、控制程序运行、改善人机界面和为应用软件提供服务的一种系统 软件。一个服务…

<软考高项备考>《论文专题 - 71 风险管理(3)》

3 过程2-识别风险 3.1 问题 4W1H过程做什么是识别单个项目风险以及整体项目风险的来源&#xff0c;并记录风险特征的过程。作用:1、记录现有的单个项目风险&#xff0c;以及整体项目风险的来源:2、汇总相关信息&#xff0c;以便项目团队能够恰当地应对已识别的风险。为什么做…

怎么修改或移除WordPress后台仪表盘概览底部的版权信息和主题信息?

前面跟大家分享『WordPress怎么把后台左上角的logo和评论图标移除&#xff1f;』和『WordPress后台底部版权信息“感谢使用 WordPress 进行创作”和版本号怎么修改或删除&#xff1f;』&#xff0c;其实在WordPress后台仪表盘的“概览”底部还有一个WordPress版权信息和所使用的…