【MyDB】4-VersionManager 之 4-VM的实现

news2025/7/8 20:59:34

【MyDB】4-VersionManager 之 4-VM的实现

  • VM 的实现
    • VM(VersionManager)的基本定义与实现优化
    • 具体功能实现
      • begin()开启事务
      • commit()提交事务
      • abort 中止事务
      • read 读取uid对应的数据记录所在的entry
      • insert方法,插入数据
      • delete方法

VM 的实现

本章代码位于:top/xianghua/mydb/server/vm/VersionManagerImpl.java

top/xianghua/mydb/server/vm/VersionManager.java

VM(VersionManager)的基本定义与实现优化

接下来,在介绍完了VM所依赖的记录版本,事务隔离以及死锁检测后,我们来到了最终VersionManager的实现。

VM 层通过 VersionManager 接口,向上层提供用于管理事务和数据操作的基本功能。包括事务的开始,提交,回滚以及数据的插入,读取和删除,VersionManager的基本定义如下:

public interface VersionManager {
    byte[] read(long xid, long uid) throws Exception;
    long insert(long xid, byte[] data) throws Exception;
    boolean delete(long xid, long uid) throws Exception;

    long begin(int level);
    void commit(long xid) throws Exception;
    void abort(long xid);
}

同时,VM 的实现类还被设计为 Entry 的缓存,需要继承 AbstractCache<Entry>。需要实现的获取到缓存和从缓存释放的方法很简单:

@Override
protected Entry getForCache(long uid) throws Exception {
    Entry entry = Entry.loadEntry(this, uid);
    if(entry == null) {
        throw Error.NullEntryException;
    }
    return entry;
}

@Override
protected void releaseForCache(Entry entry) {
    entry.remove();
}

具体功能实现

begin()开启事务

begin() 开启一个事务,并初始化事务的结构,将其存放在 activeTransaction 中,用于检查和快照使用:

    @Override
    /**
     * 根据传入的隔离级别开启一个事务
     * level:0表示读已提交,1表示可重复读
     */
    public long begin(int level) {
        lock.lock();
        try {
            long xid = tm.begin(); // 事务管理器开启一个事务,返回一个xid
            Transaction t = Transaction.newTransaction(xid, level, activeTransaction); // 创建一个事务对象
            activeTransaction.put(xid, t); // 将事务对象放入活跃事务集合中
            return xid; // 返回事务id
        } finally {
            lock.unlock();
        }
    }

commit()提交事务

commit() 方法提交一个事务,主要就是 free 掉相关的结构,并且释放持有的锁,并修改 TM 状态:

  1. 获取事务对象

  2. 将事务对象从活跃事务集合中移除

  3. 从LockTable中释放该事务占用的资源,并提交事务

    /**
     * 提交事务
     * @param xid
     * @throws Exception
     */
    @Override
    public void commit(long xid) throws Exception {
        // 1. 获取事务对象
        lock.lock();
        Transaction t = activeTransaction.get(xid); // 获取事务对象
        lock.unlock();

        try {
            if(t.err != null) {
                throw t.err;
            }
        } catch(NullPointerException n) {
            System.out.println(xid);
            System.out.println(activeTransaction.keySet());
            Panic.panic(n);
        }
        // 2. 将事务对象从活跃事务集合中移除
        lock.lock();
        activeTransaction.remove(xid); // 将事务对象从活跃事务集合中移除
        lock.unlock();

        // 3. 从LockTable中释放该事务占用的资源,并提交事务
        lt.remove(xid); // 将事务对象从LockTable中移除
        tm.commit(xid); // 事务管理器提交事务
    }

abort 中止事务

abort 事务的方法则有两种,手动和自动。手动指的是调用 abort() 方法,而自动,则是在事务被检测出出现死锁时,会自动撤销回滚事务;或者出现版本跳跃时,也会自动回滚:

  1. 从activeTransaction中根据xid获取事务对象
  2. 从LockTable中释放该事务占用的资源,并调用事务管理器终止事务
    @Override
    public void abort(long xid) {
        internAbort(xid, false);
    }

private void internAbort(long xid, boolean autoAborted) {
    lock.lock();
    Transaction t = activeTransaction.get(xid);
    if(!autoAborted) {
        activeTransaction.remove(xid);
    }
    lock.unlock();
    if(t.autoAborted) return;
    lt.remove(xid);
    tm.abort(xid);
}

read 读取uid对应的数据记录所在的entry

read() 方法读取一个 entry,注意判断下可见性即可:

    /**
     * 读取数据
     * @param xid
     * @param uid
     * @return
     * @throws Exception
     */
    @Override
    public byte[] read(long xid, long uid) throws Exception {
        // 1. 获取事务对象
        lock.lock();
        Transaction t = activeTransaction.get(xid);
        lock.unlock();

        if(t.err != null) {
            throw t.err;
        }
        // 2. 尝试从缓存中获取对应的entry
        Entry entry = null;
        try {
            entry = super.get(uid);
        } catch(Exception e) {
            if(e == Error.NullEntryException) {
                return null;
            } else {
                throw e;
            }
        }
        // 3. 判断事务是否可见
        try {
            if(Visibility.isVisible(tm, t, entry)) {
                return entry.data();
            } else {
                return null;
            }
        } finally {
            entry.release();
        }
    }

insert方法,插入数据

insert() 则是将数据包裹成 Entry,无脑交给 DM 插入即可:

@Override
public long insert(long xid, byte[] data) throws Exception {
    lock.lock();
    Transaction t = activeTransaction.get(xid);
    lock.unlock();
    if(t.err != null) {
        throw t.err;
    }
    byte[] raw = Entry.wrapEntryRaw(xid, data);
    return dm.insert(xid, raw);
}

delete方法

delete() 方法看起来略为复杂:

在这里插入图片描述

    @Override
    public boolean delete(long xid, long uid) throws Exception {
        // 1. 获取事务对象
        lock.lock();
        Transaction t = activeTransaction.get(xid);
        lock.unlock();

        // 2. 尝试从缓存中获取对应的entry
        if(t.err != null) {
            throw t.err;
        }
        Entry entry = null;
        try {
            entry = super.get(uid);
        } catch(Exception e) {
            if(e == Error.NullEntryException) {
                return false;
            } else {
                throw e;
            }
        }
        // 3. 判断事务是否可见
        try {
            // 3.1 如果事务不可见,则返回false
            if(!Visibility.isVisible(tm, t, entry)) {
                return false;
            }
            // 3.2 如果事务可见,则尝试获取锁
            Lock l = null;
            try {
                // 尝试获取指定 xid 和 uid 的锁
                l = lt.add(xid, uid);
            } catch(Exception e) {
                // 如果加锁失败,则抛出异常,并回滚事务
                t.err = Error.ConcurrentUpdateException;
                internAbort(xid, true);
                t.autoAborted = true;
                throw t.err;
            }
            // 3.3 如果成功获取到锁,锁定并立即解锁
            if(l != null) {
                l.lock();
                l.unlock();
            }

            // 3.4 如果 entry 的 Xmax 等于当前事务的 xid,说明该 entry 已经被当前事务删除,返回 false
            if(entry.getXmax() == xid) {
                return false;
            }

            // 3.5 检查是否发生版本跳过,如果发生版本跳过,则抛出异常
            if(Visibility.isVersionSkip(tm, t, entry)) {
                t.err = Error.ConcurrentUpdateException;
                internAbort(xid, true);
                t.autoAborted = true;
                throw t.err;
            }

            // 3.6 设置 entry 的 Xmax 为当前事务的 xid,并返回 true
            entry.setXmax(xid);
            return true;

        } finally {
            // 4. 释放锁
            entry.release();
        }
    }
     t.autoAborted = true;
                throw t.err;
            }

            // 3.6 设置 entry 的 Xmax 为当前事务的 xid,并返回 true
            entry.setXmax(xid);
            return true;

        } finally {
            // 4. 释放锁
            entry.release();
        }
    }

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

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

相关文章

计算机网络 笔记 传输层

概述&#xff1a; 主要功能&#xff1a; TCP&#xff1a; 特点***&#xff1a; 数据格式&#xff1a; 连接管理***&#xff1a; 建立连接&#xff08;三次握手&#xff09; 释放连接&#xff08;四次挥手&#xff09; 应用场景 UDP&#xff1a; 特点&#xff1a; 数…

(leetcode 213 打家劫舍ii)

代码随想录&#xff1a; 将一个线性数组换成两个线性数组&#xff08;去掉头&#xff0c;去掉尾&#xff09; 分别求两个线性数组的最大值 最后求这两个数组的最大值 代码随想录视频 #include<iostream> #include<vector> #include<algorithm> //nums:2,…

《TCP 网络编程实战:开发流程、缓冲区原理、三次握手与四次挥手》

一、 TCP 网络应用程序开发流程 学习目标 能够知道TCP客户端程序的开发流程1. TCP 网络应用程序开发流程的介绍 TCP 网络应用程序开发分为: TCP 客户端程序开发TCP 服务端程序开发说明: 客户端程序是指运行在用户设备上的程序 服务端程序是指运行在服务器设备上的程序,专门…

把本地搭建的hexo博客部署到自己的服务器上

配置远程服务器的git 安装git 安装依赖工具包 yum install -y curl-devel expat-devel gettext-devel openssl-devel zlib-devel安装编译工具 yum install -y gcc perl-ExtUtils-MakeMaker package下载git&#xff0c;也可以去官网下载了传到服务器上 wget https://www.ke…

接口使用实例(1)

大家好&#xff0c;今天我们来看看接口的一些实例&#xff0c;关于如何定义和实现接口&#xff0c;相信通过这些例子&#xff0c;我们能有一些清晰的认知。 先定义一个学生类&#xff1a; 再给定一个学生数组&#xff0c;对这个对象数组中的元素进行排序&#xff08;按分数排&…

Git 版本控制:基础介绍与常用操作

目录 Git 的基本概念 Git 安装与配置 Git 常用命令与操作 1. 初始化本地仓库 2. 版本控制工作流程 3. 分支管理 4. 解决冲突 5. 回退和撤销 6. 查看提交日志 前言 在软件开发过程中&#xff0c;开发者常常需要在现有程序的基础上进行修改和扩展。但如果不加以管理&am…

跨境数据传输问题常见解决方式

在全球化经济的浪潮下&#xff0c;跨境数据传输已然成为企业日常运营的关键环节。随着数字贸易的蓬勃发展和跨国业务的持续扩张&#xff0c;企业在跨境数据处理方面遭遇了诸多棘手难题。那么&#xff0c;面对这些常见问题&#xff0c;企业该如何应对&#xff1f;镭速跨境数据传…

python-leetcode-删除链表的倒数第 N 个结点

19. 删除链表的倒数第 N 个结点 - 力扣&#xff08;LeetCode&#xff09; # Definition for singly-linked list. # class ListNode: # def __init__(self, val0, nextNone): # self.val val # self.next next class Solution:def removeNthFromEnd(self…

EasyExcel写入和读取多个sheet

最近在工作中&#xff0c;作者频频接触到Excel处理&#xff0c;因此也对EasyExcel进行了一定的研究和学习&#xff0c;也曾困扰过如何处理多个sheet&#xff0c;因此此处分享给大家&#xff0c;希望能有所帮助 目录 1.依赖 2. Excel类 3.处理Excel读取和写入多个sheet 4. 执…

lanqiaoOJ 2097:青蛙过河 ← 二分+前缀和+贪心

【题目来源】 https://www.lanqiao.cn/problems/2097/learning/ https://www.luogu.com.cn/problem/P8775 【题目描述】 小青蛙住在一条河边&#xff0c;它想到河对岸的学校去学习。小青蛙打算经过河里的石头跳到对岸。 备注&#xff1a;此图由百度 AI 创作生成 河里的石头排…

