feat(config-upgrade-snapshot): add materialization-and-hash-verification activation fence
Adds a new, independent fence (ha_state_t.upgrade_materialization_fence) distinct from the existing config-byte serve-fence: that fence tracks whether the locally-held config bytes hash-match the committed marker; this one tracks whether THIS MEMBER'S OWN upgrade-snapshot materialization (task 5's marker-triggered checkpoint) has actually completed for the current committed marker, with the live on-disk config bytes still hash-verifying against it right now. upgrade_materialization_verify(c) mirrors config_activate_committed's shape: reads the current committed marker, checks whether persist.cfgref_present/cfgref_tag/cfgref_sha already reflect it (stamped by every checkpoint via scan_latest_committed_config_ref -- proof this member's own materialization ran for this exact marker), and separately re-reads the LIVE on-disk config bytes fresh on every call (never a cached/embedded copy) to hash-verify them too. Both must hold for the fence to clear. Logs loud only on the 0->1 transition, never exits/aborts, always fail-loud + fence + stay alive + retriable. upgrade_materialization_fenced(c) is the trivial atomic-read accessor. Not yet wired into the dispatch gate, promotion gate, or an automatic retry trigger -- that's task 6.2. Task 6.1 of 19. Requirements: 1.8, 3.2, 3.4
This commit is contained in:
parent
1da26b043e
commit
7b507156a0
4 changed files with 509 additions and 1 deletions
|
|
@ -320,6 +320,44 @@ typedef struct {
|
|||
* cleared and the config is activated.
|
||||
* NEVER self-terminates (loud non-serving
|
||||
* fence only). 0 at init (ha_init memset). */
|
||||
/* ── New field added by config-upgrade-snapshot spec (Task 6.1) ────── */
|
||||
_Atomic int upgrade_materialization_fence; /* Upgrade-snapshot
|
||||
* materialization-and-hash-verify
|
||||
* fence (Req 1.8, 3.2, 3.4) — a NEW,
|
||||
* INDEPENDENT fence, deliberately NOT
|
||||
* merged into config_serve_fence
|
||||
* above: that fence tracks whether the
|
||||
* out-of-band config-PUSH bytes match
|
||||
* the committed marker; THIS fence
|
||||
* tracks whether THIS MEMBER'S OWN
|
||||
* upgrade-snapshot materialization
|
||||
* (the marker-triggered checkpoint,
|
||||
* config-upgrade-snapshot task 5) has
|
||||
* actually completed for the CURRENT
|
||||
* committed marker, with the live
|
||||
* on-disk config bytes still
|
||||
* hash-verifying against it right
|
||||
* now. These are logically distinct
|
||||
* and can disagree in either
|
||||
* direction (e.g. bytes can already
|
||||
* hash-match — config_serve_fence
|
||||
* clear — while this member's own
|
||||
* checkpoint for that exact marker
|
||||
* has not run yet, immediately after
|
||||
* a marker commits but before its
|
||||
* forced checkpoint fires). Set by
|
||||
* upgrade_materialization_verify()
|
||||
* on materialization-incomplete or a
|
||||
* hash mismatch against a FRESH
|
||||
* re-read of the live config bytes
|
||||
* (never a cached/embedded copy);
|
||||
* cleared on success. While set, the
|
||||
* member MUST NOT serve under the new
|
||||
* configuration or become primary; it
|
||||
* STAYS ALIVE and keeps retrying.
|
||||
* NEVER self-terminates (loud
|
||||
* non-serving fence only). 0 at init
|
||||
* (ha_init memset). */
|
||||
/* ── New field added by raft-drive-async spec (Task 2.1) ──────── */
|
||||
_Atomic int reconnect_inflight[MAX_HA_CANDIDATES]; /* Per-peer
|
||||
* single-flight guard for the offloaded
|
||||
|
|
@ -755,6 +793,41 @@ int ha_dispatch_gate(ha_state_t *ha, int opcode);
|
|||
*/
|
||||
int ha_config_promotion_fenced(const ha_state_t *ha);
|
||||
|
||||
/*
|
||||
* upgrade_materialization_verify (config-upgrade-snapshot task 6.1, Req 1.8,
|
||||
* 3.2, 3.4): the Activation Fence's own verify function. Mirrors
|
||||
* config_activate_committed's exact shape (config_repl.c:304-377) for a
|
||||
* DIFFERENT, independently-tracked condition — see ha_state_t's
|
||||
* upgrade_materialization_fence field doc comment above for the full
|
||||
* rationale on why this must be a separate fence from config_serve_fence.
|
||||
*
|
||||
* On every call: reads the current committed WAL_CONFIG_MARKER (the
|
||||
* authority for the target upgrade), checks whether THIS MEMBER'S OWN
|
||||
* checkpoint machinery has already captured a materialization reference for
|
||||
* that EXACT marker (c->persist.cfgref_present/cfgref_tag/cfgref_sha,
|
||||
* stamped by every checkpoint via persist.c's scan_latest_committed_config_
|
||||
* ref), and separately re-reads the LIVE, currently-active config bytes off
|
||||
* disk FRESH (never a cached/embedded copy) to hash-verify them against the
|
||||
* marker too. Both must hold for the fence to clear.
|
||||
*
|
||||
* Returns 0 (fence cleared or absent-marker benign case) on success;
|
||||
* -EAGAIN when materialization is incomplete or the hash mismatches (fence
|
||||
* SET, logged loud only on the 0->1 transition); -EINVAL/-EIO on a genuine
|
||||
* error reading the committed marker. NEVER exits/aborts on this condition
|
||||
* (controller/CLAUDE.md never-self-terminate invariant) — always fail loud +
|
||||
* fence + stay alive + retriable.
|
||||
*/
|
||||
int upgrade_materialization_verify(cluster_t *c);
|
||||
|
||||
/*
|
||||
* upgrade_materialization_fenced: 1 when this member's own upgrade-snapshot
|
||||
* materialization for the current committed config marker is incomplete or
|
||||
* hash-mismatched (upgrade_materialization_fence set); 0 otherwise. Trivial
|
||||
* atomic-read accessor — mirrors config_serve_fenced (config_repl.c:262-268)
|
||||
* exactly, for the new independent fence. Pure atomic read (no I/O).
|
||||
*/
|
||||
int upgrade_materialization_fenced(const cluster_t *c);
|
||||
|
||||
/*
|
||||
* ha_apply_wal_catchup_entry: apply a single WAL catch-up entry to local
|
||||
* persistent storage and advance ha->applied_lsn on success.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue