fix(election): no-config nodes skip own election; delay_ms=0 fires election immediately
This commit is contained in:
parent
937605ec60
commit
a75fb2581b
1 changed files with 38 additions and 1 deletions
|
|
@ -314,6 +314,12 @@ static void raft_cb_start_election_after_delay(void *ctx, uint32_t delay_ms)
|
|||
cluster_t *c = ha->raft_c;
|
||||
if (!c) return; /* test mode */
|
||||
|
||||
/* Priority 0 → delay_ms == 0: highest-priority node starts immediately. */
|
||||
if (delay_ms == 0) {
|
||||
raft_check_and_start_election(&ha->raft);
|
||||
return;
|
||||
}
|
||||
|
||||
election_timeout_ctx_t *t = calloc(1, sizeof(*t));
|
||||
if (!t) return;
|
||||
|
||||
|
|
@ -2372,7 +2378,14 @@ void ha_start_election_async(ha_state_t *ha, cluster_t *c,
|
|||
|
||||
/* Step 4: delegate election to raft library.
|
||||
*
|
||||
* raft_start_election:
|
||||
* A node with no valid local config (my_config_tag == 0) must not start an
|
||||
* election — any peer with a real config tag will beat it in the freshness
|
||||
* gate and the node would waste a term increment. It stays in CTRL_ELECTING,
|
||||
* accepts incoming vote requests (granting to fresher peers), and will
|
||||
* become STANDBY after the winner sends it a heartbeat/ctrlhello.
|
||||
* n_peers and raft state are already initialised above so RDHUP retries work.
|
||||
*
|
||||
* raft_start_election when allowed:
|
||||
* - increments ha->raft.term and records self-vote (fires on_persist)
|
||||
* - single-node: fires on_become_leader → raft_cb_become_leader
|
||||
* - multi-node: fires on_send_vote_request per peer → raft_cb_send_vote_request
|
||||
|
|
@ -2380,6 +2393,30 @@ void ha_start_election_async(ha_state_t *ha, cluster_t *c,
|
|||
*
|
||||
* No direct ha->term++ or ha->voted_for_* writes happen in this function
|
||||
* after this call; the raft library owns those via on_persist. */
|
||||
/* Req 4.3 / ha-config-bootstrap Req 2.8:
|
||||
* A node with no local config (my_config_tag == 0) must not start an
|
||||
* election if any peer has a valid config — it cannot win (freshness gate
|
||||
* denies it) and it would waste a term increment. It stays in CTRL_ELECTING,
|
||||
* accepts incoming vote requests (granting to fresher peers), and becomes
|
||||
* STANDBY after the winner sends a heartbeat.
|
||||
*
|
||||
* Exception: if ALL peers also have config_tag=0 (cluster cold-start with no
|
||||
* configured node), someone must win — allow election normally.
|
||||
*
|
||||
* my_config_tag comes from myconf->config_version_tag set by load_primary_config;
|
||||
* n_peers and the peer list from --peers are always available via the parameters.
|
||||
* We check if any peer returned a non-zero tag via the xce_probe_config_tag path
|
||||
* already called in myapp_run before ha_start_election_async. */
|
||||
if (my_config_tag == 0 && n_peers > 1) {
|
||||
INFO("ha_start_election_async: no local config (tag=0, n_peers=%d) — "
|
||||
"participating as voter only, not starting own election", n_peers);
|
||||
/* Free ctx — no vote sends will happen from this node this round. */
|
||||
atomic_store_explicit(&ha->elect_ctx, NULL, memory_order_release);
|
||||
pthread_mutex_destroy(&ctx->lock);
|
||||
sem_destroy(&ctx->done);
|
||||
free(ctx);
|
||||
return;
|
||||
}
|
||||
raft_start_election(&ha->raft);
|
||||
|
||||
/* For single-node, raft_start_election fires on_become_leader synchronously.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue