update WAL current authority design

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
dailz
2026-06-11 20:09:39 +08:00
co-authored by Sisyphus
parent 5e9836c931
commit c02bbc57e3
+7 -10
View File
@@ -198,13 +198,8 @@ WAL 写入路径的失败分类如下:
3. fsync segment-N.wal.tmp 3. fsync segment-N.wal.tmp
4. rename segment-N.wal.tmp → segment-N.wal 4. rename segment-N.wal.tmp → segment-N.wal
5. fsync WAL directory 5. fsync WAL directory
6. update CURRENT via temp + rename: 6. segment-N enters durable-ready state
a. write CURRENT.tmp = segment-N.wal 7. WAL writer may append batches whose recovery depends on segment-N
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
``` ```
`Always` 下,一个 WAL Batch 只有同时满足以下条件才能确认成功并发布 sequence: `Always` 下,一个 WAL Batch 只有同时满足以下条件才能确认成功并发布 sequence:
@@ -213,13 +208,15 @@ WAL 写入路径的失败分类如下:
batch 所在 segment 已进入 durable-ready 状态 batch 所在 segment 已进入 durable-ready 状态
∧ WAL bytes 已写到 batch end offset ∧ WAL bytes 已写到 batch end offset
∧ WAL 文件已 fsync 到 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 之前任一步失败,该 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 中间损坏。 新 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 segmentCURRENT 更新失败不得影响已经通过目录 fsync 变为可发现的 segment,也不得让 recovery 改以 CURRENT 作为权威来源。
MANIFEST 不在每次 WAL segment 轮转时更新。MANIFEST 表示 recovery 起点 / checkpoint 状态,只在 MemTable flush、SSTable 与 checkpoint 元数据都持久化后推进;旧 WAL segment 何时可删除由后续文件生命周期规则定义。 MANIFEST 不在每次 WAL segment 轮转时更新。MANIFEST 表示 recovery 起点 / checkpoint 状态,只在 MemTable flush、SSTable 与 checkpoint 元数据都持久化后推进;旧 WAL segment 何时可删除由后续文件生命周期规则定义。
#### 设计决策 #### 设计决策
@@ -228,7 +225,7 @@ MANIFEST 不在每次 WAL segment 轮转时更新。MANIFEST 表示 recovery 起
| -------- | ---------------------------------- | --------------------------------------------------------------------------- | | -------- | ---------------------------------- | --------------------------------------------------------------------------- |
| 批量窗口 | 时间 + 大小双触发(500µs 或 32KB) | 高负载靠大小触发效率最大化,低负载靠时间触发不会卡住 | | 批量窗口 | 时间 + 大小双触发(500µs 或 32KB) | 高负载靠大小触发效率最大化,低负载靠时间触发不会卡住 |
| 日志格式 | 固定 Block32KB | 恢复时按 block 读取校验,比逐条快;和 SSTable block 设计一致 | | 日志格式 | 固定 Block32KB | 恢复时按 block 读取校验,比逐条快;和 SSTable block 设计一致 |
| 文件管理 | 分段日志 | 精确删除已刷盘的旧 WAL 段;恢复可并行读多文件;CURRENT 文件指向当前活跃 WAL | | 文件管理 | 分段日志 | 精确删除已刷盘的旧 WAL 段;恢复通过 MANIFEST + WAL 目录扫描发现 segmentCURRENT 仅作为 last-known active segment 的 best-effort hint |
#### WAL Block 格式 #### WAL Block 格式
@@ -449,7 +446,7 @@ Entry
###### CURRENT / MANIFEST 权威性 ###### 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 的依据
恢复时: 恢复时: