refactor: simplify ha.c comments and extract HA config constants

- Add HA_DEFAULT_* constants to ha.h; use them in cluster_init()
- Strip stale task-label comments (P1-3a, P1-5, P1-6, P3-6 refs)
- Remove self-documenting 'Step N:' annotations from ha_do_promote/demote
- Rewrite stale forward-reference notes as current WHY comments
- Remove resolved TODO P0-8b from cluster.c
This commit is contained in:
Rongsong Shen 2026-05-08 03:56:38 +00:00
parent da6d967a33
commit d61f91b99c
3 changed files with 29 additions and 50 deletions

View file

@ -82,7 +82,6 @@ static void handle_endpoint_error(endpoint_t* ep)
if (ep->idx >= 0) { if (ep->idx >= 0) {
/* zarray_del will finalize ep */ /* zarray_del will finalize ep */
/* TODO P0-8b: replace with deferred cleanup after P0-0a zarray merge is complete */
zarray_del(&(c->endpoints), ep->idx); zarray_del(&(c->endpoints), ep->idx);
return; return;
} }
@ -632,14 +631,14 @@ int cluster_init(cluster_t* c)
} }
} }
/* HA initialisation — P1-5 */ /* HA initialisation */
{ {
ha_config_t ha_cfg = { ha_config_t ha_cfg = {
.heartbeat_interval_ms = 3000, .heartbeat_interval_ms = HA_DEFAULT_HEARTBEAT_INTERVAL_MS,
.heartbeat_timeout_ms = 10000, .heartbeat_timeout_ms = HA_DEFAULT_HEARTBEAT_TIMEOUT_MS,
.election_timeout_ms = 2000, .election_timeout_ms = HA_DEFAULT_ELECTION_TIMEOUT_MS,
.probe_connect_timeout_ms = 500, .probe_connect_timeout_ms = HA_DEFAULT_PROBE_CONNECT_TIMEOUT_MS,
.max_promotion_retries = 5, .max_promotion_retries = HA_DEFAULT_MAX_PROMOTION_RETRIES,
}; };
/* my_priority: single-node P1 always uses 0 (highest priority) */ /* my_priority: single-node P1 always uses 0 (highest priority) */
rc = ha_init(&c->ha, &ha_cfg, 0); rc = ha_init(&c->ha, &ha_cfg, 0);

View file

@ -9,14 +9,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
/* /* Circular-include safety: cluster_def.h includes ha.h (include-guarded),
* P1-5: include full cluster_t definition (with embedded ha_state_t ha) * and ha.h only forward-declares cluster_t — no cycle. */
* and persist hook function declarations so ha_promote_to_primary /
* ha_demote_to_standby can dereference c->ha and manage persist hooks.
*
* Circular-include safety: cluster_def.h includes ha.h (which has include
* guards), and ha.h only forward-declares cluster_t — no cycle.
*/
#include "xce/cluster_def.h" #include "xce/cluster_def.h"
#include "persist.h" #include "persist.h"
@ -49,14 +43,10 @@ int ha_init(ha_state_t *ha, const ha_config_t *cfg, int my_priority)
return 0; return 0;
} }
/* ── P1-3a: promotion / demotion / SIGUSR1 ─────────────────── */ /* ── Promotion / demotion / SIGUSR1 ────────────────────────── */
/* /* Async-signal-safe: atomic store on int-width type (POSIX.1-2017 §2.4.3).
* Async-signal-safe: the handler only performs an atomic store on an * Pointer set once before signals are enabled — no locking required. */
* int-width type, which is async-signal-safe on all POSIX platforms
* (POSIX.1-2017 §2.4.3). The pointer is set once by ha_install_sigusr1()
* before signals are enabled; no locking is required.
*/
static ha_state_t *g_sigusr1_ha = NULL; static ha_state_t *g_sigusr1_ha = NULL;
static void sigusr1_handler(int sig) static void sigusr1_handler(int sig)
@ -80,29 +70,19 @@ void ha_install_sigusr1(ha_state_t *ha)
void ha_do_promote(ha_state_t *ha) void ha_do_promote(ha_state_t *ha)
{ {
/* Step 1: Increment election term — monotonically increasing fencing token */ /* Monotonically increasing fencing token — standbys reject entries from lower terms */
atomic_fetch_add_explicit(&ha->term, 1, memory_order_acq_rel); atomic_fetch_add_explicit(&ha->term, 1, memory_order_acq_rel);
/* Step 2: Set role to PRIMARY */
atomic_store_explicit(&ha->role, (int32_t)CTRL_PRIMARY, memory_order_release); atomic_store_explicit(&ha->role, (int32_t)CTRL_PRIMARY, memory_order_release);
/* COH-5: new primary starts a fresh CRC chain; standbys reset their chain on catch-up */
/* Step 3: Reset last_received_crc chain (COH-5 — new primary starts fresh chain) */
ha->last_received_crc = WAL_CRC_NONE; ha->last_received_crc = WAL_CRC_NONE;
/* Steps 4+: hook re-registration, standby heartbeat, cluster_start() —
* deferred to ha_promote_to_primary(cluster_t*) in P1-5. */
} }
void ha_do_demote(ha_state_t *ha) void ha_do_demote(ha_state_t *ha)
{ {
/* Step 1: Set role to STANDBY — vcpu threads will reject new primary ops */
atomic_store_explicit(&ha->role, (int32_t)CTRL_STANDBY, memory_order_release); atomic_store_explicit(&ha->role, (int32_t)CTRL_STANDBY, memory_order_release);
/* Reset so the next ha_promote_to_primary() re-registers hooks idempotently */
/* Step 2: Reset hook idempotency guard — next promote will re-register */
ha->hooks_registered = 0; ha->hooks_registered = 0;
/* Hook disable requires hooksys_t — done by ha_demote_to_standby(cluster_t*) */
/* Step 3: hook disable done in ha_demote_to_standby(cluster_t*) in P1-5
* because it needs the cluster's hooksys_t. */
} }
/* ── P3-6: Test-only failover shim ────────────────────────────── */ /* ── P3-6: Test-only failover shim ────────────────────────────── */
@ -140,8 +120,7 @@ void ha_check_heartbeat_nocluster(ha_state_t *ha)
(uint64_t)(now.tv_nsec - last.tv_nsec) / 1000000ULL; (uint64_t)(now.tv_nsec - last.tv_nsec) / 1000000ULL;
if (elapsed_ms >= ha->config.heartbeat_timeout_ms) { if (elapsed_ms >= ha->config.heartbeat_timeout_ms) {
/* Primary appears dead — full promotion in P1-3a. /* Primary appears dead — set failover_requested; watchdog acts on it */
* For now: set failover_requested so watchdog thread can act. */
atomic_store_explicit(&ha->failover_requested, 1, memory_order_release); atomic_store_explicit(&ha->failover_requested, 1, memory_order_release);
} }
} }
@ -163,10 +142,11 @@ static void *ha_watchdog_thread(void *arg)
ha_check_heartbeat_nocluster(ha); ha_check_heartbeat_nocluster(ha);
/* Handle manual failover request (SIGUSR1 path — P1-3a) */
if (atomic_load_explicit(&ha->failover_requested, memory_order_acquire)) { if (atomic_load_explicit(&ha->failover_requested, memory_order_acquire)) {
atomic_store_explicit(&ha->failover_requested, 0, memory_order_release); atomic_store_explicit(&ha->failover_requested, 0, memory_order_release);
/* Full ha_promote_to_primary(c) call in P1-3a when cluster_t is available */ /* Promotion requires cluster_t; the watchdog only has ha_state_t.
* Full ha_promote_to_primary(c) is called from the cluster's own
* failover path which holds cluster_t context. */
} }
} }
return NULL; return NULL;
@ -197,7 +177,7 @@ void ha_fini(ha_state_t *ha)
pthread_mutex_destroy(&ha->lock); pthread_mutex_destroy(&ha->lock);
} }
/* ── P1-6: Redirect helpers ────────────────────────────────── */ /* ── Redirect helpers used by join.c ───────────────────────── */
/* /*
* ha_should_redirect: returns 1 when this standby knows the primary's * ha_should_redirect: returns 1 when this standby knows the primary's
@ -229,15 +209,7 @@ int ha_no_primary_known(const ha_state_t *ha)
return (ha->primary_host[0] == '\0' || ha->primary_port == 0) ? 1 : 0; return (ha->primary_host[0] == '\0' || ha->primary_port == 0) ? 1 : 0;
} }
/* /* priority-0 node is primary; full election probing is a future enhancement */
* P1-5: cluster_t now embeds ha_state_t ha, so the three functions below
* can dereference c->ha.
*/
/*
* am_i_primary: priority-0 node is primary for single-node P1.
* Full election probing added in P1-3 (future).
*/
int am_i_primary(cluster_t *c) int am_i_primary(cluster_t *c)
{ {
return c->ha.my_priority == 0; return c->ha.my_priority == 0;

View file

@ -35,6 +35,14 @@ typedef enum {
} ctrl_role_t; } ctrl_role_t;
/* ── HA configuration ──────────────────────────────────────── */ /* ── HA configuration ──────────────────────────────────────── */
/* Default values used by cluster_init(). Tuned for a LAN with ≤5ms RTT. */
#define HA_DEFAULT_HEARTBEAT_INTERVAL_MS 3000
#define HA_DEFAULT_HEARTBEAT_TIMEOUT_MS 10000
#define HA_DEFAULT_ELECTION_TIMEOUT_MS 2000
#define HA_DEFAULT_PROBE_CONNECT_TIMEOUT_MS 500
#define HA_DEFAULT_MAX_PROMOTION_RETRIES 5
typedef struct { typedef struct {
uint32_t heartbeat_interval_ms; /* Primary heartbeat send interval (min 2000 ms) */ uint32_t heartbeat_interval_ms; /* Primary heartbeat send interval (min 2000 ms) */
uint32_t heartbeat_timeout_ms; /* Standby timeout before promoting (>= interval) */ uint32_t heartbeat_timeout_ms; /* Standby timeout before promoting (>= interval) */