tinykv project4总结

news2024/11/23 20:09:23

主要目标

实现mvcc和2pc, Percolator

partA

将存储分为三个独立的部分,lock(管理锁记录) default(存储数据),write(提交的记录),提高并行性

对于lock存储,只要存储一份(因为一个行同时只能有一个锁)。lock这个结构包含了lockttl,超时时间,lockts(应该是事务开始时间), writekind也许是用来区别读锁写锁吧。

对于数据的话,我们就用key + startTs作为key,来mvcc做

对于write,我们也用key + commotTs作为key,开始时间作为value,mvcc来做

同时我们要注意write后的话,是最先读到的,也就是我们遍历的时候要按timestamp倒序遍历。也就是说我们对key + ts这种键做排序的话,我们就是把这个key按从小到大,然后ts从大到小,实现简单,并且快(可以看看这部分比较是怎么写的(todo))

然后就是currentWrite,就是当前事务为startTs的写入

代码

func (txn *MvccTxn) CurrentWrite(key []byte) (*Write, uint64, error) {
	// Your Code Here (4A).
	iter := txn.Reader.IterCF(engine_util.CfWrite)
	key_ts := EncodeKey(key, TsMax)
	iter.Seek(key_ts)
	for ; iter.Valid(); iter.Next() {
		key_raw := iter.Item().Key()
		ts := decodeTimestamp(key_raw)
		key_1 := DecodeUserKey(key_raw)
		if !bytes.Equal(key, key_1) {
			return nil, 0, nil
		}
		if ts < txn.StartTS {
			return nil, 0, nil
		}
		val, err := iter.Item().Value()
		if err != nil {
			panic("val err")
		}
		write, err_p := ParseWrite(val)
		if err_p != nil {
			panic("parse err")
		}
		if write.StartTS == txn.StartTS {
			return write, ts, nil
		}

	}
	return nil, 0, nil
}

然后MostRecentWrite,就是以最大version读的write,也就是当前时刻的write

代码

func (txn *MvccTxn) MostRecentWrite(key []byte) (*Write, uint64, error) {
	// Your Code Here (4A).
	iter := txn.Reader.IterCF(engine_util.CfWrite)
	key_ts := EncodeKey(key, TsMax)
	iter.Seek(key_ts)
	if iter.Valid() {
		key_raw := iter.Item().Key()
		ts := decodeTimestamp(key_raw)
		key_1 := DecodeUserKey(key_raw)
		if !bytes.Equal(key, key_1) {
			return nil, 0, nil
		}
		val, err := iter.Item().Value()
		if err != nil {
			panic("val err")
		}
		write, err_p := ParseWrite(val)
		if err_p != nil {
			panic("parse err")
		}
		return write, ts, nil

	}
	return nil, 0, nil
}

PartB

需要上真锁latch,因为可能检查完,变了,然后变了还应用的话,就出错了。

KVPreWrite:针对每个 key,首先检验是否存在写写冲突(就是有没有startTS后有没有commit的,用currentWrite来查就行了)(可以阅读参考资料:有证明的),再检查是否存在行锁,如存在则需要根据所属事务是否一致来决定是否返回 KeyError,最后将 key 添加到 CFDefault 和 CFLock 即可。感觉顺序一般都是要先default,lock这样来做的

KVCommit:针对每个 key,首先检查是否存在行锁,如不存在则已经 commit 或 rollback,如存在则需要根据 CFWrite 中的当前事务状态来判断是否返回 KeyError(1.不是当前事务的锁,重试2.如果没锁的话, 已经write的是rollback的话,就放回abort),最后将 key 添加到 CFWrite 中并在 CFLock 中删除即可(注意有一些已经commit了)

KvGet.首先检查行锁,如为当前事务所锁,则返回 Error(可能是因为正在更新,lock解开后,才有write commit),否则调用 mvcc 模块的 GetValue 获得快照读即可。(之前更新的commitversion < startVersion都能读到)

partC

KvCheckTxnStatus:以primaykey做标识,别的key都要有指针来指向他,作为事务状态的标识:1.timeout,回滚改行事务(主要tinykv是混合时钟,所以我们要拿出physical部分来做)  2.lock,那么我们可以等待重试,返回locktll。3.如果已经超时回滚的话,也就是没lock,同时write为空的话,我们就写入write里面标记rollback。4.剩下的是已经commit的

