Table of Contents

Structures 导览——6 子族速查 + KV 组合

给谁看:用结构层组合存储模型的人(KV / WAL / 队列 / 时序形态的构建者)。 本篇定位:导览页——6 子族速查 + KV 组合范式 + 陷阱清单。每种结构的详细文档(Settings 全参数 / API 详表 / 自定义注入工厂 / 持久化机制 / 恢复协议 / 反模式 / 指路)已拆为独立文档,下表"详细文档"列。

机制细节(帧格式 / 水位全表 / 协议内部状态机)从源码与设计稿查阅;meta 统一协议见 meta.md;性能数字见 perf/structures-perf-baseline.md


0. 6 子族速查(详细文档一览)

子族 详细文档 主类型 是什么 何时用
Ring ring.md BlittableRing<TKey> 追加式 KV 环:页池 + 单调逻辑地址 + RCU 原地更新 + 环形驱逐 主真相源——KV 数据本体;高并发写/读
Log log.md EntryLog / DeltaLog WAL 页帧流:组提交 + 恢复水位 纯顺序日志;checkpoint delta(DeltaLog 形态)
Index 探测族 index.md HashIndex<TKey> 条目=地址+tag,不物化 key,判等经 KeyResolver 回读 点查为主、内存最省(实测 161 ns)
Index 比较族 index.md BTreeIndex<TKey> / SkipListIndex<TKey> 条目物化 (key, 地址),有序遍历/range scan/前缀批量删 需要排序/范围查询;SkipList 适合高写并发小记录(无分裂重排)
Metadata versioned-metadata.md VersionedMetadata 版本链追加式单值元数据,N=2 轮转回收 跨重启单值状态(水位/配置/锚点);meta 外部隔离传输
Mirror mirror.md WholeMirror / PagedMirror 字节镜像:完整状态基线的版本链形态 整体快照外存(流式)/ 分页增量镜像
Snapshot snapshot.md StreamSnapshot / IncrementalSnapshot 完整状态基线的纯流式形态(按字节截断)/ 段=帧的增量快照(段表 O(1) 恢复 + 阈值合并) 流式帧文件快照 / raft 日志压缩(TierWAL 内部)

主结构 2 类(Ring / Log);搭配件 4 类(Index 一族两实现 / Metadata / Mirror / Snapshot)—— 存在性=优化非正确性(搭配件经桥单向依赖、可摘;不配也安全,走全量重放 fail-safe)。


1. 快速上手:组合 KV(三步,可运行)

1.1 声明封闭形态([RingKey] 源生成器,一行)

开放泛型(BlittableRing<TKey>/HashIndex<TKey> 等)的构造是 protected internal——消费面只经 [RingKey] 生成的封闭薄类(编译期封闭 + CreateAsync 工厂)。内置 long 已声明(TC.Tier.Runtime 程序集),RingOfLong/HashOfLong/BTreeOfLong/SkipListOfLong 开箱即用;自定义 Key 在消费程序集 加一行:

[assembly: RingKey(typeof(OrderId))]   // 产出 RingOfOrderId / HashOfOrderId / ...

⚠️ Mirror 子族无工厂——直接 new WholeMirror(...) + Initialize + WaitForReady 三步。 详见 mirror.md §3。

1.2 装配与写读(真实签名)

using TC.Tier.Core.IO;
using TC.Tier.Runtime.Storage;
using TC.Tier.Runtime.Structures.Ring;
using TC.Tier.Runtime.Structures.ProbingIndex;
using TC.Tier.Contracts.Structures;

// ① 文件系统 + 配置(默认值即生产值;示例用小型页池便于观察)
using var fs = TierFs.New("memory:");
var ringSettings = new BlittableRingSettings(new StorageEngineOptions("kv-ring", 64L << 20))
{
    PageSize = 4096, MemorySize = 64 * 1024, MutableFraction = 0.5,
};
var hashSettings = new HashIndexSettings(new StorageEngineOptions("kv-hash", 64L << 20));

// ② 封闭类型 CreateAsync 一步就绪(= 构造 + Initialize + WaitForReadyAsync)
await using var ring  = await RingOfLong.CreateAsync(ringSettings, fs);        // 真相源:record 流
await using var index = await HashOfLong.CreateAsync(fs, hashSettings, ring);  // 派生数据:判等闭环必注入 ring

// ③ 写读编排(正序两步写 / 两段合口径读)
static LogicalAddress KvPut(RingOfLong ring, IIndex<long> index, long key, ReadOnlySpan<byte> value)
{
    var addr = ring.Write(key, value);        // ① 真相源先写,得地址
    index.Insert(key, addr, LogicalAddress.Empty);   // ② 索引后插(指向该地址)
    return addr;
}

static bool KvTryGet(RingOfLong ring, IIndex<long> index, long key, Span<byte> buf, out int len)
{
    len = 0;
    var addr = index.Find(key);               // ① 索引命中得地址
    if (addr == LogicalAddress.Empty) return false;
    len = ring.GetValue(addr, buf);           // ② 真相源按址取值
    return true;
}

终态读形态(批量最快)index.EnterScope() 一批一进出 + IndexScope.Find + Ring.GetValueSpan(零拷贝切片;Ring 读为内容自愈读——判据+magic/CRC 校验 内聚,调用方零保护零感知;溢出 record 回退 thread-static 拷贝;span 仅同步栈内合法)。 批口径实测反超 FASTER(perf 文档 §3)。

1.3 恢复(两段式协议,锚点 W)

① Ring.CreateAsync → 恢复水位;锚点 W = ring.ReadOpaqueMeta()
   (无锚点 / 损坏 / W 越过当前尾 → 回退 BeginAddress——宁可旧多重放)
② index 拉流重放:ScanAsync(W, TailAddress) 逐条 Insert 自建
   (Hash/SortedIndex 有主存储帧时优先载帧,见 index.md §6/§7)

锚点 W = 索引上次主存储 dump/重放完成的水位,经 Ring 的 opaque 随水位线原子落盘;每次 dump/重放后 ring.SetOpaqueMeta(W) 即可。恢复协议全文见 meta.md


2. 概念(术语在此定义)

  • 2 主结构 + 4 搭配件 = 产品发生器:Ring(数据真相源)/ Log(操作流)是主结构; 索引(一族两实现)/元数据/镜像/快照是搭配件(经桥单向依赖、可摘——存在性=优化非正确性)。
  • 真相源 vs 派生数据:Ring 是数据真相(record 流),索引是派生数据(可重建)。 写编排正序:先真相源写、再索引插;反向 = 索引指向不存在的数据。
  • 地址一等公民:16B LogicalAddress 是唯一的取值句柄——先经索引发现地址,之后永久直达取值 (跳过 hash);判等/哈希只比较地址本身。
  • 恢复统一模型:载基线(快照/镜像,到 W)+ 重放(W, 尾]。快照按字节截断(纯流式), 镜像按版本号截断(版本链 N=2/回跳/回退)——同族异坐标系。
  • 术语:WAL = 写前日志(Log 即 WAL);RCU = 读-拷贝-更新(Ring 原地更新语义); opaque = 外部记录随水位线原子落盘的扩展槽(meta.md §4);2PC 六件套 = Prepare/ConfirmCommitted/ OnCommitted/Abort 的事务参与协议(见各子族文档 §4 / §5);帧 = 持久化格式的三段式单元 (头先行校验/体/尾 CRC)。

3. 怎么选(七种结构速查,详细决策见各子族文档)

