当前位置: 首页 > news >正文

4.4 版本管理器——VM实现


VM层通过VersionManager,向上层提供api接口以及各种功能,对于VM上层的模块(是使用了VM层接口的上层模块),那么操作的都是Entry结构
而VM依赖于DM,所以VM视角里(在自我实现里面),操作的是DataItem

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);
}

同时,可以看到其中有一个CacheManager,说明也是实现了抽象缓存的,用到了模板方法设计模式,这个在介绍日志模块和数据管理器时也见到过。

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

抽象缓存的实现

GetForCache
@verride
protected Entry getForCache(long uid) throws Exception {// 核心还是调用dm.read()方法Entry entry = Entry.loadEntry(this, uid);if (entry == null) {throw Error.NullEntryException;}return entry;
}
ReleaseForCache

释放缓存

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

开启事务Begin

在这里插入图片描述

//创建事务,将事务添加到活动事务的映射中,并返回新事务的ID
@Override
public long begin(int level) {lock.lock(); // 获取锁,防止并发问题try {long xid = tm.begin(); // 调用事务管理器的begin方法,开始一个新的事务,并获取事务IDTransaction t = Transaction.newTransaction(xid, level, activeTransaction); // 创建一个新的事务对象activeTransaction.put(xid, t); // 将新的事务对象添加到活动事务的映射中return xid; // 返回新的事务ID} finally {lock.unlock(); // 释放锁}
}// 创建一个新的事务:设置事务的隔离级别、隔离级别是可重复读时创建快照
public static Transaction newTransaction(long xid, int level, Map<Long, Transaction> active) {Transaction t = new Transaction();// 设置事务IDt.xid = xid;// 设置事务隔离级别t.level = level;// 如果隔离级别不为0,创建快照if (level != 0) {t.snapshot = new HashMap<>();// 将活跃事务的ID添加到快照中for (Long x : active.keySet()) {t.snapshot.put(x, true);}}// 返回新创建的事务return t;
}

提交事务Commit

主要就是 free 掉相关的结构,并且释放持有的锁,并修改事务状态

在这里插入图片描述

// Commit 公开的commit方法,用于提交一个事务
@Override
public void commit(long xid) throws Exception {lock.lock(); // 获取锁,防止并发问题Transaction t = activeTransaction.get(xid); // 从活动事务中获取事务对象lock.unlock(); // 释放锁try {if (t.err != null) { // 如果事务已经出错,那么抛出错误throw t.err;}} catch (NullPointerException n) { // 如果事务对象为null,打印事务ID和活动事务的键集,然后抛出异常System.out.println(xid);System.out.println(activeTransaction.keySet());Panic.panic(n);}lock.lock(); // 获取锁,防止并发问题activeTransaction.remove(xid); // 1、从活动事务中移除这个事务lock.unlock(); // 释放锁lt.remove(xid); // 2、从锁表中移除这个事务的锁tm.commit(xid); // 3、调用事务管理器的commit方法,进行事务的提交操作
}

中止事务Abort

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

在这里插入图片描述

@Override
// 公开的abort方法,用于中止一个事务
public void abort(long xid) {// 调用内部的abort方法,autoAborted参数为false表示这不是一个自动中止的事务internAbort(xid, false);
}// 内部的abort方法,处理事务的中止
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);// 调用事务管理器的abort方法,进行事务的中止操作tm.abort(xid);
}

读取数据Read

read() 方法读取一个 entry,需要注意判断可见性

在这里插入图片描述

//读取一个entry,注意判断可见性
@Override
public byte[] read(long xid, long uid) throws Exception {lock.lock(); // 获取锁,防止并发问题Transaction t = activeTransaction.get(xid); // 从活动事务中获取事务对象lock.unlock(); // 释放锁if (t.err != null) { // 如果事务已经出错,那么抛出错误throw t.err;}Entry entry = null;try {entry = super.get(uid); // 尝试获取数据项} catch (Exception e) {if (e == Error.NullEntryException) { // 如果数据项不存在,那么返回nullreturn null;} else { // 如果出现其他错误,那么抛出错误throw e;}}try {// 在事务隔离级别中讲解了该方法if (Visibility.isVisible(tm, t, entry)) { // 如果数据项对当前事务可见,那么返回数据项的数据return entry.data();} else { // 如果数据项对当前事务不可见,那么返回nullreturn null;}} finally {entry.release(); // 释放数据项}
}

插入数据Insert

将数据包裹成 Entry,然后交给 DM 插入即可

// 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); // 将事务ID和数据包装成一个新的数据项return dm.insert(xid, raw); // 调用数据管理器的insert方法,插入新的数据项,并返回数据项的唯一标识符
}

删除数据Delete

