feat(ha-commit-durability): durable-backed vote/PreVote freshness floor + bare-durable candidate advertise (task 4.2)
This commit is contained in:
parent
4b7457144c
commit
3049b620f3
7 changed files with 282 additions and 26 deletions
|
|
@ -2141,6 +2141,31 @@ void ha_vote_self_freshness(ha_state_t *ha,
|
|||
*out_lsn = (local_applied_lsn > learned_lsn) ? local_applied_lsn : learned_lsn;
|
||||
}
|
||||
|
||||
/* ── Candidate advertised LSN (election safety, ha-commit-durability 4.2) ───
|
||||
*
|
||||
* A candidate advertises EXACTLY its durable WAL tip on the LSN axis — the
|
||||
* bare `persist_durable_floor(p)`, NOT the folded
|
||||
* max(durable_floor, last_known_committed_lsn) that ha_vote_self_freshness
|
||||
* computes for the VOTER floor.
|
||||
*
|
||||
* Why bare, not folded: ha_vote_self_freshness unconditionally returns
|
||||
* max(local_lsn, last_known_committed_lsn). Feeding it durable_floor would let
|
||||
* a node restarted with a TRUNCATED log (durable_floor low) but a stale
|
||||
* volatile learned_committed (high) advertise the stale-high value and WIN —
|
||||
* exactly the truncated-candidate-wins hole this task closes (design §1a/§5a).
|
||||
* A candidate may only claim a log position it can durably back.
|
||||
*
|
||||
* The candidate's TAG axis is unchanged: it still uses
|
||||
* max(local_config_tag, learned_tag) (the config epoch is orthogonal to log
|
||||
* durability — design §1a). Only the LSN axis bypasses the fold.
|
||||
*
|
||||
* NULL-safe (persist_durable_floor guards NULL → 0) for the test/seam paths.
|
||||
*/
|
||||
uint64_t ha_candidate_advertise_lsn(persist_t *p)
|
||||
{
|
||||
return persist_durable_floor(p);
|
||||
}
|
||||
|
||||
/* ── Vote Handler (Req 2.2–2.6, 6.1, 6.2, 6.4, 9.1) ────────────────────────
|
||||
*
|
||||
* handle_request_vote: process an incoming OP_requestVote RPC.
|
||||
|
|
@ -3655,14 +3680,19 @@ static void ha_enter_real_election(ha_state_t *ha, cluster_t *c)
|
|||
if (committed > 0)
|
||||
persist_truncate_wal_above(&c->persist, committed);
|
||||
|
||||
/* Candidate freshness for the RequestVote payload — same floor the voter
|
||||
* side computes (ha_vote_self_freshness), matching the rdhup path. */
|
||||
/* Candidate freshness for the RequestVote payload (ha-commit-durability
|
||||
* task 4.2). The TAG axis uses the same config-epoch fold the voter side
|
||||
* computes (ha_vote_self_freshness), but the LSN axis advertises the BARE
|
||||
* durable WAL tip — a candidate may only claim a log position it can
|
||||
* durably back, so a truncated-restart node cannot over-advertise a stale
|
||||
* volatile learned-committed value and win (design §1a/§5a). */
|
||||
uint64_t cand_tag = 0, cand_lsn = 0;
|
||||
if (c->myconf) {
|
||||
uint64_t local_tag = c->myconf->config_version_tag;
|
||||
uint64_t local_lsn = atomic_load_explicit(&ha->applied_lsn,
|
||||
memory_order_acquire);
|
||||
ha_vote_self_freshness(ha, local_tag, local_lsn, &cand_tag, &cand_lsn);
|
||||
ha_vote_self_freshness(ha, local_tag, local_lsn, &cand_tag, NULL);
|
||||
cand_lsn = ha_candidate_advertise_lsn(&c->persist);
|
||||
}
|
||||
|
||||
int n_peers = (c->myconf) ? c->myconf->peers_cfg.candidates_count : 1;
|
||||
|
|
@ -3738,7 +3768,10 @@ void ha_start_prevote_async(ha_state_t *ha, cluster_t *c)
|
|||
uint64_t local_tag = c->myconf->config_version_tag;
|
||||
uint64_t local_lsn = atomic_load_explicit(&ha->applied_lsn,
|
||||
memory_order_acquire);
|
||||
ha_vote_self_freshness(ha, local_tag, local_lsn, &cand_tag, &cand_lsn);
|
||||
/* Task 4.2: TAG via the config-epoch fold, LSN as the bare durable WAL
|
||||
* tip (PreVote must not over-advertise either — design §1a). */
|
||||
ha_vote_self_freshness(ha, local_tag, local_lsn, &cand_tag, NULL);
|
||||
cand_lsn = ha_candidate_advertise_lsn(&c->persist);
|
||||
n_peers = c->myconf->peers_cfg.candidates_count;
|
||||
|
||||
int n_other = (n_peers > 1) ? n_peers - 1 : 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue