diff --git a/docs/design.md b/docs/design.md index 48de4c3..8014fdb 100644 --- a/docs/design.md +++ b/docs/design.md @@ -219,6 +219,8 @@ CURRENT 更新不属于 durable-ready 协议,也不是 WAL Batch 确认成功 MANIFEST 不在每次 WAL segment 轮转时更新。MANIFEST 表示 recovery 起点 / checkpoint 状态,只在 MemTable flush、SSTable 与 checkpoint 元数据都持久化后推进;旧 WAL segment 何时可删除由后续文件生命周期规则定义。 +MANIFEST 只作为 checkpoint / recovery 起点元数据;recovery repair 不更新 MANIFEST,也不通过 MANIFEST 记录恢复终点。 + #### 设计决策 | 决策 | 选择 | 理由 | @@ -517,7 +519,10 @@ Entry ###### CURRENT / MANIFEST 权威性 -MANIFEST 是 recovery 起点和 checkpoint 状态的权威源,记录最老仍需恢复的 `recoverySegmentID`。CURRENT 只表示写入侧上次尝试记录的 active WAL segment hint,是写入侧快速定位 active segment 的辅助文件;它可能缺失、落后或与目录扫描结果不一致,不能作为 recovery 起点、终点或排除 segment 的依据。 +MANIFEST 是 recovery 起点和 checkpoint 状态的权威源,记录最老仍需恢复的 `recoverySegmentID`。 +MANIFEST 不记录 recovery repair 终点;尾部截断 repair 的持久化结果由 WAL 文件截断后的 EOF 隐式表达。 +CURRENT 只表示写入侧上次尝试记录的 active WAL segment hint,是写入侧快速定位 active segment 的辅助文件; +它可能缺失、落后或与目录扫描结果不一致,不能作为 recovery 起点、终点或排除 segment 的依据。 恢复时: @@ -698,13 +703,13 @@ lastCompleteBatchEnd = 当前 WAL offset 2. fsync 被截断的 segment 3. 删除 startSequence == expectedSequence 且不含任何 complete batch 的后续空 segment 4. fsync WAL directory -5. 更新 MANIFEST 或等价 recovery metadata,记录本次 recovery repair 后的恢复终点 -6. fsync metadata directory ``` -以上步骤全部成功后,recovery 才能进入恢复完成状态并允许 WAL writer 接受新写入。若任一步失败,recovery 必须报错,DB 不得进入可写状态;否则再次崩溃后可能重新暴露未持久化的截断尾部,导致重复 repair 或 recovery 边界不一致。 +以上步骤全部成功后,截断后的 WAL 文件状态本身就是 recovery repair 的持久化结果,recovery 才能进入恢复完成状态并允许 WAL writer 接受新写入。 +后续再次启动时,recovery 仍从 `MANIFEST.recoverySegmentID` 开始扫描 WAL,并自然在截断后的 EOF 停止;不需要额外记录 `recoveryEndSequence`。 -这里的 MANIFEST 更新只记录 recovery repair 后的安全边界,不等同于普通 checkpoint 推进,也不意味着旧 WAL segment 已经可以删除。旧 WAL 文件生命周期仍由 MemTable flush、SSTable 与 checkpoint 元数据持久化后的规则决定。 +若 ftruncate、segment fsync、空 segment 删除或 WAL directory fsync 任一步失败,recovery 必须报错,DB 不得进入可写状态; +否则再次崩溃后可能重新暴露未持久化的截断尾部,导致重复 repair 或 recovery 边界不一致。 ###### 恢复完成状态 @@ -717,6 +722,7 @@ publishedSequence = recoveredSequence ``` 因为 WAL 中恢复出来的数据都来自已经持久化的完整 batch,所以恢复后可以全部视为 published。 +`nextSequence` 与 `publishedSequence` 是本次 recovery 扫描结果导出的内存状态,不写入 MANIFEST;下一次启动会重新从 MANIFEST recovery 起点扫描 WAL 并重新计算。 这里的 published 表示“恢复后对普通读可见”,不表示崩溃前调用方一定已经收到成功确认。进程崩溃但机器未掉电时,已经通过 `write()` 进入 OS page cache、但尚未完成 fsync 或尚未唤醒调用方的完整 WAL Batch,可能在进程退出后被内核刷盘。重启后如果 recovery 发现该 Batch CRC 合法、sequence 连续且完整,就会按正常 WAL 规则重放并标记为 published。这不是数据丢失或 WAL 损坏,而是未确认写入的可见性前移。