Table of Contents

TierBlob 使用指南

TierBlob = SnapshotBase 的产品封面:无索引语义的 GB/TB 级大对象流式存取。对象句柄 = 起始 LogicalAddress(地址一等公民——写完即得、可持久化/传输、凭地址直达数据);流式会话边写边算 CRC64 不驻内存整块。设计全案见 docs/design/tierblob-spec.md(Tier 仓内部文档)。

与 TierKV 的分工(按访问模式,不按大小)

场景 用谁
要索引 / 点查 / 覆盖写 TierKV(溢出分离兜底)
整对象顺序写读 / 无索引 / 流式 TierBlob
随机 seek 覆写 都不——KV 覆盖写或 Delete+Put(新句柄)

快速开始

var fs = TierFs.New("local:///data/tc");            // 组合根文件系统
await using var blob = await new TierBlobBuilder(fs, new TierBlobOptions
{
    BlobName = "tc",                                 // 引擎空间:{name}.blob.data / {name}.blob.meta
    MaxBytes = 1L << 40,                             // 容量上限(null = 不限)
}).StartAsync();

// ── 整对象单发 ──
var put = await blob.PutAsync(data);                 // put.ObjectId = 句柄(持久化它即可)
var dst = new byte[put.Length];
await blob.GetAsync(put.ObjectId, dst);              // 凭地址直达,零元数据查询

// ── 流式写(GB/TB 不驻内存)──
await using (var session = blob.OpenWrite())         // expectedLength ≥ 0 = 定长契约
{
    await foreach (var chunk in ReadSourceChunkAsync())
        await session.WriteAsync(chunk);
    var result = await session.CompleteAsync();      // Dispose 未 Complete = Abort(尾截断回滚)
}

// ── 流式读(CRC64 逐帧校验)──
await using (var reader = blob.OpenRead(handle))
{
    int n;
    while ((n = await reader.ReadAsync(buf)) > 0) Consume(buf[..n]);
    // 读至对象末尾自动验帧;CRC64 不符抛 IOException
}

语义要点

  • 句柄 = 起始 LogicalAddress:同址即同对象(raft 形态下确定性 apply 全组同址——泛化复制继承)。 GetAsync/OpenRead 免元数据查询;GetInfoAsync/ListAsync 才查对象表。
  • Complete / Abort 显形BlobWriteSession Dispose 未 Complete = Abort(尾截断回滚),与 KV 会话 Dispose 收口惯例一致。定长会话(expectedLength ≥ 0)须恰好写满,不足/超过 Complete 拒绝并回滚。
  • 分配-持久分离:Complete 返回句柄 = 对象表登记已持久(表引擎 Prepare/Confirm 收口——崩溃窗口 句柄不丢);数据面 fsync 走显式 FlushAsync
  • 写入单通道:会话存活期独占写通道(结构层写尾单会话契约);不同对象并行写为 Runtime 迭代候选, 当前版本多生产者经产品写闸串行(读路径并发无锁)。
  • Delete = 墓碑 + 空间保留:List/Get 即刻不可见;物理回收走 ReclaimDeletedAsync 手动档 (引擎打洞 + 死亡前缀头截断)。后台自动 Compact = 候选项,不做。

恢复语义(崩溃对账)

启动时:对象表重放(meta O(1) 水位)→ 数据尾由表推导(登记帧几何权威)→ Active 对象逐个验帧:

  • 损坏帧 → 标墓碑TierBlobOptions.DeepVerifyOnRecovery 控制深度:默认帧尾级 O(1)/对象—— footer magic + TotalLength 对账;true = 整帧 CRC64 全量)。
  • 孤儿帧(Complete 后登记前崩溃)→ 不可见,区间被后续写入覆盖(at-least-once:崩溃 Put 由 调用方重试产生新对象)。

Session 2PC("业务写 + 对象登记"原子)

GetParticipant() 返回对象表参与者:Prepare 后的对象登记/删除延迟提交挂 undo 链——Confirm 统一 fsync + 提交水位;Abort = 表帧尾截断 + 内存镜像逆序回退(延迟删除回退 = 对象复活)。会话期间 PutAsync/DeleteAsync 自动挂入事务。

治理

机制 说明
TierBlobOptions.MaxBytes 超限 Put/OpenWrite fail-fast(不定长流在完成时点终判,超限回滚)
GetStatsAsync() ObjectCount / TombstoneCount / Bytes(物理折算)/ ReclaimableBytes
ReclaimDeletedAsync() 墓碑 extent 打洞 + 死亡前缀头截断;Active 区间零触碰
FlushAsync() 数据引擎 fsync 屏障