feat(ha-term-safety): append config markers via unified log + derive committed config (task 4.2)

Wires do_upgrade_config_with_bytes to append WAL_CONFIG_MARKER through
raft_log_append (live term-stamped consensus record), demotes committed_config_tag
to a non-authoritative cache, and derives the committed config from the latest
committed marker. Preserves the derive across checkpoint compaction via an optional,
backward-compatible config-ref tail in the snapshot sentinel.
This commit is contained in:
Rongsong Shen 2026-06-22 10:34:10 +00:00
parent f447ad4183
commit c3201a2b1e
7 changed files with 883 additions and 21 deletions

View file

@ -73,6 +73,77 @@ int config_marker_encode(uint64_t version_tag, const uint8_t sha256[32],
int config_marker_decode(const uint8_t *buf, size_t len,
uint64_t *version_tag, uint8_t sha256_out[32]);
/* ── Config marker append / committed-config derive (task 4.2) ───────
*
* A configuration change is ordered and committed through the SAME replicated
* (term,lsn) log as job state: a lightweight WAL_CONFIG_MARKER carrying only a
* reference to the configuration ({version_tag, sha256}). The committed
* configuration is DERIVED from the latest committed marker within the committed
* prefix — there is no separate authoritative config commit index (R7.1/R7.7).
*/
/*
* config_append_marker: append a config-change marker (version_tag + sha256,
* NO config bytes — R7.2/R7.4) to the unified replicated log via the single
* primary append entry point (ha_primary_log_append → raft_log_append), so the
* marker inherits the live-term stamp (R7.3), the same commit rule (R7.11), and
* the same (term,lsn) reconcile/truncate (R7.6) as a job-state entry. The
* configuration bytes travel out-of-band on the config-push transport (R7.5),
* never inside the marker.
*
* c — cluster (must be the leader for a real raft append)
* version_tag — the config version tag (be64 of the first 8 sha256 bytes)
* sha256 — the full 32-byte content hash (the reference)
* out_lsn — (may be NULL) receives the assigned 1-based LSN on success
*
* Returns 0 on success; -EINVAL on a NULL argument; otherwise the append rc
* propagated from ha_primary_log_append.
*/
int config_append_marker(cluster_t *c, uint64_t version_tag,
const uint8_t sha256[32], uint64_t *out_lsn);
/*
* config_committed_marker: derive the committed configuration reference from the
* LATEST WAL_CONFIG_MARKER at or below committed_lsn (R7.7). Scans the committed
* prefix of the local WAL; an uncommitted marker (LSN > committed_lsn) is
* deliberately ignored, so a config change is not the committed config until its
* marker reaches the committed prefix.
*
* c — cluster
* version_tag — (may be NULL) receives the latest committed marker's tag
* sha256_out — (may be NULL) receives the latest committed marker's 32-byte hash
*
* Returns 0 on success; -ENOENT when no committed config marker exists;
* -EINVAL on a NULL cluster; -EIO on a WAL read error.
*/
int config_committed_marker(const cluster_t *c, uint64_t *version_tag,
uint8_t sha256_out[32]);
/*
* config_commit_change: order + commit a config change through the unified
* (term,lsn) log (ha-term-safety task 4.2 LIVE wiring). Appends a
* WAL_CONFIG_MARKER as the consensus record, pushes the config bytes
* out-of-band on the existing config-push transport (R7.5 — byte delivery /
* hash-verify / activate is task 4.3), and waits for the MARKER's LSN to reach
* the committed prefix via the same WAL commit barrier job state uses (R7.11).
* On commit it refreshes committed_config_tag as a NON-AUTHORITATIVE cache that
* mirrors the DERIVED committed marker (config_committed_marker is the
* authority — R7.7). do_upgrade_config_with_bytes uses this instead of the
* retired term-blind committed_config_tag push/ack/advance.
*
* c — cluster (must be leader for the marker append)
* bytes/blen — re-encoded config bytes (pushed out-of-band, never in the WAL)
* sha256 — content hash (the marker reference)
* version_tag — config version tag
* acked_out — (may be NULL) receives the out-of-band transport push count
*
* Returns 0 once the marker is committed; the barrier rc (-ETIMEDOUT/-EINVAL)
* when it never commits; a negative append rc on append failure.
*/
int config_commit_change(cluster_t *c, const uint8_t *bytes, size_t blen,
const uint8_t sha256[32], uint64_t version_tag,
int *acked_out);
/* ── Phase 1: Storage ────────────────────────────────────────── */
/*