update WAL segment 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:
@@ -198,6 +198,8 @@ batch 所在 segment 已进入 durable-ready 状态
|
||||
|
||||
如果新 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 中间损坏。
|
||||
|
||||
MANIFEST 不在每次 WAL segment 轮转时更新。MANIFEST 表示 recovery 起点 / checkpoint 状态,只在 MemTable flush、SSTable 与 checkpoint 元数据都持久化后推进;旧 WAL segment 何时可删除由后续文件生命周期规则定义。
|
||||
|
||||
#### 设计决策
|
||||
@@ -309,6 +311,14 @@ Physical Record 的顺序由 WAL 文件的顺序追加和顺序扫描保证,
|
||||
- Physical Record 的 `length` 必须 `> 0`
|
||||
- 读取时,Block 尾部 padding 必须全为 0;如果 padding 区出现非 0 bytes,视为 WAL 损坏
|
||||
|
||||
##### Segment Rotation 约束
|
||||
|
||||
- WAL Batch 不得跨 segment 文件;每个 WAL Batch 的所有 Physical Record 必须位于同一个 WAL segment 内
|
||||
- Segment rotation 只在 WAL Batch 边界发生:当前 segment 写入完一个完整 WAL Batch 后,如果需要轮转,在下个 Batch 写入前切换到新 segment
|
||||
- 写入 WAL Batch 前,WAL writer 必须根据编码后的 Batch 大小计算 Physical Records 布局;如果当前 segment 剩余空间不足以容纳整个 Batch,必须先切换到新 segment,再写入该 Batch
|
||||
- 不允许先写入 Batch 的部分 fragment,再因 segment 空间不足切换 segment
|
||||
- Recovery 的 fragment 收集状态不跨 segment 携带;每个非最后恢复 segment 扫描结束时必须处于 `Idle`
|
||||
|
||||
##### WAL Batch
|
||||
|
||||
WAL Batch 是物理持久化单元,对应一次 group commit batch。恢复时必须拼出完整 WAL Batch 后才能重放,不能重放半个 batch。WAL Batch 不是事务边界;一个 WAL Batch 可以包含多个独立 autocommit 写入,后续也可以包含一个或多个事务提交记录。
|
||||
@@ -444,7 +454,11 @@ MANIFEST 是 recovery 起点和 checkpoint 状态的权威源,记录最老仍
|
||||
6. 在每个 Block 内按 Physical Record 顺序解析
|
||||
7. 将 Full 或 First/Middle/Last 拼成完整 WAL Batch
|
||||
8. 校验并重放 WAL Batch 中的 Entries
|
||||
9. 更新 expectedSequence,并继续扫描下一个 batch 或下一个 segment
|
||||
9. 更新 expectedSequence,并继续扫描下一个 batch
|
||||
10. 当前 segment 所有 Block 扫描完毕后,检查 fragment 状态:
|
||||
- Idle: 正常结束当前 segment,继续下一个 segment
|
||||
- CollectingFragments 且当前 segment 是最后一个需要恢复的 segment: 丢弃 incomplete batch,并截断到最后一个完整 WAL Batch 结束位置
|
||||
- CollectingFragments 且当前 segment 不是最后一个需要恢复的 segment: 视为 WAL 中间损坏,报错
|
||||
```
|
||||
|
||||
###### Segment 连续性校验
|
||||
@@ -522,8 +536,11 @@ CollectingFragments
|
||||
| CollectingFragments | Last | 追加 payload,拼出完整 WAL Batch,解析重放后回到 Idle |
|
||||
| CollectingFragments | Full | 非法 fragment 顺序 |
|
||||
| CollectingFragments | First | 非法 fragment 顺序 |
|
||||
| Idle | segment 结束 | 正常结束当前 segment |
|
||||
| CollectingFragments | segment 结束,且是最后恢复 segment | 丢弃 incomplete batch,并截断尾部 |
|
||||
| CollectingFragments | segment 结束,且不是最后恢复 segment | WAL 中间损坏,报错 |
|
||||
|
||||
如果扫描到 WAL 尾部时仍处于 `CollectingFragments` 状态,说明最后一个 WAL Batch 未写完整,丢弃该 incomplete batch,并截断到最后一个完整 WAL Batch 结束位置。
|
||||
Segment 边界不是合法的 fragment 边界。`First + Middle* + Last` 必须全部出现在同一个 segment 内。如果扫描到 WAL 尾部时仍处于 `CollectingFragments` 状态,说明最后一个 WAL Batch 未写完整,丢弃该 incomplete batch,并截断到最后一个完整 WAL Batch 结束位置。
|
||||
|
||||
###### WAL Batch 校验与重放
|
||||
|
||||
|
||||
Reference in New Issue
Block a user