fix(ha-bootstrap): priority staggering and candidate_id in election
Two Raft correctness fixes: 1. Priority staggering in ha_wait_for_heartbeat_or_timeout(): Add my_priority × election_priority_step_ms to the timeout so ctrl-a (priority=0) times out first and starts election before ctrl-b (priority=1) and ctrl-c (priority=2). This gives the highest-priority node a head start and prevents simultaneous campaigning that causes perpetual split votes. 2. candidate_id in vote RPC: Pass the actual node name (myconf->name) as candidate_id instead of "". This fixes the voted_for deduplication gate (Req 2.6): a peer that already voted for ctrl-a will correctly deny a second vote request from ctrl-b in the same term. Thread context gets my_name field; am_i_primary_quorum() takes my_name parameter; all call sites updated (myapp.c, ha.c RDHUP, test_ha_election.c stubs).
This commit is contained in:
parent
fcfb82f7c7
commit
80950ffbba
4 changed files with 20 additions and 9 deletions
|
|
@ -636,8 +636,11 @@ ctrl_role_t ha_wait_for_heartbeat_or_timeout(ha_state_t *ha)
|
|||
if (ha->jitter_seed == 0)
|
||||
ha_seed_jitter(&ha->jitter_seed, ha->my_priority);
|
||||
|
||||
/* Compute timeout in milliseconds: election_timeout + random jitter */
|
||||
/* Compute timeout: election_timeout + priority_step * priority + random jitter.
|
||||
* Higher-priority (lower index) nodes time out sooner, giving them a head
|
||||
* start in the election before lower-priority nodes begin campaigning. */
|
||||
long to_ms = (long)ha->config.election_timeout_ms;
|
||||
to_ms += (long)ha->my_priority * (long)ha->config.election_priority_step_ms;
|
||||
if (ha->config.election_jitter_max_ms > 0) {
|
||||
to_ms += (long)(xorshift64_next(&ha->jitter_seed)
|
||||
% ((uint64_t)ha->config.election_jitter_max_ms + 1));
|
||||
|
|
@ -1020,6 +1023,7 @@ typedef struct {
|
|||
uint64_t my_tag; /* config_tag sent in the request */
|
||||
uint64_t my_lsn; /* WAL LSN sent in the request */
|
||||
int timeout_ms; /* Connect + I/O timeout */
|
||||
const char *my_name; /* Candidate node name for voted_for deduplication */
|
||||
} vote_thread_ctx_t;
|
||||
|
||||
/*
|
||||
|
|
@ -1097,7 +1101,7 @@ static void *vote_request_thread(void *arg)
|
|||
request_vote_req_t vote_req;
|
||||
memset(&vote_req, 0, sizeof(vote_req));
|
||||
vote_req.term = vctx->my_term;
|
||||
vote_req.candidate_id = (char *)""; /* anonymous; peer reads configTag/lsn */
|
||||
vote_req.candidate_id = (char *)(vctx->my_name ? vctx->my_name : "");
|
||||
vote_req.config_tag = vctx->my_tag;
|
||||
vote_req.last_log_lsn = vctx->my_lsn;
|
||||
|
||||
|
|
@ -1229,7 +1233,8 @@ ctrl_role_t am_i_primary_quorum(ha_state_t *ha,
|
|||
int n_peers,
|
||||
xce_candidate_t **peers,
|
||||
uint64_t my_config_tag,
|
||||
uint64_t my_lsn)
|
||||
uint64_t my_lsn,
|
||||
const char *my_name)
|
||||
{
|
||||
/* Req 2.9: single-node self-elects immediately */
|
||||
if (n_peers == 1) {
|
||||
|
|
@ -1320,6 +1325,7 @@ ctrl_role_t am_i_primary_quorum(ha_state_t *ha,
|
|||
vctxs[i].my_lsn = my_lsn;
|
||||
vctxs[i].timeout_ms =
|
||||
(int)ha->config.probe_connect_timeout_ms;
|
||||
vctxs[i].my_name = my_name;
|
||||
pthread_create(&tids[i], NULL, vote_request_thread, &vctxs[i]);
|
||||
}
|
||||
|
||||
|
|
@ -1576,7 +1582,8 @@ void ha_on_primary_ctrl_fd_rdhup(ha_state_t *ha, cluster_t *c)
|
|||
uint64_t my_tag = c->myconf->config_version_tag;
|
||||
uint64_t my_lsn = atomic_load_explicit(&c->persist.committed_lsn,
|
||||
memory_order_acquire);
|
||||
ctrl_role_t new_role = am_i_primary_quorum(ha, np, peer_ptrs, my_tag, my_lsn);
|
||||
ctrl_role_t new_role = am_i_primary_quorum(ha, np, peer_ptrs, my_tag, my_lsn,
|
||||
c->myconf ? c->myconf->name : "");
|
||||
if (new_role == CTRL_PRIMARY)
|
||||
INFO("HA: RDHUP recovery → CTRL_PRIMARY (Req 6.8)");
|
||||
else
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue