From c02bbc57e3566ba840986784a8ebca4b6abcdf78 Mon Sep 17 00:00:00 2001 From: dailz Date: Thu, 11 Jun 2026 20:09:39 +0800 Subject: [PATCH] update WAL current authority design Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- docs/design.md | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/docs/design.md b/docs/design.md index e6e5d3c..413c935 100644 --- a/docs/design.md +++ b/docs/design.md @@ -198,13 +198,8 @@ WAL 写入路径的失败分类如下: 3. fsync segment-N.wal.tmp 4. rename segment-N.wal.tmp → segment-N.wal 5. fsync WAL directory -6. update CURRENT via temp + rename: - a. write CURRENT.tmp = segment-N.wal - b. fsync CURRENT.tmp - c. rename CURRENT.tmp → CURRENT - d. fsync metadata directory -7. segment-N enters durable-ready state -8. WAL writer may append batches whose recovery depends on segment-N +6. segment-N enters durable-ready state +7. WAL writer may append batches whose recovery depends on segment-N ``` `Always` 下,一个 WAL Batch 只有同时满足以下条件才能确认成功并发布 sequence: @@ -213,13 +208,15 @@ WAL 写入路径的失败分类如下: batch 所在 segment 已进入 durable-ready 状态 ∧ WAL bytes 已写到 batch end offset ∧ WAL 文件已 fsync 到 batch end offset -∧ 发现该 segment 所需的元数据已经 fsync +∧ 发现该 segment 所需的目录项已经 fsync ``` 如果新 segment 进入 durable-ready 之前任一步失败,该 segment 不得成为 active segment,也不得承载可确认写入。如果此时尚未分配 sequence,可以重试创建或切换到其他 segment;如果 sequence 已分配或已有 WAL Batch 依赖该 segment,则按 WAL write failure 处理,引擎进入 write-stopped 状态。 新 segment 的 durable-ready 协议只能在当前 active segment 已结束于完整 WAL Batch 边界后启动。实现不得预创建未来 segment,也不得让 `segment-N+1.wal` 在 `segment-N.wal` 仍可能存在未完成 Batch 尾部时对 recovery 可见。该约束保证:如果 recovery 看到后续 segment 存在,前一个 segment 必须已经 sealed 在完整 Batch 边界;否则前一个 segment 的尾部异常应被视为 WAL 中间损坏。 +CURRENT 更新不属于 durable-ready 协议,也不是 WAL Batch 确认成功的前提。写入侧可以在 segment 进入 durable-ready 后,通过 temp + rename 的方式 best-effort 更新 CURRENT,用于下次启动或运行期快速定位 active segment;CURRENT 更新失败不得影响已经通过目录 fsync 变为可发现的 segment,也不得让 recovery 改以 CURRENT 作为权威来源。 + MANIFEST 不在每次 WAL segment 轮转时更新。MANIFEST 表示 recovery 起点 / checkpoint 状态,只在 MemTable flush、SSTable 与 checkpoint 元数据都持久化后推进;旧 WAL segment 何时可删除由后续文件生命周期规则定义。 #### 设计决策 @@ -228,7 +225,7 @@ MANIFEST 不在每次 WAL segment 轮转时更新。MANIFEST 表示 recovery 起 | -------- | ---------------------------------- | --------------------------------------------------------------------------- | | 批量窗口 | 时间 + 大小双触发(500µs 或 32KB) | 高负载靠大小触发效率最大化,低负载靠时间触发不会卡住 | | 日志格式 | 固定 Block(32KB) | 恢复时按 block 读取校验,比逐条快;和 SSTable block 设计一致 | -| 文件管理 | 分段日志 | 精确删除已刷盘的旧 WAL 段;恢复可并行读多文件;CURRENT 文件指向当前活跃 WAL | +| 文件管理 | 分段日志 | 精确删除已刷盘的旧 WAL 段;恢复通过 MANIFEST + WAL 目录扫描发现 segment;CURRENT 仅作为 last-known active segment 的 best-effort hint | #### WAL Block 格式 @@ -449,7 +446,7 @@ Entry ###### CURRENT / MANIFEST 权威性 -MANIFEST 是 recovery 起点和 checkpoint 状态的权威源,记录最老仍需恢复的 `recoverySegmentID`。CURRENT 只表示当前活跃 WAL segment,是写入侧快速定位 active segment 的辅助文件,不作为 recovery 起点的权威来源。 +MANIFEST 是 recovery 起点和 checkpoint 状态的权威源,记录最老仍需恢复的 `recoverySegmentID`。CURRENT 只表示写入侧上次尝试记录的 active WAL segment hint,是写入侧快速定位 active segment 的辅助文件;它可能缺失、落后或与目录扫描结果不一致,不能作为 recovery 起点、终点或排除 segment 的依据。 恢复时: