test(ha-convergence-recovery): RED ACK-driven catch-up continuation tests + seam (task 4.1)

This commit is contained in:
Rongsong Shen 2026-06-14 05:16:54 +00:00
parent 63c12461a5
commit c2221077ff
6 changed files with 566 additions and 1 deletions

View file

@ -200,6 +200,17 @@ typedef struct {
* CtrlHelloReply in the same process
* lifetime cannot re-fire the restart.
* 0 at init (cleared by ha_init memset). */
/* ── New field added by ha-convergence-recovery spec (Task 4.x) ──────── */
_Atomic int catchup_inflight[MAX_STANDBYS]; /* Per-standby single-flight
* guard for ACK-driven catch-up
* continuation (Req 5.2): set when a
* continuation is scheduled for a
* standby slot, cleared when it
* completes; a duplicate walAck while
* the flag is set schedules nothing.
* Slot identity (the repl registry slot
* index) is stable across schedule/run.
* 0 at init (cleared by ha_init memset). */
} ha_state_t;
/* ── Public API ────────────────────────────────────────────── */
@ -909,6 +920,44 @@ extern void (*ha_fatal_hook)(const char *msg);
* used by the promotion-side lifecycle tests.
*/
void raft_cb_become_follower_with_cluster_for_test(cluster_t *c, uint64_t term);
/*
* ha_walack_continuation_for_test: test-only entry point for the ACK-driven
* catch-up continuation logic (ha-convergence-recovery task 4.x, Req 5.1, 5.2,
* 7.1).
*
* The production trigger lives in the walAck branch of
* repl_ack_decode_and_dispatch (ha.c), which decodes a real Cap'n Proto
* WalAckReply off the wire — too heavy to drive from a unit test. This shim
* exposes the SAME post-ACK decision the walAck branch performs after
* repl_on_ack, so the continuation / single-flight / parity behaviors can be
* exercised directly against a unit fixture:
*
* target = max(committed_lsn, last_written) (same derivation as ha.c:2771-2776)
* if acked_lsn < target → schedule ONE continuation that streams
* [acked_lsn+1, target] via the catch-up streaming
* path, UNLESS ha.catchup_inflight[peer_idx] is set
* (single-flight, Req 5.2); the continuation must not
* dispatch any heartbeat/stateReport action (Req 5.1).
* if acked_lsn >= target → repl_complete_catchup(&c->persist.repl, ep), which
* clears the standby's in_catch_up (Req 7.1).
*
* c — cluster_t* (real persist + repl registry; never NULL in tests)
* ep — repl registry endpoint key for the standby (the same pointer
* passed to repl_add_standby); identifies the standby slot.
* peer_idx — 0-based standby slot index (into ha.catchup_inflight[]).
* acked_lsn— the LSN the standby just acknowledged.
*
* Returns 0 on the no-op / parity paths and on a successfully scheduled
* continuation; negative on a scheduling failure.
*
* RED scaffold (task 4.1): ha_convergence.c currently records the ACK only and
* neither schedules a continuation nor calls repl_complete_catchup — task 4.2
* implements the real decision. The continuation / single-flight / parity tests
* therefore FAIL until 4.2 lands.
*/
int ha_walack_continuation_for_test(cluster_t *c, void *ep, int peer_idx,
uint64_t acked_lsn);
#endif
#endif /* HA_H */