docs(memory): 改正 Start 里那笔 Add 的并发注释,并补 Enabled=false 回归测试

review r1(p2-1items)指出:`tidy_service.go` 新加的那段注释(以及 2ba0a40 的提交
信息)写着「计数在这把锁里加 …… `Stop` 也持这把锁,这样 Add 与 Stop 的 `wg.Wait`
不可能撞在一起」。**这句不成立**:`Stop` 在 `tidy_service.go:214` 就放锁,到 `:219`
(另一个 goroutine 里)才 `wg.Wait`。锁只串行化 `running` 翻转与两笔 Add,
**不覆盖 Wait**。reviewer 用交叉 Start/Stop 探针在 -race 下复现了
`panic: sync: WaitGroup is reused before previous Wait has returned`,并实测该 panic
在 M3 之前的基线(20051f0)上同样可复现 ⇒ 既有性质,本切片不改行为,只改说法:

- 照真实理由改写注释:锁内加是为了让 `Stop` 的 `running` 判定与这两笔 Add
  **原子化**(杜绝「Stop 已看到 running=false 早退」与「Wait 漏掉一笔尚未 Add 的
  goroutine」两个窗口);
- 明确写出这把锁**不**覆盖 `Stop` 的 `wg.Wait`,WaitGroup 的复用纪律靠
  「`Start`/`Stop` 在进程生命周期各只调一次」维持;
- 并写明那个交叉探针的**当前调用点不可达**(`Start` 只在 `cmd/cyrene/main.go:97`
  调、`Stop` 只在 `cmd/cyrene/wire_services.go:212` 调),免得后人看到「有窗口但
  不可达」以为是漏改。

同时补上 reviewer 点出的真实缺口:`Enabled=false ⇒ 清扫不跑` 此前只有注释、没有
已提交的回归测试。新增 TestTidyServiceStart_整理关掉时清扫不跑,真跑 Start 后断言
「没有删除发生 + 没有审计 + running 保持 false」三件一起(不是只断言 cfg.Enabled
字段那种假牙)。两条断言各有牙:把 Enabled 闸改成恒 false ⇒ 红在 running 那一条;
在 Enabled 早退分支里偷偷起一个清扫(running 仍为 false)⇒ 红在「到期行却被删了」。
This commit is contained in:
AskaEth committed 2026-10-13 21:46:24 +08:00
1 parent 44c25eb03b
commit 69210a8586
2 files changed
+75 -3

No files matched your search

+15 -3
View File
@@ -134,9 +134,21 @@ func (s *TidyService) Start(ctx context.Context) {
s.cancel = cancel
s.wg.Add(1)
// 到期清扫(design/23 §19 的第 ② / ③ 步)与心跳**同生共死**:同一个 cctx、
// 同一个 wg,因此 Stop 会一并取消并 join 它(§19.3-3 的「可停」)。计数在
// 这把锁里加(与上面那一笔同处)是刻意的:`Stop` 也持这把锁,这样 Add 与
// Stop 的 `wg.Wait` 不可能撞在一起。
// 同一个 wg,因此 Stop 会一并取消并 join 它(§19.3-3 的「可停」)。
//
// 🔴 为什么这笔 Add 也在锁内(与上面那一笔同处):让 `Stop` 的 `running` 判定
// 与这两笔 Add **原子化** —— 于是不可能出现「Stop 已看到 `running=false` 早退」
// 或「Wait 漏掉一笔尚未 Add 的 goroutine(那会当场泄漏一个清扫 goroutine)」
// 这两种窗口。
//
// ⚠️ 这把锁**不**覆盖 `Stop` 的 `wg.Wait`:`Stop` 在 `tidy_service.go:214`
// 就放锁,到 `:219`(另一个 goroutine 里)才 Wait。因此 WaitGroup 的复用纪律
// (「上一轮 Wait 返回前不得再 Add」)**不是**由这把锁给的,而是靠
// 「`Start` / `Stop` 在整个进程生命周期各只调用一次」维持:`Start` 只在
// `cmd/cyrene/main.go:97` 调、`Stop` 只在 `cmd/cyrene/wire_services.go:212` 调。
// 交叉调用(`Start` 与在飞的 `Stop` 并发)在 `-race` 下会 `panic: sync:
// WaitGroup is reused before previous Wait has returned` —— 实测该 panic 在
// M3 之前的基线上同样可复现(既有性质,非本切片引入),只是当前调用点**不可达**。
s.wg.Add(1)
s.mu.Unlock()