在这里插入图片描述

// Delete 删除一个数据项
@Override
// 删除一个数据项的方法
public boolean delete(long xid, long uid) throws Exception {// 获取锁,防止并发问题lock.lock();// 从活动事务中获取事务对象Transaction t = activeTransaction.get(xid);// 释放锁lock.unlock();// 如果事务已经出错,那么抛出错误if (t.err != null) {throw t.err;}Entry entry = null;try {// 尝试获取数据项entry = super.get(uid);} catch (Exception e) {// 如果数据项不存在,那么返回falseif (e == Error.NullEntryException) {return false;} else {// 如果出现其他错误,那么抛出错误throw e;}}try {// 如果数据项对当前事务不可见,那么返回falseif (!Visibility.isVisible(tm, t, entry)) {return false;}Lock l = null;try {// 尝试为数据项添加锁l = lt.add(xid, uid);} catch (Exception e) {// 如果出现并发更新的错误,那么中止事务,并抛出错误t.err = Error.ConcurrentUpdateException;internAbort(xid, true);t.autoAborted = true;throw t.err;}// 如果成功获取到锁,那么锁定并立即解锁if (l != null) {l.lock();l.unlock();}// 如果数据项已经被当前事务删除,那么返回falseif (entry.getXmax() == xid) {return false;}// 如果数据项的版本被跳过,那么中止事务,并抛出错误if (Visibility.isVersionSkip(tm, t, entry)) {t.err = Error.ConcurrentUpdateException;internAbort(xid, true);t.autoAborted = true;throw t.err;}// 设置数据项的xmax为当前事务的ID,表示数据项被当前事务删除entry.setXmax(xid);// 返回true,表示删除操作成功return true;} finally {// 释放数据项entry.release();}
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • if语句:悬空else问题
  • SpringBoot开发——数据校验
  • echarts3D地图:旋转、添加纹理图片(vue3)
  • 信息学奥赛初赛天天练-85-NOIP2014普及组-基础题4-链表、随机存取、顺序存取、二分查找、二分比较、循环结构、图领奖
  • RabbitMQ 应用
  • 【OJ】常用技巧
  • Mysql高级教程
  • 【电子通识】洁净度等级划分及等级标准
  • 远程桌面 Rust Desk 自建服务器
  • 使用procfs
  • 文件的时间戳
  • 【区块链 + 人才服务】基于 FISCO BCOS 联盟链的电子证书认证平台 | FISCO BCOS应用案例
  • Kubernetes 1.25 containerd 环境部署 SuperMap iManager
  • 前端工程化2:从0-1的eslint插件开发教程
  • Proxfier+burpsuite抓包配置问题
  • $translatePartialLoader加载失败及解决方式
  • 【159天】尚学堂高琪Java300集视频精华笔记(128)
  • 2018一半小结一波
  • Android组件 - 收藏集 - 掘金
  • bootstrap创建登录注册页面
  • Date型的使用
  • ECMAScript 6 学习之路 ( 四 ) String 字符串扩展
  • HTTP那些事
  • JavaScript类型识别
  • Js基础——数据类型之Null和Undefined
  • RedisSerializer之JdkSerializationRedisSerializer分析
  • Travix是如何部署应用程序到Kubernetes上的
  • 给github项目添加CI badge
  • 极限编程 (Extreme Programming) - 发布计划 (Release Planning)
  • 浏览器缓存机制分析
  • 每天一个设计模式之命令模式
  • 使用putty远程连接linux
  • 世界编程语言排行榜2008年06月(ActionScript 挺进20强)
  • 项目管理碎碎念系列之一:干系人管理
  • 分布式关系型数据库服务 DRDS 支持显示的 Prepare 及逻辑库锁功能等多项能力 ...
  • ​MPV,汽车产品里一个特殊品类的进化过程
  • ​必胜客礼品卡回收多少钱,回收平台哪家好
  • #define、const、typedef的差别
  • #pragma预处理命令
  • (007)XHTML文档之标题——h1~h6
  • (3)(3.2) MAVLink2数据包签名(安全)
  • (pojstep1.1.1)poj 1298(直叙式模拟)
  • (二)什么是Vite——Vite 和 Webpack 区别(冷启动)
  • (二)原生js案例之数码时钟计时
  • (数位dp) 算法竞赛入门到进阶 书本题集
  • (算法二)滑动窗口
  • *** 2003
  • .NET 5种线程安全集合
  • .NET Core 成都线下面基会拉开序幕
  • .net core控制台应用程序初识
  • .NET MAUI Sqlite程序应用-数据库配置(一)
  • .net 受管制代码
  • .NET导入Excel数据
  • .net与java建立WebService再互相调用
  • @PreAuthorize注解