feat(raft-library): task 3.3 — raft_on_vote_request 6-step decision; 10 tests
This commit is contained in:
parent
4955fa3805
commit
e0bcb35554
3 changed files with 497 additions and 15 deletions
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue