fix(controller,lib): decide each PreVote round once and promote only with this election's votes (bug-1915)
A late PreVote grant after WON re-ran the WON path and started a second real election that replaced elect_ctx, so the term-2 leader promoted no vote endpoints. Rounds now carry an id and endpoints a round/kind; stale or wrong-kind replies, timeouts and errors are dropped; raft ignores replies with no round in progress. raft_cb_become_leader promotes only with its own stamped election record (own term, majority), else steps down and re-arms. raft_on_leader_lost keeps voted_for (one vote per term) and the delayed election starts only as a follower in the lost term. The failover stagger hands the PreVote start to a vtask so the delaymgr stays trigger-only. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
acf78f9a94
commit
88a8bf8a47
7 changed files with 2463 additions and 201 deletions
|
|
@ -125,6 +125,14 @@ typedef struct {
|
|||
* for the full rationale (a pure per-endpoint count would allow a
|
||||
* spurious free before the round is superseded). */
|
||||
_Atomic int refcount;
|
||||
/* bug-1915 follow-up: which round this carrier belongs to, checked by
|
||||
* raft_cb_become_leader before it trusts votes[]. election_term is the
|
||||
* term ha_start_election_async stamped (raft.term + 1, under raft_lock,
|
||||
* immediately before raft_start_election); 0 = not stamped (synthetic
|
||||
* test carriers). is_pre_vote = 1 for a PreVote round carrier
|
||||
* (ha_start_prevote_async), which never holds real votes. */
|
||||
uint64_t election_term;
|
||||
int is_pre_vote;
|
||||
ha_vote_entry_t votes[]; /* C99 flexible array: n_peers-1 entries */
|
||||
} ha_elect_ctx_t;
|
||||
|
||||
|
|
@ -245,6 +253,13 @@ typedef struct {
|
|||
* -> real election, within one call chain) — that nesting must not
|
||||
* self-deadlock, while a genuinely different thread still fully blocks. */
|
||||
pthread_mutex_t raft_lock;
|
||||
/* bug-1915 follow-up: PreVote round id. Incremented under raft_lock by
|
||||
* ha_start_prevote_async for every round it starts and captured by that
|
||||
* round's PreVote endpoints and round timeout, so a reply, endpoint error
|
||||
* or timeout from an older round is dropped instead of being tallied in
|
||||
* the current one (PreVote replies carry no round id on the wire).
|
||||
* Read and written only under raft_lock. */
|
||||
uint64_t pre_vote_round;
|
||||
/* ── New fields added by raft-library spec (Task 6.2) ──────── */
|
||||
cluster_t *raft_c; /* cluster_t* set by ha_start_election_async; used by raft callbacks */
|
||||
void *raft_election_timeout_ctx; /* election_timeout_ctx_t* for cancel (task 6.2) */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue