Core 故障注入面使用指南——IO 缝(FaultInjectingFileSystem)与时钟缝(FakeTimeProvider)
对应设计:
docs/design/fault-injection-surface-design.md(件一时钟缝 / 件三 IO 缝扩展)。 哲学锚:注入脸只建在真实失败边界上,且是常设面非测试代码泄漏(spec-12 §9.2 传输面先例)。
0. 快速开始(30 秒上手)
// IO 缝——错误/腐败/慢/挂/乱序六族规则,装饰任意 IFileSystem
using var fi = new FaultInjectingFileSystem(TierFs.New("memory:"));
fi.AddRule("*", "Write", IOError.DiskFull, failAtCallIndex: 1); // 第 1 次写 DiskFull
fi.AddCorruptRule("data", "Write", offset: 8, mask: new byte[] { 0xFF }); // 静默腐败
using var dev = new StorageEngineOptions("eng").Builder(fi).Start(); // 注入引擎根 fs
// 时钟缝——假钟快进驱动一切 provider 时间语义
var clock = new FakeTimeProvider();
var kv = await TierKvOfLongLong.CreateAsync(fs, TierKvOptions.Default.WithKvName("kv").WithClock(clock));
clock.Advance(TimeSpan.FromSeconds(61)); // TTL 过期判定即刻生效——零真实睡等
1. IO 缝:FaultInjectingFileSystem(TC.Tier.Core.IO.Testing,internal——测试经 IVT 可见)
装饰器形态:持有内层 IFileSystem,句柄包装为 FaultInjectingFileHandle。规则 = 「路径 × 操作 × 命中仲裁」三维:
路径/操作匹配是精确名或 "*";命中仲裁 = 概率(seeded Random——可复现)或第 N 次(failAtCallIndex,1 起,
两者都设时确定性优先)。每条规则暴露 MatchCount(命中记账,可观测)。
六族规则(可叠加,各管各的注入维度)
| 族 | API | 注入点 | 语义 |
|---|---|---|---|
| 错误(类型化) | AddRule(path, op, IOError, probability, failAtCallIndex, detail) |
前置 | 抛 FileIOException(语义码透传) |
| 错误(自定义异常) | AddExceptionRule(path, op, Func<Exception>, …) |
前置 | 非致命异常传播边界 |
| 延迟 | AddDelayRule(path, op, TimeSpan, …) |
前置 | 同步 Thread.Sleep / 异步 Task.Delay(ct 可取消)——watchdog/有界等待触发器 |
| 挂起 | AddHangRule(path, op, detail) |
前置 | 操作永不到达内层;异步路径 ct 取消即出(有界等待路径);ClearRules/Dispose 释放门仅供拆除 |
| 乱序 | AddReorderRule(path, op, TimeSpan holdDelay, …) |
前置(仅异步写族:WriteAsync/AppendAsync/WriteVectorAsync) | 命中操作延后 hold 再提交——与其后并发到达操作形成受控乱序;同步操作永不命中 |
| 腐败 | AddCorruptRule(path, op, long offset, ReadOnlyMemory<byte> mask, …) |
后置(写族转发成功后) | 对介质 [offset, offset+mask.Length) 现存字节按 mask[i % Length] 循环 XOR(读-XOR-写回,静默不抛)——读自愈/CRC 判废/MagicLocator 恢复扫描的对抗抓手 |
注入链与注入点全集
- 同步入口链:错误(抛)→ 延迟(睡)→ 挂起(阻塞)。fs 级操作(Open/Delete/CreateFile/Stat/Enumerate*/…)与 句柄同步数据面(Write/Read/Append/Flush/PunchHole/CopyRange/…)共用同链。
- 异步入口链:错误 → 延迟(异步等)→ 挂起(
WaitAsync(ct))→(写族)乱序裁决 → 转发 →(写族)腐败评估。 异步注入点:WriteAsync / ReadAsync / AppendAsync / WriteVectorAsync / ReadVectorAsync。 - 腐败后置评估点:Write / Append / WriteVector / CopyRange / CloneRange 及其异步版。
ClearRules():六族全清 + 释放挂起门;Dispose()同样先放行挂起线程再转发内层。
反模式(禁忌)
- 挂起规则不设拆除外置——挂点在故障语义下永不放行,测试必须以被测方超时/取消路径先行处置;
依赖
ClearRules/Dispose 放行当"正常路径"= 测试假绿。 - 乱序规则打同步操作——永不命中(乱序需要异步解耦);静默不命中是设计契约,不是缺陷。
- 腐败规则按"当前写负载"寻址——腐败以介质绝对偏移寻址,翻转的是落盘现存字节(可能来自更早的写)。
- 真实乱序/掉电时序拿 mem 卷当真——mem 卷保序前提下的受控乱序只服务恢复协议确定性测试; 真盘乱序归云上形态(二者互补,见 VALIDATIONS.md 各 V 项"本地注入形态/云上形态")。
2. 时钟缝:FakeTimeProvider(TC.Tier.Core.Testing,public——零外部依赖替身)
BCL TimeProvider 自建测试替身(不用 Microsoft.Extensions.TimeProvider.Testing)。双钟模型:
| 钟 | 读数 API | 注入 | 语义 |
|---|---|---|---|
| 单调钟 | GetTimestamp()(ms 域,TimestampFrequency=1000——与 Environment.TickCount64 同域) |
Advance(delta) 快进 |
停走/倒流免疫;墙钟跳变不污染 |
| 墙钟 | GetUtcNow() |
Advance(按走速)/ SetWallClock(跳变)/ SetDrift(rate)(走速) |
TTL/租约消费点;跳变建模 NTP 校时 |
Advance同步推进双钟并按到期序同步触发到期定时器(周期定时器在大跨度 Advance 内连发;回调异常原样 冒泡不吞);Advance(TimeSpan.Zero)= 冲刷已到期定时器;due ≤ 0 的定时器"创建即到期"(下次 Advance 触发)。CreateTimer返回完整ITimer(DueTime/Period 可读写、Change可重挂、Dispose 解除挂载)。- 缺省零变化:
TimeProvider.System下一切落点行为逐字节同现状;单调戳经TimeProviderExtensions.GetMsTimestamp()(System 快路径直读TickCount64),延迟经TimeProviderExtensions.Delay()(System 直通Task.Delay)。 - 消费侧统一供给源:组件 Options 以
TimeProvider Clock { get; init; } = TimeProvider.System;形态注入 (RaftOptions.WithClock / TierKvOptions.WithClock / TierQueueOptions.WithClock / DistributedLock 锁组状态机与客户端构造参 / DeadlineRegistry(clock:))。
反模式(禁忌)
- 假钟不配同钟节拍注册表——raft 侧注入假钟时不显式传 registry 即自动新建同钟注册表; 自行混搭(假钟 options + Shared 注册表)= deadline 判定错乱。
- 对墙钟消费点断言"倒流后复活"——TTL 观测点带单调水位守卫(
TierKv.NowUtcTicks),已判过期项不复活; 测试应断言不复活(§1.3 矩阵倒流行)。 - 等待循环用真实 Thread.Sleep 判定假钟推进——假钟语义下用
Advance驱动;raft 节拍线程为真实线程 (同钟注册表,100ms 封顶扫描粒度),快进后到 Role 收敛允许 ≤ 数百 ms 真实延迟。 TimeSpan.FromMilliseconds(-1)当负延迟用——它是Timeout.InfiniteTimeSpan哨兵(永不完成)。
3. 指路
- 引擎缝(
IStorageEngineFaultInjector):见src/TC.Tier.Runtime/docs/storage-engine.md§故障注入面。 - 本地注入形态 / 云上形态落账:
scripts/cloud/VALIDATIONS.md各 V 项。 - 设计定案:
docs/design/fault-injection-surface-design.md(内部)。