[Critical] 恢复后未确认 Batch 可能变成已发布 #8

Closed
opened 2026-06-09 13:07:51 +08:00 by dailz · 0 comments
Owner

来源

Oracle 审核 docs/design.md Section 3.2 WAL

位置

Section 3.2 "恢复完成状态"(~line 575)与 "持久化策略"(~line 96)

问题描述

Recovery 重放所有 CRC 合法、sequence 连续的 WAL batch,并在恢复完成后将其全部标记为 published。但其中可能包含崩溃前从未 fsync 确认(调用方未收到成功)的 batch。

场景:

  1. WAL bytes 已通过 write() 写入 OS page cache
  2. 进程崩溃(非掉电),OS 将 page cache 刷盘
  3. 重启后 recovery 发现该 batch 完整、CRC 合法、sequence 连续
  4. 该 batch 被重放并标记为 published
  5. 但调用方从未收到成功确认

影响

Always 策略下,调用方收到的语义是 "Put 返回成功 = 已持久化"。但如果进程 crash(非掉电),未确认的写入可能变成已发布。这是一个 API 语义问题而非数据安全问题。

建议修复

在 Section 3.2 "持久化策略" 或 "恢复完成状态" 中显式声明:

进程崩溃(非掉电)后恢复时,OS page cache 中已写入但尚未 fsync 的完整 WAL Batch 可能被恢复并视为已发布。这不是数据丢失,而是数据可见性前移。
调用方必须理解:进程崩溃重启后,比掉电场景可能多恢复一些写入。

如果需要严格区分"调用方已确认"与"未确认但存在于 WAL",需要后续引入 durable commit marker 或 confirmed-sequence 元数据。

## 来源 Oracle 审核 `docs/design.md` Section 3.2 WAL ## 位置 Section 3.2 "恢复完成状态"(~line 575)与 "持久化策略"(~line 96) ## 问题描述 Recovery 重放所有 CRC 合法、sequence 连续的 WAL batch,并在恢复完成后将其全部标记为 `published`。但其中可能包含崩溃前从未 fsync 确认(调用方未收到成功)的 batch。 **场景:** 1. WAL bytes 已通过 `write()` 写入 OS page cache 2. 进程崩溃(非掉电),OS 将 page cache 刷盘 3. 重启后 recovery 发现该 batch 完整、CRC 合法、sequence 连续 4. 该 batch 被重放并标记为 published 5. 但调用方从未收到成功确认 ## 影响 `Always` 策略下,调用方收到的语义是 "Put 返回成功 = 已持久化"。但如果进程 crash(非掉电),未确认的写入可能变成已发布。这是一个 API 语义问题而非数据安全问题。 ## 建议修复 在 Section 3.2 "持久化策略" 或 "恢复完成状态" 中显式声明: > 进程崩溃(非掉电)后恢复时,OS page cache 中已写入但尚未 fsync 的完整 WAL Batch 可能被恢复并视为已发布。这不是数据丢失,而是数据可见性前移。 > 调用方必须理解:进程崩溃重启后,比掉电场景可能多恢复一些写入。 > > 如果需要严格区分"调用方已确认"与"未确认但存在于 WAL",需要后续引入 durable commit marker 或 confirmed-sequence 元数据。
dailz closed this issue 2026-06-11 18:15:21 +08:00
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dailz/go-kv#8