fix(controller): clamp committed_config_tag to own loaded config on promotion
bug-1462: raft_cb_become_leader baselined committed_config_tag to the majority-safe floor across voters, correct for WAL LSN safety but wrong for config tags — a leader's own actively-loaded config isn't speculative like an unacknowledged WAL entry. On a fresh deploy every peer reports tag=0 except the new primary, so the floor stuck at 0 forever and late-joining standbys never received a config push. ha_promotion_config_tag_floor() clamps to max(safe_tag, self_tag), mirroring bug-1060's WAL-truncation clamp pattern. Validated with 20-round sequential (63 jobs, zero loss) and 20-round chaotic overlapping-kill (zero committed divergence, zero committed job loss) HA failover soaks; unit suite 977/977 green.
This commit is contained in:
parent
ee8473bd99
commit
0649e17f62
3 changed files with 106 additions and 2 deletions
|
|
@ -817,6 +817,28 @@ void ha_compute_safe_committed_lsn(ha_elect_ctx_t *ctx,
|
|||
* producing divergent WALs and a permanent prevote deadlock. */
|
||||
uint64_t ha_promotion_truncate_floor(uint64_t safe_lsn, uint64_t durable_tip);
|
||||
|
||||
/* ── bug-1462: config_tag floor for post-election committed_config_tag ───────
|
||||
*
|
||||
* ha_promotion_config_tag_floor: clamp the post-election committed_config_tag
|
||||
* baseline so it never drops below the config the new leader already has
|
||||
* loaded.
|
||||
*
|
||||
* Returns max(safe_tag, self_tag). safe_tag is the majority-threshold config
|
||||
* tag from the vote replies (ha_compute_safe_committed_lsn); self_tag is the
|
||||
* candidate's own actively-loaded config tag at election time. Unlike WAL LSN
|
||||
* (where an unacknowledged entry is genuinely speculative), a node's own
|
||||
* loaded config is never speculative — so the majority floor, correct for
|
||||
* LSN, is wrong for config_tag.
|
||||
*
|
||||
* Root cause it fixes: on a cluster where no live admin config push had ever
|
||||
* happened, every peer voter reported config_tag=0 while the new leader's own
|
||||
* self_tag was a real, non-zero, loaded tag. The majority floor picked 0,
|
||||
* permanently stalling the heartbeat-driven HA_REPL_PUSH_CONFIG decision for
|
||||
* any standby not connected at the exact instant of promotion (a late
|
||||
* joiner) — WAL/job replication was unaffected since it correctly floors at
|
||||
* genuinely-speculative LSN 0. */
|
||||
uint64_t ha_promotion_config_tag_floor(uint64_t safe_tag, uint64_t self_tag);
|
||||
|
||||
/* ── raft-drive-async task 1.1: peer-scaled liveness reservation ─────────────
|
||||
*
|
||||
* drive_async_liveness_reserved: PURE derivation of VTASK_LIVENESS_RESERVED —
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue