【ETCD】【源码阅读】深入分析 storeTxnWrite.Put方法源码

该方法是 storeTxnWrite 类型中的核心方法,负责将键值对存储到数据库,同时处理键的元数据(如版本、修订号、租约)并管理租约关联。

目录

      • 一、完整代码
      • 二、方法详解
      • 方法签名
      • 1. 计算修订号并初始化变量
      • 2. 检查键是否已存在
      • 3. 生成索引修订号与字节表示
      • 4. 更新版本号并构建新的键值对
      • 5. 序列化键值对并存储
      • 6. 处理旧租约
      • 7. 绑定新租约
      • 三、总结
        • 方法的主要功能:
        • 核心步骤:

一、完整代码

func (tw *storeTxnWrite) put(key, value []byte, leaseID lease.LeaseID) {rev := tw.beginRev + 1c := revoldLease := lease.NoLease// if the key exists before, use its previous created and// get its previous leaseID_, created, ver, err := tw.s.kvindex.Get(key, rev)if err == nil {c = created.mainoldLease = tw.s.le.GetLease(lease.LeaseItem{Key: string(key)})tw.trace.Step("get key's previous created_revision and leaseID")}ibytes := newRevBytes()idxRev := revision{main: rev, sub: int64(len(tw.changes))}revToBytes(idxRev, ibytes)ver = ver + 1kv := mvccpb.KeyValue{Key:            key,Value:          value,CreateRevision: c,ModRevision:    rev,Version:        ver,Lease:          int64(leaseID),}d, err := kv.Marshal()if err != nil {tw.storeTxnRead.s.lg.Fatal("failed to marshal mvccpb.KeyValue",zap.Error(err),)}tw.trace.Step("marshal mvccpb.KeyValue")tw.tx.UnsafeSeqPut(buckets.Key, ibytes, d)tw.s.kvindex.Put(key, idxRev)tw.changes = append(tw.changes, kv)tw.trace.Step("store kv pair into bolt db")if oldLease != lease.NoLease {if tw.s.le == nil {panic("no lessor to detach lease")}err = tw.s.le.Detach(oldLease, []lease.LeaseItem{{Key: string(key)}})if err != nil {tw.storeTxnRead.s.lg.Error("failed to detach old lease from a key",zap.Error(err),)}}if leaseID != lease.NoLease {if tw.s.le == nil {panic("no lessor to attach lease")}err = tw.s.le.Attach(leaseID, []lease.LeaseItem{{Key: string(key)}})if err != nil {panic("unexpected error from lease Attach")}}tw.trace.Step("attach lease to kv pair")
}

二、方法详解

方法签名

func (tw *storeTxnWrite) put(key, value []byte, leaseID lease.LeaseID)
  • key, value []byte:键值对的字节切片。
  • leaseID lease.LeaseID:与键关联的租约 ID。如果为 lease.NoLease,表示没有租约。

1. 计算修订号并初始化变量

rev := tw.beginRev + 1
c := rev
oldLease := lease.NoLease
  • rev:新键值对的修订号,比事务起始修订号 beginRev 大 1。
  • c:表示键的 CreateRevision,初始值为当前修订号。
  • oldLease:存储键之前的租约 ID,初始值设为 lease.NoLease(无租约)。

2. 检查键是否已存在

_, created, ver, err := tw.s.kvindex.Get(key, rev)
if err == nil {c = created.mainoldLease = tw.s.le.GetLease(lease.LeaseItem{Key: string(key)})tw.trace.Step("get key's previous created_revision and leaseID")
}
  • tw.s.kvindex.Get
    • kvindex 中查找当前键是否存在(按当前修订号 rev)。
    • 如果键存在,获取:
      • created.main:键的初始创建修订号。
      • ver:键的当前版本号。
  • c = created.main:如果键已存在,将其初始创建修订号 created.main 赋值给 c
  • oldLease = tw.s.le.GetLease:查找该键关联的旧租约(如果有)。
  • tw.trace.Step:记录 “获取键的创建修订号和租约 ID” 这一步操作。

3. 生成索引修订号与字节表示

ibytes := newRevBytes()
idxRev := revision{main: rev, sub: int64(len(tw.changes))}
revToBytes(idxRev, ibytes)
  • idxRev:为键生成索引修订号:
    • main:当前修订号 rev
    • sub:当前事务中已变更的键值对数量(len(tw.changes))。
  • revToBytes:将修订号 idxRev 转换成字节数组 ibytes,用于存储到底层数据库。

4. 更新版本号并构建新的键值对

ver = ver + 1
kv := mvccpb.KeyValue{Key:            key,Value:          value,CreateRevision: c,ModRevision:    rev,Version:        ver,Lease:          int64(leaseID),
}
  • ver = ver + 1:增加键的版本号。
  • 构建新的 mvccpb.KeyValue 对象:
    • Key:键。
    • Value:值。
    • CreateRevision:键的创建修订号 c
    • ModRevision:键的最新修改修订号 rev
    • Version:键的版本号。
    • Lease:关联的租约 ID。

5. 序列化键值对并存储

d, err := kv.Marshal()
if err != nil {tw.storeTxnRead.s.lg.Fatal("failed to marshal mvccpb.KeyValue",zap.Error(err),)
}tw.trace.Step("marshal mvccpb.KeyValue")
tw.tx.UnsafeSeqPut(buckets.Key, ibytes, d)
tw.s.kvindex.Put(key, idxRev)
tw.changes = append(tw.changes, kv)
tw.trace.Step("store kv pair into bolt db")
  • 序列化:将 kv 通过 Marshal 序列化为字节数组 d
  • 存储
    • 调用 UnsafeSeqPut 将键值对存储到 Bolt DB 中。
    • 使用 kvindex.Put 更新键的索引,记录索引修订号 idxRev
    • kv 添加到事务变更列表 tw.changes 中。
  • tw.trace.Step:记录 “序列化键值对” 和 “存储到 Bolt DB” 的步骤。

6. 处理旧租约

if oldLease != lease.NoLease {if tw.s.le == nil {panic("no lessor to detach lease")}err = tw.s.le.Detach(oldLease, []lease.LeaseItem{{Key: string(key)}})if err != nil {tw.storeTxnRead.s.lg.Error("failed to detach old lease from a key",zap.Error(err),)}
}
  • 如果键之前绑定了租约 oldLease,调用 Detach 方法解除该键与旧租约的关联。
  • 如果 Detach 失败,记录错误日志。

7. 绑定新租约

if leaseID != lease.NoLease {if tw.s.le == nil {panic("no lessor to attach lease")}err = tw.s.le.Attach(leaseID, []lease.LeaseItem{{Key: string(key)}})if err != nil {panic("unexpected error from lease Attach")}
}
tw.trace.Step("attach lease to kv pair")
  • 如果指定了新租约 leaseID,调用 Attach 将键绑定到新租约。
  • 如果 Attach 失败,触发 panic。

三、总结

方法的主要功能:
  1. 检查键是否存在:如果存在,获取其创建修订号和旧租约。
  2. 生成修订号和版本号:为新键值对生成修订号和版本号。
  3. 存储键值对
    • 序列化键值对。
    • 存储到 Bolt DB。
    • 更新索引。
  4. 处理租约
    • 解除旧租约绑定。
    • 绑定新租约。
  5. 事务追踪:通过 tw.trace 记录关键步骤,便于调试和性能分析。
核心步骤:
  1. 查找旧数据与租约。
  2. 构建新的键值对(包括版本、修订号)。
  3. 存储键值对并更新索引。
  4. 管理租约绑定/解绑。

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

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

相关文章

构建高性能异步任务引擎:FastAPI + Celery + Redis

在现代应用开发中,异步任务处理是一个常见的需求。无论是数据处理、图像生成,还是复杂的计算任务,异步执行都能显著提升系统的响应速度和吞吐量。今天,我们将通过一个实际项目,探索如何使用 FastAPI、Celery 和 Redis …

go面试问题

1 Go的内存逃逸如何分析 go build -gcflags-m main_pointer.go 2 http状态码 300 请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择 301 永久移动。请求的资源已被永久的移动到新U…

JVM性能优化一:初识内存泄露-内存溢出-垃圾回收

本文主要是让你充分的认识到什么叫做内存泄露,什么叫做内存溢出,别再傻傻分不清了,别再动不动的升级服务器的内存了。 文章目录 1.基本概念1.1.内存泄露1.2.内存溢出1.3.垃圾回收1.4.内存泄露-垃圾回收-内存溢出三者的关系关系 2.代码示例2.…

安装milvus以及向量库增删改操作

首先电脑已经安装了docker windows电脑可下载yml文件 https://github.com/milvus-io/milvus/releases/download/v2.4.6/milvus-standalone-docker-compose.yml 创建milvus文件夹,并在这个目录下创建五个文件夹:conf、db、logs、pic、volumes、wal 然后…

ARP..

ARP 0 前言 真正接触到现网才发现ARP十分重要,无论是排错还是S-MLAG都需要用到ARP这个协议,以前对于ARP的理解比较混乱;所以这次对其中的主要内容做个梳理;一定要学好ARP!!! 1 ARP的概念 Ar…

单片机上电后程序不运行怎么排查问题?

1.电源检查。使用电压表测量单片机的电源电压是否正常,确保电压在规定的范围内,如常见的5V。 2.复位检查。检查复位引脚的电压是否正常,在单片机接通电源时,复位引脚通常会有一个高电平,按下复位按钮时,复位…

SKETCHPAD——允许语言模型生成中间草图,在几何、函数、图算法和游戏策略等所有数学任务中持续提高基础模型的性能

概述 论文地址:https://arxiv.org/pdf/2406.09403 素描是一种应用广泛的有效工具,包括产生创意和解决问题。由于素描能直接传达无法用语言表达的视觉和空间信息,因此从古代岩画到现代建筑图纸,素描在世界各地被用于各种用途。儿童…

Linux应用开发————mysql数据库表

mysql数据库表操作 查看表的结构 mysql> desc / describe 表名; 或者: mysql> show create table 表名; 常见数据库引擎: innodb, myISAM... 删除表 mysql> drop tabl…

【C#】实现Json转Lua (Json2Lua)

关键词: C#、JsonToLua、Json2Lua、对象序列化Lua 前提需引入NewtonsofJson,引入方法可先在Visual Studio 2019 将Newtonsoft.Json.dll文件导入Unity的Plugins下。 Json格式字符串转Lua格式字符串,效果如下: json字符串 {"1": &q…

2.4 网络概念(分层、TCP)

网络层与传输层概述 网络层: 抽象概念:网络层是基于 IP 的抽象概念,与数据链路层用 MAC 地址标记设备不同。MAC 地址是一种具体化的概念,绑定于所在的物理网络,而 IP 地址可以是固定的,也可以通过路由动态…

LabVIEW伸缩臂参数监控系统

LabVIEW开发伸缩臂越野叉车参数监控系统主要应用于工程机械中的越野叉车,以提高车辆的作业效率和故障诊断能力。系统通过PEAK CAN硬件接口和LabVIEW软件平台实现对叉车作业参数的实时监控和故障分析,具有良好的实用性和推广价值。 系统组成 系统主要由P…

多目标优化常用方法:pareto最优解

生产实际中的许多优化问题大都是多目标问题,举个例子:我们想换一份工资高、压力小、离家近的新工作,这里工资高、压力小、离家近就是我们的目标,显然这是一个多目标问题,那我们肯定想找到这三个目标同时最优的工作&…

跨站脚本攻击的多种方式——以XSS-Labs为例二十关详解解题思路

一、XSS-Labs靶场环境搭建 1.1、XSS介绍 跨站脚本攻击(XSS)_跨站脚本测试-CSDN博客https://coffeemilk.blog.csdn.net/article/details/142266454 1.2、XSS-Labs XSS-Labs是一个学习XSS攻击手法的靶场,方便我们系统性的学习掌握跨站脚本攻击…

【win10+RAGFlow+Ollama】搭建本地大模型助手(教程+源码)

一、RAGFlow简介 RAGFlow是一个基于对文档深入理解的开源RAG(Retrieval-augmented Generation,检索增强生成)引擎。 主要作用: 让用户创建自有知识库,根据设定的参数对知识库中的文件进行切块处理,用户向大…

54、库卡机器人轴的软限位设置

步骤1:将用户组改为“专家”。 步骤2:点击“投入运行”----“售后服务”-----“软件限位开关” 步骤3:就可以针对每个轴修改对应的角度值,然后点击“保存”。

0基础学前端-----CSS DAY9

0基础学前端-----CSS DAY9 视频参考:B站Pink老师 今天是CSS学习的第九天,今天开始的笔记对应Pink老师课程中的CSS第四天的内容。 本节重点:常见网页布局以及清除浮动 2. 常见网页布局 2.1 常见网页布局 有以下三种: 参考代码…

【自动化】Python SeleniumUtil 工具 开启开发者模式 自动安装油猴用户脚本等

【自动化】Python SeleniumUtil 工具 【Python】使用Selenium 操作浏览器 自动化测试 记录-CSDN博客文章浏览阅读58次。文章浏览阅读42次。【附件】Selenium chromedriver 驱动及浏览器下载。【附件】Selenium chromedriver 驱动及浏览器下载-CSDN博客。3.安装Chrome浏览器驱动…

UE5 移植Editor或Developer模块到Runtime

要将源码中的非运行时模块移植到Runtime下使用,个人理解就是一个解决编译报错的过程,先将目标模块复制到项目的source目录内,然后修改模块文件夹名称,修改模块.build.cs与文件夹名称保持一致 修改build.cs内的类名 ,每…

全志H618 Android12修改doucmentsui选中图片资源详情信息

背景: 由于当前的文件管理器在我们的产品定义当中,某些界面有改动的需求,所以需要在Android12 rom中进行定制以符合当前产品定义。 需求: 进入file文件管理器后,点击选中图片资源,选中功能按钮,获取信息,不显示“调试信息(仅开发者)”;现状是,获取信息,显示“调试信…

【WPS安装】WPS编译错误总结:WPS编译失败+仅编译成功ungrib等

WPS编译错误总结:WPS编译失败仅编译成功ungrib等 WPS编译过程问题1:WPS编译失败错误1:gfortran: error: unrecognized command-line option ‘-convert’; did you mean ‘-fconvert’?解决方案 问题2:WPS编译三个exe文件只出现u…