feat(ha-term-safety): out-of-band config bytes, hash-verify-before-activate, serve-fence (task 4.3)
Wires config_committed_marker to a production consumer (config_activate_committed): verifies pushed bytes' sha256 against the committed marker before activation, fences (loud, non-serving, stay-alive) on mismatch, and activates the latest committed marker on recovery. Enforced via ha_dispatch_gate + promotion gate. Fixes bug-981: a 2nd+ config upgrade could permanently fence a standby on a push-before-commit ordering. Adds an off-iomgr delaymgr retry scheduled from the commit-advance hook (atomic read + non-blocking enqueue only on the ACK thread) that re-activates and clears the stale fence once the new marker commits and bytes verify.
This commit is contained in:
parent
c3201a2b1e
commit
be4c1f0721
7 changed files with 1074 additions and 12 deletions
|
|
@ -25,6 +25,9 @@ int validate_startup_config(const char *config_path,
|
|||
|
||||
/* forward declaration — implemented in config_repl.c */
|
||||
int load_primary_config(cluster_t *c);
|
||||
/* ha-term-safety task 4.3: hash-verified recovery-activate from the latest
|
||||
* committed WAL_CONFIG_MARKER (-ENOENT falls back to load_primary_config). */
|
||||
int config_activate_committed(cluster_t *c);
|
||||
|
||||
time_t last_print_time = 0;
|
||||
unsigned long npkts = 0;
|
||||
|
|
@ -193,12 +196,30 @@ int myapp_run(myconf_t *myconf)
|
|||
* will receive the config via the primary's replication push post-election
|
||||
* (Req 7.3). */
|
||||
{
|
||||
int pre_rc = load_primary_config(&c);
|
||||
/* ha-term-safety task 4.3 (remediation r1, Finding B / R7.10): activate
|
||||
* the config referenced by the LATEST COMMITTED WAL_CONFIG_MARKER,
|
||||
* hash-VERIFIED against the locally-held bytes, instead of a blind
|
||||
* load_primary_config. persist recovery (step 6 above) has already
|
||||
* re-derived committed_lsn, so config_committed_marker reads the committed
|
||||
* prefix here. Semantics:
|
||||
* - committed marker present + bytes hash-match → activate (verified).
|
||||
* - committed marker present + bytes mismatch/absent → loud serve-fence,
|
||||
* member STAYS ALIVE and retries when correct bytes arrive
|
||||
* out-of-band post-election (NEVER self-terminates).
|
||||
* - NO committed marker (legacy / first boot) → -ENOENT falls back to
|
||||
* the existing load_primary_config blind-load (no false fence). */
|
||||
int pre_rc = config_activate_committed(&c);
|
||||
if (pre_rc == 0) {
|
||||
INFO("Pre-election config loaded: tag=%016llx",
|
||||
INFO("Pre-election config activated: tag=%016llx",
|
||||
(unsigned long long)c.myconf->config_version_tag);
|
||||
} else if (pre_rc == -EAGAIN) {
|
||||
ERROR("Pre-election config serve-FENCED: committed config marker "
|
||||
"references bytes not yet present/matching locally — member "
|
||||
"NON-SERVING under the new config, staying alive and awaiting "
|
||||
"out-of-band config-push (R7.9)");
|
||||
}
|
||||
/* Ignore errors — node may have no config yet (first boot or standby) */
|
||||
/* Ignore other errors — node may have no config yet (first boot/standby);
|
||||
* it fetches config via the primary's push post-election (Req 7.3). */
|
||||
}
|
||||
|
||||
/* ── Step 8: ha_start_election_async ─────────────────────────────────── */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue