feat(ha-single-leader-role): legacy election path symmetry — direct CTRL_PRIMARY via shared sequence (task 3.1)
This commit is contained in:
parent
c089fb69f3
commit
b7b951b9e7
4 changed files with 167 additions and 46 deletions
|
|
@ -2346,16 +2346,21 @@ apply_role:
|
|||
ha->phase2_done = 1;
|
||||
}
|
||||
|
||||
/* Enter COMMITTING: block job traffic until majority ack (Req 4.1, 8.1) */
|
||||
atomic_store_explicit(&ha->role, (int32_t)CTRL_PRIMARY_COMMITTING,
|
||||
/* ha-single-leader-role task 3.1 (Req 1.1, 1.5): enter CTRL_PRIMARY
|
||||
* DIRECTLY — symmetric with raft_cb_become_leader's rewrite. There
|
||||
* is no transitional COMMITTING state and no committing-timeout
|
||||
* watchdog; new-leader safety comes from the own-term WAL_NOOP +
|
||||
* writable_lsn gate armed below (ha_arm_own_term_gate), not from a
|
||||
* fourth role value. The legacy XCE_TESTING election path OWNS its
|
||||
* term (no raft library in test mode); it historically did NOT
|
||||
* increment the term in this branch, so we preserve that — no
|
||||
* ha_do_promote, no new term store (research.md §4 finding 2). */
|
||||
atomic_store_explicit(&ha->role, (int32_t)CTRL_PRIMARY,
|
||||
memory_order_release);
|
||||
INFO("HA FSM: → CTRL_PRIMARY_COMMITTING (term=%" PRIu64
|
||||
INFO("HA FSM: → CTRL_PRIMARY (term=%" PRIu64
|
||||
", first_boot=%d)", atomic_load_explicit(&ha->term, memory_order_acquire),
|
||||
is_first_boot);
|
||||
|
||||
/* Reset ack counter for this committing round (Req 5.2) */
|
||||
atomic_store(&ha->repl_ack_count, 0);
|
||||
|
||||
/* Push config to standbys with lower config_tag (Req 7.1) */
|
||||
#ifdef XCE_TESTING
|
||||
if (ha_push_config_hook != NULL)
|
||||
|
|
@ -2374,30 +2379,25 @@ apply_role:
|
|||
ha_send_ctrlhello_to_all_standbys(c);
|
||||
#endif
|
||||
|
||||
/* Arm committing timeout watchdog (degraded-mode fallback, Req 8.4) */
|
||||
/* ha-single-leader-role task 3.1: route promotion side effects
|
||||
* through the SAME shared sequence raft_cb_become_leader runs so the
|
||||
* test-driven (legacy) and raft-driven promotion paths cannot diverge
|
||||
* (design §Legacy Path Symmetry). Guarded on a real cluster_t — the
|
||||
* helpers dereference &c->hooksys / &c->persist / &c->commit, and the
|
||||
* unit-test evaluation path passes c == NULL. Identical role / hook /
|
||||
* heartbeat / no-watchdog / own-term-gate state results either road. */
|
||||
if (c) {
|
||||
/* Cancel any prior committing timeout */
|
||||
committing_timeout_ctx_t *prev = (committing_timeout_ctx_t *)
|
||||
atomic_exchange(&ha->committing_timeout_ctx, NULL);
|
||||
if (prev) {
|
||||
atomic_store(&prev->cancelled, 1);
|
||||
}
|
||||
committing_timeout_ctx_t *ct = calloc(1, sizeof(*ct));
|
||||
if (ct) {
|
||||
atomic_init(&ct->cancelled, 0);
|
||||
ct->ha = ha;
|
||||
ct->c = c;
|
||||
atomic_store(&ha->committing_timeout_ctx, ct);
|
||||
int rc = delay_task_ms(&c->delaymgr,
|
||||
(int)ha->config.committing_timeout_ms,
|
||||
1, committing_timeout_fn, ct);
|
||||
if (rc < 0) {
|
||||
WARN("ha_elect_evaluate_and_signal: delay_task_ms "
|
||||
"for committing timeout failed: %d", rc);
|
||||
atomic_store(&ha->committing_timeout_ctx, NULL);
|
||||
free(ct);
|
||||
}
|
||||
}
|
||||
/* Register the persistence hooks BEFORE the own-term no-op append,
|
||||
* so the persistence seam is live before any racing client write.
|
||||
* Idempotent via the hooks_registered guard. */
|
||||
ha_register_persist_hooks(c);
|
||||
/* Periodic heartbeat to standbys (idempotency guard prevents
|
||||
* double-arming if already started). */
|
||||
ha_start_primary_heartbeat(c);
|
||||
/* Own-term WAL_NOOP + writable_lsn gate (Req 1.4, 2.1, 2.2) —
|
||||
* non-blocking; append failure degrades safe (gate unset,
|
||||
* promotion still completes). */
|
||||
ha_arm_own_term_gate(c);
|
||||
}
|
||||
} else {
|
||||
/* STANDBY result */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue