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

@ -188,6 +188,23 @@ struct persist_s {
uint64_t term_index_count; /* highest recorded LSN (slots in use) */
uint64_t term_index_cap; /* allocated slot capacity */
/* Durable committed-config reference carried in the checkpoint sentinel
* (ha-term-safety task 4.2 remediation r1 — compaction-safe config derive).
* A checkpoint trims WAL segments older than the open one (trim_wal_segments)
* and the snapshot sentinel does NOT carry entity state, so a committed
* WAL_CONFIG_MARKER in a trimmed segment would vanish and the derived
* committed config (config_committed_marker) would regress. To prevent that,
* checkpoint stamps the latest-committed marker's 40-byte REFERENCE
* ({version_tag, sha256} — a reference, NOT the config bytes / entity
* snapshot) into the sentinel; recovery reads it back here; and the derive
* falls back to this when no marker survives the live WAL scan.
* cfgref_present == 0 means "no committed config marker was known at the last
* checkpoint" (a fresh store or a pre-config-marker checkpoint). Written
* single-threaded at checkpoint/recovery; read by config_committed_marker. */
int cfgref_present; /* 1 if cfgref_tag/sha are valid */
uint64_t cfgref_tag; /* latest committed marker version_tag */
uint8_t cfgref_sha[32]; /* latest committed marker content hash */
/* Recovery-integrity verdict (ha-commit-durability task 3.1, Req 2.1).
* Set by persist_recover/replay_wal at startup: RECOVER_CLEAN when the
* local WAL forms a valid CRC chain to a clean entry boundary (incl. an
@ -559,6 +576,13 @@ void persist_test_sync_append_legacy_commit_store(persist_t* p,
* (so an unprimed read can never falsely look "off-thread"). Compiled out of
* production. */
pthread_t persist_test_last_fdatasync_thread(persist_t* p);
/* Close the active WAL segment and open a fresh one at the current LSN
* (ha-term-safety task 4.2 r1 test seam). Forces a multi-segment layout so a
* subsequent persist_checkpoint trims the older segment — exercising the
* compaction hazard where a committed marker's segment is unlinked. Returns 0
* on success, negative errno on I/O failure. Compiled out of production. */
int persist_test_force_new_segment(persist_t* p);
#endif /* XCE_TESTING */
/* Checkpoint */