chore(wolf): checkpoint buglog.json (1040 bugs)
This commit is contained in:
parent
54ea98fb35
commit
473fa8d8cd
1 changed files with 7 additions and 5 deletions
|
|
@ -19035,7 +19035,7 @@
|
|||
"error_message": "Chaotic HA soak (post-bug-1695-fix) reports committed_job_loss on every round; waldump on ctrl-1's live data dir shows the ENTIRE on-disk WAL truncated to a single NOOP entry (entries: 1 submits: 0) despite 21+ jobs previously verified committed; no snapshot exists; log shows ha_compute_safe_committed_lsn=0 immediately before raft_cb_become_leader promotes ctrl-1 to CTRL_PRIMARY at term=2 on its SECOND boot.",
|
||||
"file": "src/controller/ha.c",
|
||||
"root_cause": "raft_cb_become_leader() computes the promotion WAL-truncation floor (line ~1658-1662: trunc_floor = ha_promotion_truncate_floor(safe_lsn, persist_durable_floor(&c->persist)); persist_truncate_wal_above(&c->persist, trunc_floor)) and evaluates the whole promotion-eligibility gate (durable_floor/truncated/apply_verdict, ~line 1699-1823) BEFORE cluster_init_phase2() -- the ONLY call that invokes persist_recover() for this process's first-ever boot -- which does not run until is_first_boot handling at line ~1873-1899, further down in the SAME function. persist_durable_floor()/persist_recovery_truncated()/persist_apply_verdict() all read fields persist_recover() is responsible for populating from the real on-disk WAL; before that call, a freshly persist_init()'d struct reports durable_lsn=0 (bug-1445's comment at line 1901 already flagged this exact 'gate evaluated blind before recovery' hazard for ONE flag -- persist_apply_resource_fenced -- with a narrow re-check-after-phase2 patch, but the far more consequential durable_floor/truncation-floor computation was never covered by that fix). With durable_floor=0 (bogus, pre-recovery) and safe_lsn=0 (every voter, including self, ALSO advertised its LSN via persist_durable_floor() before its own recovery ran -- myapp.c:324-329, ha_candidate_advertise_lsn), ha_promotion_truncate_floor(0,0)=0 and persist_truncate_wal_above(p, 0) physically ftruncates/unlinks the real on-disk WAL segments down to LSN 0/1 -- destroying committed job data that persist_recover(), had it run FIRST, would have correctly reported as durable and protected via the bug-1060 floor guard. This scenario (a node RESTARTS with real durable data on disk, then immediately WINS its own promotion on that same boot, before its own recovery has run) was unreachable before bug-1695's fix -- previously a restarted node's stale-but-nonzero persisted term made it always skip its own election and defer to a peer, so it never hit is_first_boot-during-become_leader with real data at stake. bug-1695 correctly restored real re-election on restart and, in doing so, newly exposed this pre-existing boot-ordering flaw. A genuine Leader Completeness / bug-1060-guard-defeat, not a test-harness artifact: confirmed via direct waldump on-disk evidence plus source-level trace of the read-before-recover ordering.",
|
||||
"fix": "PENDING -- dispatching a dedicated fix: reorder raft_cb_become_leader() so cluster_init_phase2()/persist_recover() (is_first_boot path, currently ~line 1873-1899) runs BEFORE the safe_committed_lsn/promotion-truncation-floor computation and the promotion-eligibility gate (currently ~line 1637-1823), so persist_durable_floor()/persist_recovery_truncated()/persist_apply_verdict() always reflect this boot's REAL recovered WAL state before any truncation or eligibility decision reads them. Must NOT touch the separate become_follower cluster_init_phase2 call site (~line 2101-2135) or the bug-1445 apply_resource_fenced re-check (keep as a defense-in-depth no-op once reordered). Requires new RED regression test: a node with real durable committed WAL data, restarted, winning its own promotion on that same restart, must retain all committed data post-promotion (not truncate to an empty/near-empty floor). Prove with full controller unit suite + a live chaotic HA soak A/B (pre-fix reproduces committed_job_loss>0, post-fix committed_job_loss=0) before closing.",
|
||||
"fix": "FIXED. Reordered raft_cb_become_leader() (ha.c) so cluster_init_phase2()/persist_recover() (is_first_boot path) runs BEFORE the promotion-eligibility gate and the promotion-truncation-floor computation, so persist_durable_floor()/persist_recovery_truncated()/persist_apply_verdict() always reflect this boot's REAL recovered WAL state before any eligibility/truncation decision reads them. Split the pure vote-derived safe_committed_lsn computation (reads only ha->elect_ctx, safe pre-recovery) from the truncation-floor computation (needs post-recovery persist state) -- the former stays early, the latter moved to run after phase2. Original RED test hypothesis (physical WAL destruction via truncate) was disproven by source tracing (persist_truncate_wal_above's own no-op guard plus persist_init's current_lsn=1 reset make that specific mechanism impossible); the REAL, provable defect was the promotion-eligibility gate wrongly judging a genuinely corrupt/divergent node ELIGIBLE because it read persist_recovery_truncated()/persist_apply_verdict() before recovery ran. New regression test test_first_boot_promotion_refuses_when_own_first_recovery_finds_corruption (CRC-corrupts a real on-disk WAL entry, restarts, promotes) confirmed RED against unfixed code (wrongly became CTRL_PRIMARY despite RECOVER_TRUNCATED) and GREEN against the fix (correctly refused). Full controller unit suite: 1193 tests, 2 pre-existing bug-1561 failures only, 0 new. Live proof: full 10-round --chaotic soak under ASAN (build-asan-1696repro) PASSED (VERDICT mode=chaotic rounds=10 jobs=33 committed_divergence=0 committed_job_loss=0 result=PASS) and full 10-round --sequential soak PASSED (PASS: 10 rounds, 33 jobs submitted, zero job loss; all 3 nodes led (ctrl-1,ctrl-2,ctrl-3)) -- both legs of the audit skill's Step 4 mandate satisfied. Note: the fix's own verification agent died mid-A/B-soak leaving the fix orphaned in a git stash for a period before being discovered and restored; a subsequent independent full soak (this entry) is what actually closes it out.",
|
||||
"tags": [
|
||||
"controller",
|
||||
"ha",
|
||||
|
|
@ -19051,7 +19051,9 @@
|
|||
"found-via-soak",
|
||||
"critical",
|
||||
"bug-1695-adjacent",
|
||||
"unfixed"
|
||||
"fixed",
|
||||
"live-soak-verified",
|
||||
"asan-verified"
|
||||
],
|
||||
"related_bugs": [
|
||||
"bug-1695",
|
||||
|
|
@ -19060,8 +19062,8 @@
|
|||
"bug-828",
|
||||
"bug-1487"
|
||||
],
|
||||
"occurrences": 1,
|
||||
"last_seen": "2026-08-25T16:20:00Z"
|
||||
"occurrences": 2,
|
||||
"last_seen": "2026-08-26T07:50:00Z"
|
||||
},
|
||||
{
|
||||
"id": "bug-1697",
|
||||
|
|
@ -19155,4 +19157,4 @@
|
|||
"last_seen": "2026-08-26T07:35:00Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue