# versionvector **Repository Path**: idcu-go/versionvector ## Basic Information - **Project Name**: versionvector - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-26 - **Last Updated**: 2026-08-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # gitee.com/idcu-go/versionvector > 当前版本:**v0.1.0** ## 1. 定位 + 当前版本 > 模块类型:**通用公共模块 · 原语 primitive**(跨节点版本向量合并 + LWW 冲突收敛,纯标准库)。 零依赖的版本向量原语:为「被动式跨公网低一致、多节点对同一条记录各自增写、恢复对账时需收敛成唯一赢家」 这类场景提供一组与节点无关、可复现的收敛规则。仅依赖标准库(`fmt` / `reflect` / `sort`), 无任何第三方依赖,可在任意 Go 项目中直接复用。 本包只做**合并与冲突裁决**,不感知任何业务字段;幂等去重与消息重放由上层负责。 ## 2. 安装 ```bash go get gitee.com/idcu-go/versionvector@v0.1.0 ``` **依赖**: - 内部(gitee.com/idcu-go/*):无 - 外部(第三方):无 - 用途:纯 stdlib 实现;仅需 `go 1.25` 与私有源 `GOPRIVATE="gitee.com/idcu-go/*"`。 --- ## 3. API 签名 包内导出符号共 6 个(1 个类型、1 个函数、4 个方法、1 个泛型函数参数相关类型): ```go package versionvector // import "gitee.com/idcu-go/versionvector" // Vector 是 node -> 已见最大版本号 的映射(每节点一个计数)。零值为可用的空向量。 type Vector map[string]uint64 // 新建一个空的、可直接赋值的向量。 func New() Vector // 逐节点取最大值,返回新的合并向量(不修改入参)。 func Merge(a, b Vector) Vector // 报告 v 是否不领先于 other(标准版本向量支配序,v ⊆ other 的因果前序判定)。 func (v Vector) Leq(other Vector) bool // 报告两向量是否逐节点相等。 func (v Vector) Equal(other Vector) bool // 深拷贝向量,避免与调用方共享底层 map。 func (v Vector) Clone() Vector // 待收敛的一条带版本向量与 LWW 时间戳的记录。 type Entry[T any] struct { Ops Vector // 产生本条记录时的版本向量(合并依据) Val T // 载荷(业务字段;本包不解析) Ts int64 // 逻辑时间戳(毫秒),LWW 主比较键 } // 对 local 与 remote 两条同主题记录做 LWW 收敛裁决。 // 返回确定的赢家;resolved=false 表示两条完全相同(重复投递,无需处理)。 func Resolve[T any](local, remote Entry[T]) (Entry[T], bool) ``` --- ## 4. 关键类型 / 语义 ### `Vector` 以节点名为键、以「该节点已见最大版本号」为值的稀疏映射。零值 `nil` 也是可用的空向量。 | 方法 | 语义 | 备注 | |---|---|---| | `Merge(a,b)` | 逐节点取版本最大值,返回新向量 | 不改入参,等价于版本向量的 join | | `Leq(other)` | `v` 每个已知节点版本都不超过 `other` 同名节点 | `v ⊆ other`,`v == other` 时亦为真 | | `Equal(other)` | 逐节点相等 | 长度不同直接为假 | | `Clone()` | 深拷贝 | 避免调用方共享底层 map | ### `Entry[T]` 与收敛规则(LWW) 两条同主题记录 `local`、`remote` 冲突时的裁决顺序: 1. **比 `Ts`(毫秒逻辑时间戳)**:较大者胜; 2. **`Ts` 相同 → 比向量身份串**:将 `Ops` 各节点 `node=version` 排序后拼接的字典序,较大者胜; 与节点观测顺序无关,保证跨节点收敛; 3. **向量也相同**:若载荷 `Val` 全等 → 判为**重复投递**(`resolved=false`,无需处理); 否则保守返回 `local` 并标记已裁决(步进到具体约束的收敛仍确定可复现)。 LWW 规则对齐架构 §4「(version, node_id 字典序)」。 --- ## 5. 最小用法示例 ```go package main import ( "fmt" "gitee.com/idcu-go/versionvector" ) func main() { // 两个节点各自对同一条记录增写后的版本向量与时间戳 local := versionvector.Entry[string]{ Ops: versionvector.Vector{"edge-1": 7, "edge-2": 3}, Val: "配置-A", Ts: 1700000001000, } remote := versionvector.Entry[string]{ Ops: versionvector.Vector{"edge-2": 5}, Val: "配置-B", Ts: 1700000001000, } winner, resolved := versionvector.Resolve(local, remote) switch { case !resolved: fmt.Println("两条完全相同,按重复投递忽略") case winner.Val == local.Val: fmt.Println("local 胜:", winner.Val) default: fmt.Println("remote 胜:", winner.Val) } // 合并两个节点自治域的版本 merged := versionvector.Merge(local.Ops, remote.Ops) fmt.Println("合并后版本向量:", len(merged), "个节点") } ``` --- ## 6. 测速 ```bash go test -race ./... # 单测 + 竞态 go test -bench=. -benchmem ./... # 基准(合并 / 收敛裁决 / 身份串) make ci # vet + lint + 覆盖率门禁(≥50%) ``` 实测基准(13th Gen Intel i5-13400,go 1.25,`-benchmem`): | Benchmark | 说明 | 结果 | |---|---|---| | `BenchmarkMerge` | 3~4 节点合并 | **155 ns/op,0 allocs/op** | | `BenchmarkMergeLarge` | 16 节点合并 | **834 ns/op,3 allocs/op** | | `BenchmarkResolve` | 一次冲突收敛裁决 | **641 ns/op,10 allocs/op** | | `BenchmarkVectorKey` | 决定性身份串生成 | **507 ns/op,9 allocs/op** | 收敛正确性由 `TestResolveDeterministic`(顺序无关 + 对称)与 `TestResolveTiebreaksByVector` 等用例保证。 --- ## 7. 版本 | 版本 | 摘要 | |---|---| | v0.1.0 | 首版:`Vector` / `Merge` / `Leq` / `Equal` / `Clone` / `Entry[T]` / `Resolve` |