feat(raft-ha-core-safety): establish snapshot (term,lsn) boundary on install (task 3.2)
Adds checkpointTerm (@6, append-only) to the SnapshotTransfer wire message. The leader stamps it via persist_entry_term(p, checkpoint_lsn) when sending a snapshot; the standby reconciles it into its own per-LSN term index (persist_reconcile_checkpoint_term) right after persist_load_snapshot succeeds, before applied_lsn advances. This authoritatively overwrites any stale local term a divergent pre-snapshot entry left at the checkpoint LSN, closing the gap task 3.1's RED test proved (Expected 7 Was 3 -> now passes). Transport stays persist_t-free; the reconcile lives in persist.c per the existing dependency direction. Decode is auto-generated via capnp mapname; only the hand-rolled encode path (request.c/typemap.h, needed for the raw snapshot payload) required a matching manual update. test_ha_core_safety 25/0, test_config_repl 66/0, no ASAN reports.
This commit is contained in:
parent
21858faba4
commit
a53b9a7b6c
11 changed files with 132 additions and 23 deletions
|
|
@ -354,6 +354,31 @@ void persist_set_term(persist_t* p, uint64_t term);
|
|||
* Safe on a NULL p (returns 0). */
|
||||
uint64_t persist_entry_term(const persist_t* p, uint64_t lsn);
|
||||
|
||||
/* raft-ha-core-safety task 3.2 (Req 3.1/5.1) — Snapshot Boundary Reconcile.
|
||||
*
|
||||
* Authoritatively overwrite the per-LSN term index entry at `checkpoint_lsn`
|
||||
* with `checkpoint_term` (the checkpoint's own true term, as carried on the
|
||||
* wire by the leader that shipped the snapshot). Called from the standby
|
||||
* snapshot-install receive path (ha_handle_snapshot_chunk) immediately after
|
||||
* persist_load_snapshot() succeeds, so a divergent pre-snapshot entry's STALE
|
||||
* local term at the checkpoint LSN is reconciled to the checkpoint's own
|
||||
* term. Establishes a verifiable (term, lsn) boundary: post-install AE intake
|
||||
* (prevLogIndex/prevLogTerm checks) never references an LSN below the
|
||||
* checkpoint against this member again, so only the checkpoint LSN's own
|
||||
* term needs reconciling — not the full compacted history below it.
|
||||
*
|
||||
* `checkpoint_term == 0` means a legacy sender (pre-task-3.2 peer) never
|
||||
* stamped the wire field; treat that as WAL_LEGACY_TERM per the existing
|
||||
* legacy-0 convention (record_entry_term stores the raw value verbatim; the
|
||||
* legacy-0 -> WAL_LEGACY_TERM mapping is applied uniformly at read-back by
|
||||
* persist_entry_term/entry_term_locked, so this call is consistent with that
|
||||
* convention without needing to special-case it here).
|
||||
*
|
||||
* Takes p->lock internally (callers must NOT already hold it). Safe on a
|
||||
* NULL p or checkpoint_lsn == 0 (no-op). */
|
||||
void persist_reconcile_checkpoint_term(persist_t* p, uint64_t checkpoint_lsn,
|
||||
uint64_t checkpoint_term);
|
||||
|
||||
/* Lifecycle */
|
||||
int persist_init(persist_t* p, persist_config_t* config, cluster_t* c);
|
||||
int persist_start(persist_t* p);
|
||||
|
|
|
|||
|
|
@ -338,6 +338,11 @@ struct snapshot_transfer_s {
|
|||
* owned by the struct, freed by xce_free_request(). */
|
||||
uint8_t *raw_payload;
|
||||
size_t raw_payload_len;
|
||||
/* raft-ha-core-safety task 3.2 (Req 3.1/5.1): the leader's term for the
|
||||
* checkpoint LSN above. 0 = unset (legacy sender) -> receiver treats as
|
||||
* WAL_LEGACY_TERM, same convention as persist's existing legacy-0 term
|
||||
* mapping (see entry_term_locked in persist.c). */
|
||||
uint64_t checkpoint_term;
|
||||
};
|
||||
|
||||
struct wal_catchup_entry {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue