feat(raft-log-replication): raft_log_append leader client-entry append (tasks 3.1, 3.2)

Leader-only (-EPERM for follower/candidate, no mutation/callback); index=
log_len+1, term=currentTerm (raft.tla ClientRequest:246, Req 2.1-2.4);
persist-before-act: on_persist_entry called once BEFORE log_len advances,
non-zero return propagated with no phantom entry (Req 2.5); no commit-index
advance, no transport I/O. Spy-based tests for all four branches. ASAN green.
This commit is contained in:
Rongsong Shen 2026-06-21 15:50:33 +00:00
parent fc87a662cd
commit e5b9b83955
3 changed files with 212 additions and 2 deletions

View file

@ -470,3 +470,36 @@ int raft_check_and_start_election(raft_state_t *s)
(void)rc;
return RAFT_ELECTION_STARTED;
}
int raft_log_append(raft_state_t *s, const void *entry, size_t len,
uint64_t *out_index)
{
/* Role gate (Req 2.2): only a leader may grow the log. Reject without any
* log mutation or callback (raft.tla ClientRequest is enabled only at the
* leader). */
if (s->role != RAFT_LEADER)
return -EPERM;
/* Assign the next 1-based index (== WAL LSN) and stamp the leader's current
* term, mirroring raft.tla ClientRequest's [term ↦ currentTerm, value ↦ v]
* (Req 2.1, 2.3, 2.4). */
uint64_t index = s->log_len + 1;
uint64_t term = s->term;
/* Persist-before-act (Req 2.3, 2.5): durably write the entry BEFORE
* advancing log_len. On failure, propagate the error verbatim and leave the
* log untouched (no phantom entry). */
int rc = s->cbs->on_persist_entry(s->ctx, index, term, entry, len);
if (rc != 0)
return rc;
/* Commit the append only after a successful persist. */
s->log_len = index;
if (out_index)
*out_index = index;
if (s->cbs->on_trace)
s->cbs->on_trace(s->ctx, "log_append", NULL);
return RAFT_OK;
}