KvBatchRollback:针对每个 key,首先检查是否存在行锁,如果存在则删除 key 在 CFLock 和 CFValue 中的数并且在 CFWrite 中写入一条 rollback 即可(Rollback是以startTs为writeVersion的)[参考文末的的图片].如果不存在或者不归当前事务锁定,则从 CFWrite 中获取当前事务的提交信息,如果不存在则向 CFWrite 写入一条 rollback。存在write,如果不是rollback的的话,我们就要返回abort错误。

KvResolveLock:针对每个 key,根据请求中的参数决定来 commit 或者 rollback 即可。

KvResolveLock代码如下:

func (server *Server) KvResolveLock(_ context.Context, req *kvrpcpb.ResolveLockRequest) (*kvrpcpb.ResolveLockResponse, error) {
	// Your Code Here (4C).
	resp := new(kvrpcpb.ResolveLockResponse)
	txn := server.mvccGenerate(req.StartVersion, req.Context)
	iter := txn.Reader.IterCF(engine_util.CfLock)
	for {
		if !iter.Valid() {
			break
		}
		key := iter.Item().Key()
		value, err := iter.Item().Value()
		iter.Next()
		if err != nil {
			panic(err)
		}
		lock, err_lock := mvcc.ParseLock(value)
		if err_lock != nil {
			panic(err_lock)
		}
		write, _, _ := txn.CurrentWrite(key)
		if lock != nil && lock.Ts != txn.StartTS {
			// other transaction locked the key
			continue
		}
		if write == nil {
			if req.StartVersion < req.CommitVersion {
				// commit
				txn.DeleteLock(key)
				txn.PutWrite(key, req.CommitVersion, &mvcc.Write{StartTS: req.StartVersion, Kind: mvcc.WriteKindPut})
			}
			if req.StartVersion > req.CommitVersion {
				// rollback
				txn.DeleteValue(key)
				txn.DeleteLock(key)
				txn.PutWrite(key, req.StartVersion, &mvcc.Write{StartTS: req.StartVersion, Kind: mvcc.WriteKindRollback})
			}
		}
	}
	server.storage.Write(req.Context, txn.Writes())

	return resp, nil
}

Scanner 扫描到没有 key 或达到 limit 阈值即可。针对 scanner,需要注意不能读有锁的 key,不能读未来的版本(也就是生产了个快照),不能读已删除或者已 rollback 的 key 

首先我们前面的封装了一下这个必要的细节,所以,我们要再写个新的定制分装

scanner

结构如下

type Scanner struct {
	// Your Data Here (4C).
	txn    *MvccTxn
	preKey []byte
	iter   engine_util.DBIterator
}

我们要mvccTxn来分装一下事务操作,这是必要的。然后preKey就是防止有多个key version,但是只要返回一个最新的key就行,用这个来防止放回重复,然后就是default列的iter,当然iter是用来查next key的,我们还要拿这个key,去到writecf里面找第一个不是version,且这个write不是回滚操作的.同时scan有错误,不停在操作,记录错误在kvpair里面

代码如下(注意key有没有ts)

func (scan *Scanner) Next() ([]byte, []byte, error) {
	// Your Code Here (4C).
	for {
		if !scan.iter.Valid() {
			return nil, nil, ErrEnd{}
		}
		key := scan.iter.Item().KeyCopy(nil)
		// value, err := scan.iter.Item().ValueCopy(nil)
		// ts := decodeTimestamp(key)
		user_key := DecodeUserKey(key)
		scan.iter.Next()
		// the same key with preKey should continue
		if bytes.Equal(user_key, scan.preKey) {
			continue
		}
		iter := scan.txn.Reader.IterCF(engine_util.CfWrite)
		key_ts := EncodeKey(user_key, scan.txn.StartTS)
		iter.Seek(key_ts)
		for {
			if !iter.Valid() {
				break
			}
			key_raw := iter.Item().Key()
			ts := decodeTimestamp(key_raw)
			key_1 := DecodeUserKey(key_raw)
			if !bytes.Equal(user_key, key_1) {
				// no write on the key
				break
			}
			scan.preKey = user_key
			val, err := iter.Item().Value()
			if err != nil {
				panic("val err")
			}
			iter.Next()
			write, err_p := ParseWrite(val)
			if err_p != nil {
				panic("parse err")
			}

			if write.Kind == WriteKindPut && ts <= scan.txn.StartTS {
				// find the latest
				log.Infof("ts{%v} timestamp{%v}", ts, scan.txn.StartTS)
				scan.iter.Seek(EncodeKey(user_key, write.StartTS))
				value, err := scan.iter.Item().ValueCopy(nil)
				if err != nil {
					return nil, nil, err
				}
				return user_key, value, nil
			}
			if (write.Kind == WriteKindRollback || write.Kind == WriteKindDelete) && ts <= scan.txn.StartTS {
				// if deleted, impossible
				if write.Kind == WriteKindDelete {
					break
				}
				// if rollback, look back
				continue
			}

		}
	}

	return nil, nil, nil
}

Ref:注意本文只总结了api的细节,接下来要做大局的探讨很深入(todo)

TiKV 源码解析系列文章(十二)分布式事务 - 知乎

TiKV 事务模型概览,Google Spanner 开源实现 | PingCAP

PolarDB 数据库内核月报

Async Commit 原理介绍丨 TiDB 5.0 新特性 | PingCAP

我在lab实现了这个判断 

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

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

相关文章

chatgpt赋能python:用Python编写聊天机器人:打造AI智能助手

用Python编写聊天机器人&#xff1a;打造AI智能助手 简介 聊天机器人在现代生活中越来越受欢迎。一个好的聊天机器人能够回答我们的问题、执行任务、提供娱乐&#xff0c;甚至成为我们的朋友。Python是一种强大的编程语言&#xff0c;其模块化和易学的特性使其成为开发聊天机…

GPT-4在药物发现中的作用|景联文科技

GPT-4是一种生成式AI模型&#xff0c;可以响应文本和图像&#xff0c;它代表了生成式AI可能实现的重大进步。 药物发现的最早任务之一是检索和观察与靶蛋白结合的已知分子。这可能会导致一种基于知识的筛选方法&#xff0c;人们试图通过仅检查这些分子来进行筛选。我们让GPT-4…

【MySQL数据库的表连接语句】

目录 一、连接查询1、inner join(内连接)2、left join(左连接)3、right join(右连接) 二、CREATE VIEW三、UNION取非交集的值 五、CASE六、空值(NULL) 和 无值() 的区别 一、连接查询 A表 B表 UPDATE store_info SET store_nameWashington WHERE sales300;#修改一下表里面的…

chatgpt赋能Python-python自动化办公真的有用吗_知乎

简介 如今&#xff0c;Python作为一种必学的编程语言&#xff0c;已经走进了各行各业的办公场景。Python自动化办公也逐渐成为了一个热门话题&#xff0c;很多人开始使用Python来进行一些机械化、重复性的办公工作&#xff0c;例如数据清洗、文本处理、文件管理、自动发送邮件…

专业CPU信息检测工具:CPU-Z

今天小编为大家测试了一款轻量级的CPU处理器的测试工具&#xff0c;可以查看CPU的详细信息&#xff0c;以供各位同学们学习。 一、简单介绍 CPU-Z是一款非常流行的CPU检测软件&#xff0c;被广大用户所熟知。它是目前最受欢迎的CPU检测软件之一&#xff0c;除了Intel和AMD自带…

chatgpt赋能python:Python自动化填表:省时省力的数据录入方式

Python自动化填表&#xff1a;省时省力的数据录入方式 现代社会&#xff0c;数据填写是我们日常工作中不可避免的一项任务。但手动填写数据不仅费时费力&#xff0c;还容易出错。那么有没有一种方法可以既省时又省力呢&#xff1f;答案是有的&#xff0c;那就是Python自动化填…

Swagger与knife4j接口文档组件详解

swagger介绍 相信无论是前端还是后端开发&#xff0c;都或多或少地被接口文档折磨过。前端经常抱怨后端给的接口文档与实际情况不一致。后端又觉得编写及维护接口文档会耗费不少精力&#xff0c;经常来不及更新。其实无论是前端调用后端&#xff0c;还是后端调用后端&#xff…

【数据挖掘】——常见算法对比和选择

&#x1f935;‍♂️ 个人主页&#xff1a;Lingxw_w的个人主页 ✍&#x1f3fb;作者简介&#xff1a;计算机科学与技术研究生在读 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01; &#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4…

2022(一等奖)D678基于改进结构函数法的大气气溶胶遥感反演

作品介绍 1 应用背景 大气气溶胶是大气中重要的成分之一&#xff0c;是悬浮于大气中的固体和液体微粒与它们的气体载体共同组成的多相体系&#xff0c;其尺度大约在10-3到102 μm之间。大气气溶胶的特性对空气质量具有良好的指示作用&#xff0c;气溶胶的研究对空气质量的监测…

读发布!设计与部署稳定的分布式系统(2版)笔记12_超时模式

1. “模式采用量”绝不是好的质量指标 1.1. 应该形成一种“面向恢复”的思维模式 1.2. 良好的模式能为开发工程师提供架构和设计方面的指导&#xff0c;从而减少、消除或缓解系统中的裂纹产生的影响 1.2.1. 在新发布软件后&#xff0c;它们能让你睡个安稳觉 2. 超时 2.1. …

车载网络测试 - CANCANFD - 基础篇_04

9、CAN报文包含帧格式 1&#xff09;数据帧 2&#xff09;远程帧 3&#xff09;错误帧 4&#xff09;过载帧 SOF&#xff1a;Start Of Frame&#xff0c;帧起始位&#xff1b;一个显性位&#xff0c;表明一帧的开始 RTR&#xff1a;Remote Transmission Request&#xff0c;远…

数字孪生世界建设核心能力:数字孪生高效建模能力

创建高保真的数字孪生体虚拟模型是构建数字孪生应用的重要步骤之一&#xff0c;需要真实的再现物理实体的几何图形、属性、行为和规则等。数字孪生体模型不仅要在几何结构上与物理实体保持一致&#xff0c;更重要的是要能模拟物理实体的时空状态、行为、功能等。 1、三维数字孪…

python爬虫之Scrapy框架--日志信息--数据提取

目录 Scrapy日志信息 了解日志信息 关于日志信息的重要性 利用日志信息进行调试和优化 Scrapy数据的提取 选择器&#xff08;Selector&#xff09;的基本使用 Item的定义与使用 数据处理与管道&#xff08;Pipeline&#xff09; Scrapy日志信息 在开发和调试过程中&a…

chatgpt赋能python:Python能跨平台吗?一文详解

Python 能跨平台吗&#xff1f;一文详解 Python 是一种高级编程语言&#xff0c;自问世以来就一直备受欢迎。其简洁明了的语法&#xff0c;高效率的开发和优秀的文档支持为 Python 赢得了数量众多的粉丝。与其他编程语言相比&#xff0c;Python 最大的优势之一是其可在多个操作…

基于Java应急资源管理系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a; ✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精…

什么是HuggingFace

一.HuggingFace简介 1.HuggingFace是什么 可以理解为对于AI开发者的GitHub&#xff0c;提供了模型、数据集&#xff08;文本|图像|音频|视频&#xff09;、类库&#xff08;比如transformers|peft|accelerate&#xff09;、教程等。 2.为什么需要HuggingFace 主要是HuggingFace…

机器学习——决策树算法

一、实验目的 掌握如何实现决策树算法&#xff0c;用并决策树算法完成预测。 二、实验内容 本次实验任务我们使用贷款申请样本数据表&#xff0c;该数据表中每列数据分别代表ID、年龄、高薪、有房、信贷情况、类别&#xff0c;我们根据如下数据生成决策树&#xff0c;使用代…

Python基础 P7 字典和集合

文章目录 Python基础 P7 字典和集合字典字典基础内置函数增操作fromkeys()删操作pop()、popitems()和clear()改操作update()查操作get()和in/not in视图对象keys(),values(),items()拷贝copy()setdefault() 其他函数键值数量len()列表转换list()迭代器转换iter()逆向序列revers…

【初识C语言(1)】变量和常量

文章目录 1. 局部变量和全局变量2. 变量的作用域和生命周期3. 常量 生活中的有些值是不变的&#xff08;比如&#xff1a;圆周率&#xff0c;性别&#xff0c;身份证号码&#xff0c;血型等等&#xff09;有些值是可变的&#xff08;比如&#xff1a;年龄&#xff0c;体重&…

GitHub 上数百万个存储库可能容易被劫持

GitHub 上数以百万计的企业软件存储库很容易受到重新劫持&#xff0c;这是一种相对简单的软件供应链攻击&#xff0c;威胁行为者将依赖于特定存储库的项目重定向到恶意攻击。 研究人员在本周的一份报告中表示&#xff0c;这个问题与 GitHub 用户或组织更改项目名称或将其所有权…