fix(controller): record standby state under its absolute peer index (bug-1891)
A promoted vote endpoint carries a peer index relative to the votes array (which leaves out the primary); a late-joiner's heartbeat endpoint carries the absolute index. repl_ack_decode_and_dispatch recorded state reports under the raw index, so with ctrl-1 primary, ctrl-3's vote endpoint (relative 1) and a rejoined ctrl-2's heartbeat endpoint (absolute 1) shared standby_reported_*[1]. Each handler then acted on the other's position over its own endpoint: the snapshot meant for the empty, rejoining ctrl-2 went to the caught-up ctrl-3, and ctrl-2 never caught up. Resolve the absolute index with ha_repl_ack_abs_peer_idx (as the WAL-ack branch already did) for the state report and for ha_walack_on_ack, and size catchup_inflight by MAX_HA_CANDIDATES so every absolute index fits. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1922ac803e
commit
4922f6c844
6 changed files with 188 additions and 10 deletions
|
|
@ -279,7 +279,7 @@ typedef struct {
|
|||
* 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
|
||||
_Atomic int catchup_inflight[MAX_HA_CANDIDATES]; /* Per-standby (absolute peer index, bug-1891) single-flight
|
||||
* guard for ACK-driven catch-up
|
||||
* continuation (Req 5.2): set when a
|
||||
* continuation is scheduled for a
|
||||
|
|
@ -667,6 +667,16 @@ int ha_raft_on_repl_nack(cluster_t *c, int abs_peer_idx, uint64_t reply_term,
|
|||
* remap-vs-passthrough distinction cannot drift. */
|
||||
int ha_repl_ack_abs_peer_idx(ha_state_t *ha, int ep_is_vote, int peer_idx);
|
||||
|
||||
#ifdef XCE_TESTING
|
||||
/* bug-1891: run one inbound packet through the primary's replication-reply
|
||||
* dispatcher as if it arrived on a promoted vote endpoint (ep_is_vote=1,
|
||||
* relative votes index) or a heartbeat standby endpoint (ep_is_vote=0,
|
||||
* absolute index). Takes ownership of pkt. */
|
||||
int ha_repl_ack_dispatch_for_test(ha_state_t *ha, endpoint_t *ep,
|
||||
int ep_is_vote, int peer_idx,
|
||||
io_packet_t *pkt);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ha_schedule_demotion_convergence: schedule the one-shot delaymgr task that
|
||||
* truncates above committed_lsn (Req 1.2), WARN-logs the discarded range
|
||||
|
|
@ -762,7 +772,7 @@ void cluster_apply_ctrlhello_reply(cluster_t *c, uint64_t committed_lsn,
|
|||
* c — cluster_t* (real persist + repl registry; never NULL).
|
||||
* ep — repl registry endpoint key for the standby (endpoint_t* /
|
||||
* repl_ep_t); identifies the standby slot for streaming + parity.
|
||||
* peer_idx — 0-based standby slot index (into c->ha.catchup_inflight[]).
|
||||
* peer_idx — absolute peer index (into c->ha.catchup_inflight[]).
|
||||
* acked_lsn— the LSN the standby just acknowledged.
|
||||
*
|
||||
* Returns 0 on the parity / single-flight-suppressed paths and on a successfully
|
||||
|
|
@ -2293,7 +2303,7 @@ void raft_cb_become_leader_with_cluster_for_test(cluster_t *c, uint64_t term);
|
|||
* 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[]).
|
||||
* peer_idx — absolute peer 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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue