feat(raft-library): task 2.2 — raft_callbacks_t, raft_config_t, public API signatures
This commit is contained in:
parent
66c9810823
commit
d109155a21
3 changed files with 191 additions and 1 deletions
|
|
@ -15,7 +15,7 @@
|
|||
- Header includes only `stdint.h`, `string.h`, `errno.h` — no `iomgr_t`, `endpoint_t`, `SSL_CTX`, `cluster_t`, or capnp types visible anywhere
|
||||
- _Requirements: 1.1, 1.3_
|
||||
|
||||
- [ ] 2.2 Define callback interface (raft_callbacks_t, raft_config_t) and all public function signatures
|
||||
- [x] 2.2 Define callback interface (raft_callbacks_t, raft_config_t) and all public function signatures
|
||||
- `raft_callbacks_t` with 9 function pointers: `on_send_vote_request`, `on_vote_eligible` (optional/NULL-safe), `on_become_leader`, `on_become_follower`, `on_persist`, `on_schedule_timeout`, `on_cancel_timeout`, `on_start_election_after_delay`, `on_trace` (optional/NULL-safe)
|
||||
- `raft_config_t` struct: `n_peers`, `self_idx`, `election_timeout_ms` (0 → 2000ms default), `my_priority`, `initial_term`, `initial_voted_for`, `cbs`, `ctx`
|
||||
- All public function signatures: `raft_init`, `raft_start_election`, `raft_on_vote_request`, `raft_on_vote_reply`, `raft_on_election_timeout`, `raft_on_leader_lost`, `raft_check_and_start_election`, `raft_snapshot`
|
||||
|
|
|
|||
|
|
@ -9,3 +9,51 @@ void raft_snapshot(const raft_state_t *s, raft_snapshot_t *snap)
|
|||
snap->votes_granted = s->votes_granted;
|
||||
snap->election_decided = s->election_decided;
|
||||
}
|
||||
|
||||
int raft_init(raft_state_t *s, const raft_config_t *cfg)
|
||||
{
|
||||
(void)s;
|
||||
(void)cfg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int raft_start_election(raft_state_t *s)
|
||||
{
|
||||
(void)s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int raft_on_vote_reply(raft_state_t *s, int from_idx, int granted, uint64_t term)
|
||||
{
|
||||
(void)s;
|
||||
(void)from_idx;
|
||||
(void)granted;
|
||||
(void)term;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void raft_on_election_timeout(raft_state_t *s)
|
||||
{
|
||||
(void)s;
|
||||
}
|
||||
|
||||
void raft_on_leader_lost(raft_state_t *s)
|
||||
{
|
||||
(void)s;
|
||||
}
|
||||
|
||||
int raft_check_and_start_election(raft_state_t *s)
|
||||
{
|
||||
(void)s;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,148 @@ typedef struct {
|
|||
int election_decided;
|
||||
} raft_snapshot_t;
|
||||
|
||||
/* raft_callbacks_t: all side effects the library fires.
|
||||
*
|
||||
* The library owns Raft invariants (term ordering, one-vote-per-term, quorum).
|
||||
* All application-specific policy (freshness gate, role gate, catch-up state,
|
||||
* heartbeat liveness) is delegated to on_vote_eligible so the library is
|
||||
* fully independent of XCE domain logic.
|
||||
*
|
||||
* REQUIRED callbacks (must be non-NULL at raft_init):
|
||||
* on_send_vote_request, on_become_leader, on_become_follower,
|
||||
* on_persist, on_schedule_timeout, on_cancel_timeout,
|
||||
* on_start_election_after_delay
|
||||
*
|
||||
* OPTIONAL callbacks (may be NULL):
|
||||
* on_vote_eligible — if NULL, all Raft-eligible candidates are granted
|
||||
* on_trace — if NULL, tracing is suppressed
|
||||
*/
|
||||
typedef struct {
|
||||
/* REQUIRED: Send a RequestVote RPC to peer peer_idx for the given term.
|
||||
* The caller encodes config_tag, log_lsn, and any other fields in the wire RPC. */
|
||||
int (*on_send_vote_request)(void *ctx, int peer_idx, uint64_t term);
|
||||
|
||||
/* OPTIONAL: Application-specific vote eligibility gate.
|
||||
* Called after Raft invariants pass (correct term, voted_for unset).
|
||||
* Returns 1 to grant, 0 to deny. Receives the candidate's peer_idx and
|
||||
* the incoming term so the caller can check freshness (config_tag, log_lsn),
|
||||
* role gate (LEADER/COMMITTING deny), catch-up status, heartbeat liveness.
|
||||
* If NULL, the library grants the vote whenever Raft invariants pass. */
|
||||
int (*on_vote_eligible)(void *ctx, int from_idx, uint64_t term);
|
||||
|
||||
/* REQUIRED: Node has won the election */
|
||||
void (*on_become_leader)(void *ctx, uint64_t term);
|
||||
/* REQUIRED: Node lost election or saw higher term; leader_idx = -1 if unknown */
|
||||
void (*on_become_follower)(void *ctx, uint64_t term, int leader_idx);
|
||||
/* REQUIRED: Persist term + voted_for before granting vote (durability guarantee) */
|
||||
int (*on_persist)(void *ctx, uint64_t term, int voted_for);
|
||||
/* REQUIRED: Schedule election timeout (fires raft_on_election_timeout after delay_ms) */
|
||||
void (*on_schedule_timeout)(void *ctx, uint32_t delay_ms);
|
||||
/* REQUIRED: Cancel pending election timeout */
|
||||
void (*on_cancel_timeout)(void *ctx);
|
||||
/* REQUIRED: Request delayed election start after RDHUP (priority-based jitter) */
|
||||
void (*on_start_election_after_delay)(void *ctx, uint32_t delay_ms);
|
||||
/* OPTIONAL: Trace callback for observability.
|
||||
* event: short string literal, e.g. "vote_granted", "became_leader"
|
||||
* detail: formatted human-readable context string
|
||||
* If NULL, tracing is suppressed. */
|
||||
void (*on_trace)(void *ctx, const char *event, const char *detail);
|
||||
} raft_callbacks_t;
|
||||
|
||||
/*
|
||||
* raft_config_t: initialization context for a Raft node.
|
||||
*
|
||||
* Encapsulates all configuration so raft_init() has a single, extensible
|
||||
* parameter rather than a flat list. Matches the existing XCE pattern
|
||||
* (ha_config_t, persist_config_t). Zero-initialize and set only the
|
||||
* fields you need — the library fills in safe defaults for unset fields.
|
||||
*
|
||||
* Persistence model:
|
||||
* initial_term / initial_voted_for are restored by the caller from disk
|
||||
* before raft_init(). The library never reads storage; it only writes
|
||||
* via on_persist callbacks. Pass {0, -1} on first boot.
|
||||
*/
|
||||
typedef struct {
|
||||
int n_peers; /* total cluster size (including self) */
|
||||
int self_idx; /* this node's index in [0, n_peers) */
|
||||
uint32_t election_timeout_ms; /* base election timeout; 0 → default 2000ms */
|
||||
int my_priority; /* priority index for RDHUP jitter (0 = highest) */
|
||||
uint64_t initial_term; /* term restored from disk; 0 on first boot */
|
||||
int initial_voted_for; /* voted_for restored from disk; -1 if none */
|
||||
const raft_callbacks_t *cbs; /* all callbacks; required callbacks must be non-NULL */
|
||||
void *ctx; /* opaque caller context passed to every callback */
|
||||
} raft_config_t;
|
||||
|
||||
/* Return codes
|
||||
*
|
||||
* Note: RAFT_GRANT and RAFT_BECAME_LEADER share value 1; RAFT_DENY and RAFT_OK
|
||||
* share value 0. This is intentional — different return values are used by
|
||||
* different functions (raft_on_vote_request vs raft_on_vote_reply) in different
|
||||
* call contexts.
|
||||
*/
|
||||
#define RAFT_OK 0
|
||||
#define RAFT_GRANT 1
|
||||
#define RAFT_DENY 0
|
||||
#define RAFT_BECAME_LEADER 1
|
||||
#define RAFT_BECAME_FOLLOWER 2
|
||||
#define RAFT_PENDING 3
|
||||
#define RAFT_ELECTED_IMMEDIATELY 4
|
||||
#define RAFT_SKIP_ELECTION 5
|
||||
#define RAFT_ELECTION_STARTED 6
|
||||
|
||||
/*
|
||||
* raft_init: initialize raft_state_t from a raft_config_t.
|
||||
* on_vote_eligible and on_trace may be NULL (optional policy / observability).
|
||||
* All other callbacks in cbs must be non-NULL.
|
||||
* Returns 0 on success; -EINVAL if a required callback is NULL or n_peers < 1.
|
||||
*/
|
||||
int raft_init(raft_state_t *s, const raft_config_t *cfg);
|
||||
|
||||
/*
|
||||
* raft_start_election: begin a new election.
|
||||
* Increments term, records self-vote (voted_for=self_idx), transitions to
|
||||
* CANDIDATE, fires on_send_vote_request for each peer, fires on_schedule_timeout.
|
||||
* Returns 0 on success; -EALREADY if already CANDIDATE/LEADER;
|
||||
* RAFT_ELECTED_IMMEDIATELY for single-node (n_peers==1).
|
||||
*/
|
||||
int raft_start_election(raft_state_t *s);
|
||||
|
||||
/*
|
||||
* raft_on_vote_request: process an incoming RequestVote RPC.
|
||||
* Applies Raft invariants (term comparison, one-vote-per-term).
|
||||
* If invariants pass, calls on_vote_eligible to allow application policy.
|
||||
* Fires on_persist before granting.
|
||||
* Returns RAFT_GRANT (1) or RAFT_DENY (0); sets *reply_term to current term.
|
||||
*/
|
||||
int raft_on_vote_request(raft_state_t *s, int from_idx, uint64_t term,
|
||||
uint64_t *reply_term);
|
||||
|
||||
/*
|
||||
* raft_on_vote_reply: process a reply to our RequestVote.
|
||||
* Returns RAFT_BECAME_LEADER, RAFT_BECAME_FOLLOWER, or RAFT_PENDING.
|
||||
*/
|
||||
int raft_on_vote_reply(raft_state_t *s, int from_idx, int granted, uint64_t term);
|
||||
|
||||
/*
|
||||
* raft_on_election_timeout: called by the timer when no quorum was reached.
|
||||
* Transitions CANDIDATE → FOLLOWER; fires on_become_follower, on_cancel_timeout.
|
||||
*/
|
||||
void raft_on_election_timeout(raft_state_t *s);
|
||||
|
||||
/*
|
||||
* raft_on_leader_lost: primary control channel dropped (RDHUP).
|
||||
* Clears voted_for, transitions to FOLLOWER, fires on_start_election_after_delay.
|
||||
*/
|
||||
void raft_on_leader_lost(raft_state_t *s);
|
||||
|
||||
/*
|
||||
* raft_check_and_start_election: call after the delay from raft_on_leader_lost.
|
||||
* Starts election only if we have not already voted for a non-self candidate
|
||||
* in the new term (i.e., another node won during the jitter window).
|
||||
* Returns RAFT_SKIP_ELECTION or RAFT_ELECTION_STARTED.
|
||||
*/
|
||||
int raft_check_and_start_election(raft_state_t *s);
|
||||
|
||||
/* Fills snap with current state. Caller must hold lock. */
|
||||
void raft_snapshot(const raft_state_t *s, raft_snapshot_t *snap);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue