版本号协调状态机使用指南(EpochProtectedVersionScheme)
给谁看:需要"整体过渡到新版本"的组件作者(index 扩容、checkpoint 分阶段切换)。 回答什么:EPVS 解决什么问题、读者怎么写、版本怎么推进、自定义多步状态机怎么用。 前置:epoch 基础设施
LightEpoch见locking-and-epoch.md(EPVS 是它之上的 版本协调层)。完整积木全景见../COORDINATION.md。
0. 它解决什么
经典两难:写过渡要"没人再用旧版本"才能动数据结构(否则读者看到半成品);但不能全局锁 (读吞吐全没了)。
EPVS 的做法:用 LightEpoch 做"版本保护" + 一个状态机驱动"从旧版本分步过渡到新版本"。
读者 Enter() 拿到一个保证不变的版本状态,保护期内该版本不会被改;写方跑状态机,每个中间态
等所有旧 epoch 读者退出后再推进(临界区互斥执行)。读者让出后,版本才真正前进。
当前 Core 已就绪、有测试;上层引擎尚未接入(checkpoint/index 扩容等过渡场景待接入)。
1. 读者协议(Enter / Leave / Refresh)
var epoch = new LightEpoch();
var epvs = new EpochProtectedVersionScheme(epoch);
// 进入保护——返回"截至进入时刻"的状态(保证在此保护期内不变,不会处于中间态)
VersionSchemeState state = epvs.Enter();
try
{
/* 按 state.Version 读数据结构——此期间版本不会前进 */
state = epvs.Refresh(); // 长临界区内刷新到当前版本(等价 Leave+Enter 但更快)
}
finally
{
epvs.Leave(); // 必须同一线程释放(thread-static epoch)
}
Enter返回的 state 在保护期内有效——EPVS 保证你不会观察到中间态(IsIntermediate()必为 false,会自旋等过渡完成)。Leave必须同线程;Refresh用于长循环周期刷新(让版本能前进 + 重新拿当前 state)。
2. 版本推进(单步——最常见)
| API | 阻塞? | 用途 |
|---|---|---|
AdvanceVersionWithCriticalSection(criticalSection, targetVersion?, spin?) |
spin:true 阻塞到完成 / false 仅发起 |
期望"推进完成"的同步调用 |
TryAdvanceVersionWithCriticalSection(...) |
非阻塞,返回 OK/RETRY/FAIL |
并发发起、自行处理结果 |
bool ok = epvs.AdvanceVersionWithCriticalSection(
(fromVersion, toVersion) => // 临界区:互斥执行,旧版本所有读者已退出
{
/* 搬数据 / 切指针 */
},
spin: true); // 自旋等到过渡完成
// ok==true:成功(版本 +1);ok==false:目标版本已被超过(FAIL)
- 临界区参数
(fromVersion, toVersion) => ...——在互斥、旧读者已退出的条件下执行真正的数据搬迁。 targetVersion:默认-1= 推进到"当前+1";指定正数 = 推进到具体版本;目标 ≤ 当前返回FAIL(不会回退)。- 安全保护:在保护区内(
Enter后)调Advance→ 抛InvalidOperationException(不能在保护下 又驱动过渡)。
3. 自定义多步状态机(checkpoint 式)
多阶段过渡(如 Prepare → Commit → Rest):继承 VersionSchemeStateMachine,实现
GetNextStep/OnEnteringState/AfterEnteringState,用 ExecuteStateMachine/TryExecuteStateMachine
驱动。
每步过渡 = 「一次 drain + 一次临界区」:MakeTransition(旧态 → 中间态) 后,drain action 在旧 epoch
所有读者退出后执行 OnEnteringState(互斥)+ 推进到新态。多步机器靠步骤自动链接走完全程——
链接点刻意安排在 bump 之外(读者线程可顺手接力推进,机器不依赖外部驱动也能走完),绝不嵌套
bump(LightEpoch 嵌套守卫禁止 drain action 内二次 bump)。
4. API 速查
| 需求 | API |
|---|---|
| 进入版本保护 | var state = epvs.Enter();(返回非中间态 state) |
| 释放保护 | epvs.Leave();(同线程) |
| 长临界区刷新 | state = epvs.Refresh(); |
| 单步推进+临界区(阻塞) | epvs.AdvanceVersionWithCriticalSection((from,to)=>..., spin:true) |
| 单步推进+临界区(非阻塞) | epvs.TryAdvanceVersionWithCriticalSection(...) → OK/RETRY/FAIL |
| 查当前状态 | epvs.CurrentState() → VersionSchemeState{Phase, Version, IsIntermediate()} |
| 自定义多步(checkpoint 式) | 继承 VersionSchemeStateMachine + ExecuteStateMachine/TryExecuteStateMachine(§3) |
5. 想深入?指路
| 想懂什么 | 去哪 |
|---|---|
类型全貌(VersionSchemeState 位布局/StateMachineExecutionStatus) |
类型 XML 注释 |
| 步骤自动链接三情形(内联/推迟/无关 bump 内触发) | 源码注释(Epochs/EpochProtectedVersionScheme.cs) |
| 验证过的行为(单步/并发/自定义机器) | EpochProtectedVersionSchemeTests / ...CustomMachineTests |
| epoch 基础设施(Resume/Suspend/Bump/drain 契约) | locking-and-epoch.md §3 |