MybatisX插件快速创建项目

一、安装插件 二、创建一个数据表测试 三、IDEA连接Mysql数据库 四、选择MybatiX构造器 五、配置参数 六、项目结构

llama3学习

首先是预训练部分&#xff0c;数据注意版权和风险问题。数据去重和数据清理&#xff0c;PII人的身份信息&#xff08;人名、地址等&#xff09;。如果数据有大量PII数据则这个数据丢掉。 网页的数据&#xff0c;提取&#xff0c;代码和数学的提取的特别的方法&#xff0c;OCR…

H3CNE-31-BFD

Bidirectional Forwarding Dection&#xff0c;双向转发检查 作用&#xff1a;毫秒级故障检查&#xff0c;通常结合三层协议&#xff08;静态路由、vrrp、ospf、BGP等&#xff09;&#xff0c;实现链路故障快速检查。 BFD配置示例 没有中间的SW&#xff0c;接口down&#xff…

python学opencv|读取图像(四十七)使用cv2.bitwise_not()函数实现图像按位取反运算

【0】基础定义 按位与运算&#xff1a;两个等长度二进制数上下对齐&#xff0c;全1取1&#xff0c;其余取0。按位或运算&#xff1a;两个等长度二进制数上下对齐&#xff0c;有1取1&#xff0c;其余取0。 按位取反运算&#xff1a;一个二进制数&#xff0c;0变1,1变0。 【1】…

Ability Kit(程序框架服务)

Ability Kit&#xff08;程序框架服务&#xff09;提供了应用程序开发和运行的应用模型&#xff0c;是系统为开发者提供的应用程序所需能力的抽象提炼&#xff0c;它提供了应用程序必备的组件和运行机制。有了应用模型&#xff0c;开发者可以基于一套统一的模型进行应用开发&am…

拦截器快速入门及详解

拦截器Interceptor 快速入门 什么是拦截器&#xff1f; 是一种动态拦截方法调用的机制&#xff0c;类似于过滤器。 拦截器是Spring框架中提供的&#xff0c;用来动态拦截控制器方法的执行。 拦截器的作用&#xff1a;拦截请求&#xff0c;在指定方法调用前后&#xff0c;根…

python爬虫入门(一) - requests库与re库,一个简单的爬虫程序

目录 web请求与requests库 1. web请求 1.1 客户端渲染与服务端渲染 1.2 抓包 1.3 HTTP状态代码 2. requests库 2.1 requests模块的下载 2.2 发送请求头与请求参数 2.3 GET请求与POST请求 GET请求的例子&#xff1a; POST请求的例子&#xff1a; 3. 案例&#xff1a;…

智慧园区管理平台实现智能整合提升企业运营模式与管理效率

内容概要 在当今数字化的背景下&#xff0c;智慧园区管理平台正逐渐成为企业提升运营效率和管理模式的重要工具。这个平台汇聚了多种先进技术&#xff0c;旨在通过智能整合各类资源与信息&#xff0c;帮助企业实现全面的管理创新。 智慧园区管理平台不仅仅是一个数据处理工具…

傅里叶分析之掐死教程

https://zhuanlan.zhihu.com/p/19763358 要让读者在不看任何数学公式的情况下理解傅里叶分析。 傅里叶分析 不仅仅是一个数学工具&#xff0c;更是一种可以彻底颠覆一个人以前世界观的思维模式。但不幸的是&#xff0c;傅里叶分析的公式看起来太复杂了&#xff0c;所以很多…

PVE 虚拟机安装 Debian 无图形化界面服务器

Debian 安装 Debian 镜像下载 找一个Debian镜像服务器&#xff0c;根据需要的版本和自己硬件选择。 iso-cd/&#xff1a;较小&#xff0c;仅包含安装所需的基础组件&#xff0c;可能需要网络访问来完成安装。有镜像 debian-12.9.0-amd64-netinst.isoiso-dvd/&#xff1a;较…