update WAL manifest repair boundary 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:
+11
-5
@@ -219,6 +219,8 @@ CURRENT 更新不属于 durable-ready 协议,也不是 WAL Batch 确认成功
|
|||||||
|
|
||||||
MANIFEST 不在每次 WAL segment 轮转时更新。MANIFEST 表示 recovery 起点 / checkpoint 状态,只在 MemTable flush、SSTable 与 checkpoint 元数据都持久化后推进;旧 WAL segment 何时可删除由后续文件生命周期规则定义。
|
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 权威性
|
###### 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
|
2. fsync 被截断的 segment
|
||||||
3. 删除 startSequence == expectedSequence 且不含任何 complete batch 的后续空 segment
|
3. 删除 startSequence == expectedSequence 且不含任何 complete batch 的后续空 segment
|
||||||
4. fsync WAL directory
|
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。
|
因为 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 损坏,而是未确认写入的可见性前移。
|
这里的 published 表示“恢复后对普通读可见”,不表示崩溃前调用方一定已经收到成功确认。进程崩溃但机器未掉电时,已经通过 `write()` 进入 OS page cache、但尚未完成 fsync 或尚未唤醒调用方的完整 WAL Batch,可能在进程退出后被内核刷盘。重启后如果 recovery 发现该 Batch CRC 合法、sequence 连续且完整,就会按正常 WAL 规则重放并标记为 published。这不是数据丢失或 WAL 损坏,而是未确认写入的可见性前移。
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user