Table of Contents

版本号协调状态机使用指南(EpochProtectedVersionScheme)

给谁看:需要"整体过渡到新版本"的组件作者(index 扩容、checkpoint 分阶段切换)。 回答什么:EPVS 解决什么问题、读者怎么写、版本怎么推进、自定义多步状态机怎么用。 前置:epoch 基础设施 LightEpochlocking-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 之外(读者线程可顺手接力推进,机器不依赖外部驱动也能走完),绝不嵌套 bumpLightEpoch 嵌套守卫禁止 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