feat: ha_do_promote/demote + SIGUSR1 atomic flag handler (P1-3a)
- ha_do_promote(): atomic_fetch_add term, set role=PRIMARY, reset last_received_crc to WAL_CRC_NONE (COH-5 chain restart on promotion) - ha_do_demote(): set role=STANDBY, reset hooks_registered idempotency guard - ha_install_sigusr1(): sigaction handler stores only atomic int — async-signal-safe per POSIX.1-2017 §2.4.3; global g_sigusr1_ha set once before signals are enabled - ha_promote_to_primary() / ha_demote_to_standby() remain (void)c stubs pending P1-5 cluster wiring Tests: 3 new cases in test_ha_role.c test_promote_increments_term: term > term_before, role == PRIMARY test_demote_sets_standby_role: role reverts to STANDBY after promote+demote test_sigusr1_sets_failover_requested: raise(SIGUSR1) sets atomic flag Result: 100 Tests 0 Failures 0 Ignored (controller suite)
This commit is contained in:
parent
2fae4c3df5
commit
652b015458
3 changed files with 165 additions and 0 deletions
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stdatomic.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -37,6 +38,62 @@ int ha_init(ha_state_t *ha, const ha_config_t *cfg, int my_priority)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* ── P1-3a: promotion / demotion / SIGUSR1 ─────────────────── */
|
||||
|
||||
/*
|
||||
* Async-signal-safe: the handler only performs an atomic store on an
|
||||
* 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 void sigusr1_handler(int sig)
|
||||
{
|
||||
(void)sig;
|
||||
if (g_sigusr1_ha)
|
||||
atomic_store_explicit(&g_sigusr1_ha->failover_requested, 1,
|
||||
memory_order_release);
|
||||
}
|
||||
|
||||
void ha_install_sigusr1(ha_state_t *ha)
|
||||
{
|
||||
g_sigusr1_ha = ha;
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = sigusr1_handler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sigaction(SIGUSR1, &sa, NULL);
|
||||
}
|
||||
|
||||
void ha_do_promote(ha_state_t *ha)
|
||||
{
|
||||
/* Step 1: Increment election term — monotonically increasing fencing token */
|
||||
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);
|
||||
|
||||
/* Step 3: Reset last_received_crc chain (COH-5 — new primary starts fresh chain) */
|
||||
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)
|
||||
{
|
||||
/* 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);
|
||||
|
||||
/* Step 2: Reset hook idempotency guard — next promote will re-register */
|
||||
ha->hooks_registered = 0;
|
||||
|
||||
/* Step 3: hook disable done in ha_demote_to_standby(cluster_t*) in P1-5
|
||||
* because it needs the cluster's hooksys_t. */
|
||||
}
|
||||
|
||||
/* ── Watchdog thread implementation ────────────────────────── */
|
||||
|
||||
void ha_check_heartbeat_nocluster(ha_state_t *ha)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue