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:
parent
da6d967a33
commit
d61f91b99c
3 changed files with 29 additions and 50 deletions
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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) */
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue