diff --git a/src/controller/ha.c b/src/controller/ha.c index 9230b406..bff52132 100644 --- a/src/controller/ha.c +++ b/src/controller/ha.c @@ -179,12 +179,20 @@ static int raft_cb_send_vote_request(void *ctx, int peer_idx, uint64_t term) vctx->my_lsn = (ectx->n_peers > 0) ? ectx->votes[0].my_lsn : 0; /* ha-term-safety task 1.2: advertise our Raft (lastLogTerm, lastLogIndex). * lastLogIndex == our WAL log length (the library's log_len == WAL tip LSN); - * lastLogTerm == the recovered/live WAL term that stamps that last entry. - * NOTE: sourced directly from persist (c->persist.term / raft.log_len), NOT - * via on_get_entry_term — that callback seam is task 2.x and is unwired here - * (see CONCERNS). The formal persist_entry_term accessor is task 1.3. */ + * lastLogTerm == the term STAMPED ON THAT LAST ENTRY. + * + * bug-851 / task 5.5: lastLogTerm MUST be the term of the entry at log_len — + * sourced via persist_entry_term, the SAME accessor voters use to compute + * their own last-log term (on_get_entry_term → persist_entry_term, ha.c:1556). + * The old stopgap advertised c->persist.term (the persist layer's RUNNING + * term), which is stale/0 after a restart and does NOT equal the last entry's + * stored term. That made a freshly-restarted but freshest survivor advertise + * a too-low lastLogTerm, so every voter's logOk rejected it (asymmetric with + * how the voter computes its own term) and the election stalled. */ vctx->my_last_log_index = ha->raft.log_len; - vctx->my_last_log_term = c ? c->persist.term : 0; + vctx->my_last_log_term = (c && ha->raft.log_len > 0) + ? persist_entry_term(&c->persist, ha->raft.log_len) + : 0; vctx->my_name = c->myconf ? c->myconf->name : ""; /* Get a fresh endpoint */ @@ -294,10 +302,14 @@ static int raft_cb_send_pre_vote_request(void *ctx, int peer_idx, vctx->my_term = prospective_term; vctx->my_tag = (ectx->n_peers > 0) ? ectx->votes[0].my_tag : 0; vctx->my_lsn = (ectx->n_peers > 0) ? ectx->votes[0].my_lsn : 0; - /* ha-term-safety task 1.2: advertise our Raft (lastLogTerm, lastLogIndex) - * — identical sourcing to the real-vote send path above. */ + /* ha-term-safety task 1.2 + bug-851/task 5.5: advertise lastLogTerm as the + * term of the entry at log_len (persist_entry_term — the same source voters + * use), NOT the stale c->persist.term. Identical sourcing to the real-vote + * send path above; see the full rationale there. */ vctx->my_last_log_index = ha->raft.log_len; - vctx->my_last_log_term = c ? c->persist.term : 0; + vctx->my_last_log_term = (c && ha->raft.log_len > 0) + ? persist_entry_term(&c->persist, ha->raft.log_len) + : 0; vctx->my_name = c->myconf ? c->myconf->name : ""; endpoint_t *ep = endpoint_get();