feat(raft-library): task 3.3 — raft_on_vote_request 6-step decision; 10 tests

This commit is contained in:
Rongsong Shen 2026-05-31 05:44:34 +00:00
parent 4955fa3805
commit e0bcb35554
3 changed files with 497 additions and 15 deletions

View file

@ -101,11 +101,64 @@ int raft_start_election(raft_state_t *s)
int raft_on_vote_request(raft_state_t *s, int from_idx, uint64_t term,
uint64_t *reply_term)
{
(void)s;
(void)from_idx;
(void)term;
(void)reply_term;
return 0;
/* Step 1: stale term — deny immediately, no state change */
if (term < s->term) {
*reply_term = s->term;
if (s->cbs->on_trace)
s->cbs->on_trace(s->ctx, "vote_denied_stale_term", NULL);
return RAFT_DENY;
}
/* Step 2: term upgrade — update term, clear vote, step down to FOLLOWER */
if (term > s->term) {
s->term = term;
s->voted_for = -1;
s->voted_for_term = 0;
s->role = RAFT_FOLLOWER;
}
/* reply_term reflects our (possibly updated) current term from here on */
*reply_term = s->term;
/* Step 3: role gate — LEADER denies */
if (s->role == RAFT_LEADER) {
if (s->cbs->on_trace)
s->cbs->on_trace(s->ctx, "vote_denied_role", NULL);
return RAFT_DENY;
}
/* Step 4: duplicate-vote deny — already voted for a *different* candidate
* this same term. If voted_for == from_idx and voted_for_term == term,
* fall through to idempotent re-grant path below. */
if (s->voted_for != -1 &&
s->voted_for != from_idx &&
s->voted_for_term == term) {
if (s->cbs->on_trace)
s->cbs->on_trace(s->ctx, "vote_denied_already_voted", NULL);
return RAFT_DENY;
}
/* Step 5: application-level policy gate (freshness, log lsn, etc.) */
if (s->cbs->on_vote_eligible != NULL) {
if (s->cbs->on_vote_eligible(s->ctx, from_idx, term) == 0) {
if (s->cbs->on_trace)
s->cbs->on_trace(s->ctx, "vote_denied_freshness", NULL);
return RAFT_DENY;
}
}
/* Step 6: persist before granting — durability guarantee */
if (s->cbs->on_persist(s->ctx, term, from_idx) != 0) {
/* Persist failed — deny without updating voted_for */
return RAFT_DENY;
}
/* Grant: record vote */
s->voted_for = from_idx;
s->voted_for_term = term;
if (s->cbs->on_trace)
s->cbs->on_trace(s->ctx, "vote_granted", NULL);
return RAFT_GRANT;
}
int raft_on_vote_reply(raft_state_t *s, int from_idx, int granted, uint64_t term)