docs(buglog): bug-1913 and bug-1916 fixed; log bug-1915, bug-1917, bug-1918
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0fb2e14cc7
commit
acf78f9a94
6 changed files with 346 additions and 12 deletions
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
id: "bug-1913"
|
||||
status: "open"
|
||||
status: "fixed"
|
||||
status_updated: "2026-10-03"
|
||||
status_note: "newly logged"
|
||||
status_note: ""
|
||||
component: "controller"
|
||||
severity: "wrong-result"
|
||||
timestamp: "2026-10-03T14:18:58Z"
|
||||
|
|
@ -11,6 +11,7 @@ occurrences: 1
|
|||
files: ["src/controller/ha.c", "src/controller/repl.c", "src/controller/config_repl.c"]
|
||||
tags: ["ha", "raft", "replication", "latency"]
|
||||
related: ["bug-1485"]
|
||||
fix_commits: ["2aefa939"]
|
||||
---
|
||||
|
||||
# bug-1913: after a late-joiner election the primary cannot commit client writes for ~2 heartbeat cycles
|
||||
|
|
@ -45,15 +46,15 @@ In some elections the vote connections are not converted into standby channels (
|
|||
- Evidence: not kept (scratchpad loop logs from the bug-1485 investigation).
|
||||
|
||||
## Root cause
|
||||
TODO: required for fixed/partial
|
||||
Nothing asked a late-registered standby for its state, so its catch-up waited for the heartbeat clock. `ha_arm_own_term_gate` (ha.c ~5180) appends the own-term no-op while no standby is registered; `repl_broadcast` drops it (repl.c:306-311) and `repl_add_standby` never resends it. `on_standby_connected` (ha.c ~9511-9690) sends only a ctrlhello (no reply) and sets `last_push_time = now`. Catch-up is driven solely by a heartbeat reply's state report → `repl_ack_decode_and_dispatch` (peer-control vtask) → `ha_dispatch_repl_action_for_standby` (ha.c:4455), one action per report (config push if the tag is behind, else WAL stream). A standby rejoining with tag 0 therefore got the config push on the next 3 s tick and the WAL stream carrying the no-op on the tick after: ~6 s with committed_lsn below the no-op and every client write NACKed. The config-before-WAL order is a pacing rule of the ha-repl-hardening design ("no further decisions until the next state report confirms"), not a correctness requirement. Why the vote connections were not promoted in the first place is tracked separately (bug-1915).
|
||||
|
||||
## Fix
|
||||
TODO: required for fixed/partial
|
||||
Make the state report arrive sooner; the decision loop and its one-action-per-report pacing are unchanged. New `ha_send_catchup_probe()` (ha.c) sends the ordinary `xce_ha_heartbeat_req` (same fields, read the same way as `primary_heartbeat_fn`), only while `CTRL_PRIMARY`, encode + enqueue only (same non-blocking path as the ctrlhello and the delaymgr tick); a send failure is a WARN and the periodic tick stays the fallback. Triggers: (1) once at the end of `on_standby_connected` (iomgr connect callback, after `msg_handler` is set), which also arms `ha->catchup_kick_armed[peer]` (ha.h); (2) the accepted config-push-ACK branch of `repl_ack_decode_and_dispatch` (peer-control vtask) after a 1→0 CAS on the arm, so the WAL stream follows the config push at ~RTT while keeping config-before-WAL. The arm is cleared on the standby's disconnect (`standby_ep_err_handler_primary`) and on every `raft_cb_become_leader` / `raft_cb_become_follower`, so it never outlives its registration or leadership; at most two probes per connect. No new executor, opcode or protocol change; heartbeat interval unchanged; WAL streaming still runs only on the vtask.
|
||||
|
||||
## Verification
|
||||
- Test: TODO: name + file; RED before the fix, GREEN after
|
||||
- Suites: TODO: suite results and build profile
|
||||
- Live: TODO: soak/deploy run, or n/a and why
|
||||
- Test: `src/controller/testsuite/test_late_joiner_catchup_kick.c` — `test_late_joiner_registration_probes_standby_state`, `test_config_ack_after_registration_reprobes_once`, `test_rejected_config_ack_does_not_probe` RED before the fix (Expected 1 Was 0), GREEN after; `test_step_down_clears_catchup_arm` RED with the become_follower clear removed (Expected 0 Was 1); guards for no-registration and non-primary.
|
||||
- Suites: controller 5/5 meson suites, main 1285/0 (asan); `xce-build.sh all --incremental` green (C tests 127/0, scheduler 16/0, xceadmin 373), 2026-10-03.
|
||||
- Live: `/xce-test-ha` sequential 20 rounds PASS (63 jobs, zero loss, all 3 led, SIMVERIFY 21/0); chaotic 6 rounds PASS (zero committed divergence/loss); sequential 8 rounds under 40 busy loops PASS (with the bug-1916 fix; earlier loaded runs aborted on bug-1916). In those soaks catch-up started 0-6 ms after each late standby registration and a restarted standby was fully caught up 46 ms after registering (was up to ~6 s). Proxy (wiped standby) before/after: WAL stream at +5.8 s → +18-60 ms. Live HA push tests 6/6 under load; promoted-vote elections commit the no-op in median 6 ms (max 16 ms). Observation, not a regression: after catch-up the decision loop re-streams already-acked ranges on later stale state reports (harmless; standby discards duplicates).
|
||||
|
||||
## References
|
||||
- Related: none
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue