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

【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. 管理租约绑定/解绑。

相关文章:

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

该方法是 storeTxnWrite 类型中的核心方法,负责将键值对存储到数据库,同时处理键的元数据(如版本、修订号、租约)并管理租约关联。 目录 一、完整代码二、方法详解方法签名1. 计算修订号并初始化变量2. 检查键是否已存在3. 生成索…...

MySQL技术:深入理解索引与优化

MySQL是一个广泛使用的开源关系型数据库管理系统。它以其高性能、可靠性和易用性而闻名。在数据库操作中,查询优化是一个非常重要的环节,而索引是实现查询优化的关键技术之一。本文将深入探讨MySQL中的索引原理、类型以及如何优化索引以提高数据库性能。…...

【广东-东莞】《东莞市政府投资信息化项目造价指南》-省市费用标准解读系列26

2023年6月27日,东莞市发展和改革局发布《东莞市政府投资信息化项目造价指南(试行)》,此指南由东莞市政府投资项目评审中心编制,指南旨在完善东莞市为规范政府投资信息化项目造价计费方式,高质量、高效率推进…...

8、基于SpringBoot的房屋租赁系统

摘 要 社会的发展和科学技术的进步,互联网技术越来越受欢迎。网络计算机的生活方式逐渐受到广大人民群众的喜爱,也逐渐进入了每个用户的使用。互联网具有便利性,速度快,效率高,成本低等优点。 因此,构建符…...

SLM510A系列——24V,15到150mA单通道可调电流线性恒流LED驱动芯片

SLM510A 系列产品是单通道、高精度、可调电流线性恒流源的 LED 驱动芯片,在各种 LED 照明产品中非常简单易用。其在宽电压输入范围内,能保证极高的输出电流精度,从而在大面积的光源照明中,都能让 LED 照明亮度保持均匀一致。 由于…...

深度学习试题及答案解析(一)

1. 一幅256*256的图像,若灰度级数为16,则存储它所需的比特数是() 2. 在深度学习中,涉及大量的矩阵相乘,现在需要计算三个稠密矩阵A,B,C的乘积ABC,假设三个矩阵的尺寸分别为m∗n&…...

【钉钉群聊机器人定时发送消息功能实现】

Java实现 钉钉群聊机器人定时发送消息功能 钉钉群聊准备工作钉钉发起群聊创建项目群打开钉钉群聊设置打开机器人管理选择Webhook机器人添加机器人安全设置保存Webhook地址(重点是token) 项目代码实现添加依赖启动类添加定时任务启动扫描编写调度任务定义…...

uni-app多环境配置动态修改

前言 这篇文章主要介绍uniapp在Hbuilderx 中,通过工程化,区分不同环境、动态修改小程序appid以及自定义条件编译,解决代码发布和运行时手动切换问题。 背景 当我们使用uniapp开发同一个项目发布不同的环境二级路径不同时,这时候…...

verilog代码连线集成工具的实践

目录 引言 代码解析 解析器的需求 数据结构 基础class 集合class: 界面 模块例化里界面 连线界面 连线界面示例 消息传递 引言 工作中经常需要开发很多自动化的脚本或者小工具来提升开发效率。在没有读《Cad Frameworks: Principles And Architecture》…...

【深入STL:C++容器与算法】深度解析string类的使用

文章目录 1️⃣什么是stringstring的设计以及编码问题 2️⃣string的重要接口💫💫一、string的初始化二、string的赋值三、string的长度四、string元素获取1. char& at(size_t pos)2. operaotr []3. front和back 五、迭代器1. 什么是迭代器2. 范围fo…...

【ChatGPT】解锁AI思维链:如何让机器像人类一样思考?

在人工智能领域,我们一直在追求让机器像人类一样思考。然而,即使是最先进的AI,也常常被诟病缺乏“常识”,难以理解复杂问题,更不用说像人类一样进行逻辑推理和解决问题了。最经常的表现就是遇到不会的地方,…...

用 Python 从零开始创建神经网络(十七):回归(Regression)

回归(Regression) 引言1. 线性激活(Linear Activation)2. 均方误差损失(Mean Squared Error Loss)3. 均方误差损失导数(Mean Squared Error Loss Derivative)4. 平均平方误差 (MSE) …...

gentoo安装Xfce桌面

一、安装Xfce 1.选择一个配置文件 具体步骤可参见笔者的另一篇博客https://blog.csdn.net/my1114/article/details/143919066,配置文件选择24. 2.安装Xfce (1)root #emerge --ask xfce-base/xfce4-meta 第一次启动登录后时可能还需starx来启动X11 (2)安装slim&#…...

阿尔茨海默症数据集,使用yolo,voc,coco格式对2013张原始图片进行标注,可识别轻微,中等和正常的症状

阿尔茨海默症数据集,使用yolo,voc,coco格式对2013张原始图片进行标注,可识别轻微,中等,严重和正常的症状 数据集分割 训练组100% 2013图片 有效集% 0图片 测试集&#xf…...

【物联网技术与应用】实验4:继电器实验

实验4 继电器实验 【实验介绍】 继电器是一种用于响应施加的输入信号而在两个或多个点或设备之间提供连接的设备。换句话说,继电器提供了控制器和设备之间的隔离,因为设备可以在AC和DC上工作。但是,他们从微控制器接收信号,因此…...

lvs介绍与应用

LVS介绍 LVS(Linux Virtual Server)是一种基于Linux操作系统的虚拟服务器技术,主要用于实现负载均衡和高可用性。它通过将客户端请求分发到多台后端服务器上,从而提高整体服务的处理能力和可靠性。lvs是基于集群的方式实现 集群…...

Group FLUX - User Usage Survey Report

文章目录 User Feedback Summary: Software Advantages and FeaturesUser Feedback Issues and Suggested Improvements1. Security Concerns:Improvement Measures: 2. System Performance and Loading Speed:Improvement Measures: 3. Data Display Issues:Improvement Measu…...

XXE靶机攻略

XXE-Lab靶场 1.随便输入账号密码 2.使用bp抓包 3.插入xxl代码,得到结果 xxe靶机 1.安装好靶机,然后输入arp-scan -l,查找ip 2.输入ip 3.使用御剑扫描子域名 4.输入子域名 5.输入账号密码抓包 6.插入xml代码 7.使用工具解码 8.解码完毕放入文…...

第78期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区,集成了生成预训练Transformer(GPT)、人工智能生成内容(AIGC)以及大语言模型(LLM)等安全领域应用的知识。在这里,您可以找…...

电容Q值、损耗角、应用

电容发热的主要原因:纹波电压 当电容两端施加纹波电压时,电容承受的是变化的电压,由于电容内部存在寄生电阻(ESR)和寄生电感(ESL).因此电容会有能量损耗,从而产生热量,这…...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计:let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性,这种设计体现了语言的核心哲学。以下是深度解析: 1.1 设计理念剖析 安全优先原则:默认不可变强制开发者明确声明意图 let x 5; …...

IGP(Interior Gateway Protocol,内部网关协议)

IGP(Interior Gateway Protocol,内部网关协议) 是一种用于在一个自治系统(AS)内部传递路由信息的路由协议,主要用于在一个组织或机构的内部网络中决定数据包的最佳路径。与用于自治系统之间通信的 EGP&…...

拉力测试cuda pytorch 把 4070显卡拉满

import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包

文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容

目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...

站群服务器的应用场景都有哪些?

站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...

逻辑回归暴力训练预测金融欺诈

简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)

题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...

【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案

目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...