结构 是什么 何时用 注意
RingBlittableRing<TKey> 追加式 KV 环:页池 + 单调逻辑地址 + 原地更新 + 环形驱逐 主真相源——KV 数据本体;高并发写/读 默认内存上限 16GB(MemorySize 旋钮);TKey : unmanaged;8 水位详见 ring.md §4.3
HashIndex 探测族:条目=地址+tag,不物化 key,判等经 KeyResolver 回读 点查为主、内存最省(实测 161 ns) 构造必注入 KeyResolver(判等闭环);无有序遍历;自建主存储(PersistenceKind.Builtin
BTreeIndex / SkipListIndex 比较族:条目物化 (key, 地址),有序遍历/range scan/前缀批量删 需要排序/范围查询 内部操作闸读写全互斥(任意并发组合安全;游标=单步粒度);恢复重放需要 KeyResolver;自建主存储(PersistenceKind.Builtin
LogEntryLog/DeltaLog WAL 页帧流:组提交 + 恢复水位 纯顺序日志;checkpoint delta 单写者;超单页抛(entry 不跨页);DeltaLog = 嵌入式 meta + 临时文件
MetadataVersionedMetadata 版本链追加式单值元数据,N=2 轮转回收 跨重启单值状态(水位/配置/锚点);meta 外部隔离传输 PayloadSize 须 ≥ 托管块上界;Sync/Async 持久化策略
MirrorWholeMirror/PagedMirror 字节镜像:完整状态基线的版本链形态 整体快照外存(流式)/ 分页增量镜像 与 Snapshot 同族异坐标系(版本号 vs 字节截断);无 Create 工厂——new + Initialize + WaitForReady
SnapshotStreamSnapshot 完整状态基线的纯流式形态(按字节截断) 流式帧文件快照 无版本概念;与 Ring 自带区间快照无引用关系
增量快照IncrementalSnapshot 段 = 帧的增量快照:新段 append 不重写旧段 + 段表 O(1) 恢复 + 阈值合并 raft 日志压缩(镜像快照第三部件——TierWAL 内部快照) 段累积需合并(raft 只需最新快照);合并 = 低频全量重写

索引三选:点查 → Hash;有序遍历/range → BTree/SkipList;高写并发小记录 → SkipList(无分裂重排)。 性能对照见 perf/structures-perf-baseline.md §3。


4. 持久化机制(两族索引)

两族均用自建主存储PersistenceKind.Builtin,可关 None)——基类是机制容器: 后台 dump 编排 / 版本链 N 版轮替 / 帧走链恢复载入 / 策略触发;子类只实现格式布局 (几何 + 桶区/溢出池逐槽拷贝 + 物化——铁律 10,对齐 LogBase/RingBase/MirrorBase)。

  • HashIndex:链 + N 版轮替
  • SortedIndex:固定锚点覆写

⚠️ 历史上索引族曾用 ITransferPersistence 桥接注入(WholeMirrorPersistence 托管 WholeMirror); 镜像通道注入面已退役——见 ProbingIndexBase.cs 头注释。WholeMirrorPersistence 桥接器仍保留 在 Runtime/DataMirror/ 给其他需"借镜像存储能力"的组件消费。详见 index.md §6 与 mirror.md §3.2。


5. 反模式(组合层必守——详见各子族文档 §8)

  1. 写编排反序:先 index.Insertring.Write——索引指向不存在的数据。
  2. 零拷贝 span 跨 awaitGetValueSpan 返回值仅同步栈内合法——跨 await/跨线程消费必须走拷贝 API (TryGetValue/GetValue)。详见 ring.md §8。
  3. Log 并发 Append:单写者硬性要求(多生产者经队列汇聚)。详见 log.md §8。
  4. 绕过 [RingKey] 直接继承开放泛型——封闭薄类是唯一消费面(分析器诊断不满足 unmanaged 约束的声明)。
  5. 为索引手搭 checkpoint 引擎/存储——两族均走自建主存储(PersistenceKind.Builtin);详见 index.md §6。
  6. 给地址直达读加会话/索引——地址即句柄:GetValue(addr) 永久零税。
  7. 跨实例组合 DeleteOnClose=true——跨重启组合必须 DeleteOnClose=false(否则索引重建时真相源被清)。
  8. 增长后检查索引阈值——增长必须在插入之前检查(增长时刻表内条目必可经 KeyResolver 解析)。
  9. 混淆 Ring 区间快照与 StreamSnapshot——前者是 Ring 导出能力(OpenSnapshotReader/Writer), 后者是独立文件形态。详见 snapshot.md §1 / §8。
  10. 混淆 Mirror 与 Snapshot 截断坐标系——Mirror 按版本号截断(N=2 轮替);Snapshot 按字节截断 (纯流式)。详见 mirror.md §1 / snapshot.md §1。

6. 想深入?指路

想懂什么 去哪
Ring 详细(8 水位 / Codec / KeyResolver / 自愈读 / 锚点 W 协议) ring.md
Log 详细(EntryLog vs DeltaLog / 组提交策略 / 单写者 / Replay) log.md
Index 详细(三选一决策树 / KeyResolver 闭环 / PersistenceKind / RecoveryHints) index.md
VersionedMetadata 详细(版本链 N=2 / Sync/Async 持久化 / MetadataMetaTransport) versioned-metadata.md
Mirror 详细(WholeMirror 三拍 / PagedMirror 逐页 / 2PC Abort / 跨实例恢复) mirror.md
Snapshot 详细(StreamFrameWriter/Reader / 段表 O(1) 恢复 / 阈值合并 / raft 日志压缩) snapshot.md
meta 统一协议(opaque 搭车/块格式/自定义传输) meta.md
Session 协调协议(写/读/检查点三 op、悬挂裁决、故障模型) session.md
引擎使用(读写/水位/恢复/Compact) storage-engine.md
段表 / lease 协议 segment-table.md / lease-protocol.md
性能基线(点查/写/恢复/并发扩展) perf/structures-perf-baseline.md / perf/log-perf-baseline.md / perf/kv-composition.md
帧格式/主存储机制/恢复细节 源码注释(Structures/ 各 partial)与设计稿(docs/design/

机制级细节(8 水位全表、帧字节布局、dump 协议、2PC 内部状态机)按需从源码与设计稿查阅——使用面 不需要这些细节;能力全集以类型 XML 注释为准。