feat(ha-term-safety): on_send_append_entries callback body (task 2.3)
Replaces the stub: builds a WalCatchupEntry AppendEntries to standbys[peer_idx].ep carrying prev_log_index/prev_log_term; for n_entries==1 sources the entry at prev_log_index+1 from the local WAL (term via persist_entry_term, type+payload via ha_read_wal_entry_at); n_entries==0 emits a zero-entry heartbeat. Async send (xce_wal_batch_req_raw), payload freed on all paths. 2 tests via a capture seam. Review-applied: corrected the misleading repl.c comment — leader_commit is accepted but NOT yet wire-encoded (deferred to task 3.2: WalCatchupEntry leaderCommit field + standby intake). Reviewer APPROVED; per-group 0 failures.
This commit is contained in:
parent
ed2443533f
commit
2c5d298cb5
6 changed files with 452 additions and 4 deletions
|
|
@ -71,6 +71,28 @@ int repl_active_standby_count(replicator_t *r);
|
|||
int repl_broadcast(replicator_t *r, const wal_entry_hdr_t *hdr,
|
||||
const void *payload, uint32_t payload_len);
|
||||
|
||||
/* AppendEntries send (ha-term-safety task 2.3, Req 1.3/3.1).
|
||||
*
|
||||
* Build and enqueue ONE AppendEntries envelope to the standby at slot
|
||||
* `peer_idx` (== the library's raft peer index, which maps 1:1 to the repl
|
||||
* standby registry slot — the same index used by match_index/next_index).
|
||||
* The envelope carries the AppendEntries prev tuple (`prev_log_index`,
|
||||
* `prev_log_term`) + `leader_commit`; when `n_entries == 1` it also carries the
|
||||
* single entry at LSN `prev_log_index + 1` whose `entry_term` is the term the
|
||||
* leader recorded for that LSN (== persist_entry_term) and whose
|
||||
* `entry_type`/`payload` are read from the leader's own WAL. `n_entries == 0`
|
||||
* is a heartbeat (zero entries) carrying only the prev tuple + leader_commit.
|
||||
*
|
||||
* Non-blocking: enqueues via the existing async repl transport
|
||||
* (xce_wal_batch_req_raw), never blocks. Returns 0 on enqueue, or a negative
|
||||
* errno (e.g. -ENOENT when peer_idx has no live endpoint). */
|
||||
int repl_send_append_entries(replicator_t *r, int peer_idx,
|
||||
uint64_t prev_log_index, uint64_t prev_log_term,
|
||||
uint64_t leader_commit, int n_entries,
|
||||
uint64_t entry_lsn, uint8_t entry_type,
|
||||
uint64_t entry_term,
|
||||
const void *payload, uint32_t payload_len);
|
||||
|
||||
/* WAL ACK handling — call from io_worker read callback ONLY */
|
||||
void repl_on_ack(replicator_t *r, repl_ep_t ep, uint64_t acked_lsn);
|
||||
|
||||
|
|
@ -108,3 +130,28 @@ void repl_complete_catchup(replicator_t *r, repl_ep_t ep);
|
|||
/* Returns 1 if standby needs a full snapshot transfer (its LSN predates oldest WAL).
|
||||
* oldest_wal_lsn == 0 means no WAL exists — no snapshot needed for LSN 0 standbys. */
|
||||
int repl_needs_snapshot(replicator_t *r, uint64_t standby_lsn, uint64_t oldest_wal_lsn);
|
||||
|
||||
#ifdef XCE_TESTING
|
||||
/* AppendEntries send capture seam (ha-term-safety task 2.3).
|
||||
*
|
||||
* When `repl_send_ae_capture_hook` is non-NULL, repl_send_append_entries
|
||||
* records the FULL built envelope into this struct instead of enqueuing it on a
|
||||
* real endpoint — so a unit test asserts the prev tuple / leader_commit /
|
||||
* n_entries / entry term + payload without network I/O. The payload bytes are
|
||||
* copied into a fixed buffer (capped at sizeof(payload)). */
|
||||
typedef struct {
|
||||
int called;
|
||||
int peer_idx;
|
||||
uint64_t prev_log_index;
|
||||
uint64_t prev_log_term;
|
||||
uint64_t leader_commit;
|
||||
int n_entries;
|
||||
uint64_t entry_lsn;
|
||||
uint8_t entry_type;
|
||||
uint64_t entry_term;
|
||||
uint32_t payload_len;
|
||||
uint8_t payload[256];
|
||||
} repl_ae_capture_t;
|
||||
|
||||
extern repl_ae_capture_t *repl_send_ae_capture_hook;
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue