feat(ha-wal-replication): standby WAL ACK reply (tasks 3.1-3.3)

Standby sends WalAckReply via xce_reply after each successfully
applied WAL entry. ha_apply_wal_catchup_entry signature extended
with endpoint_t* and cluster_t* parameters. walackreplymsg union
arm added to RequestReply capnp schema and xce_reply_t. Error
entries skip ACK. Dispatch gate test confirms OPCode_walCatchupEntry
allowed in CTRL_STANDBY/ELECTING/INIT.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Rongsong Shen 2026-06-10 09:14:25 +00:00
parent 81dbc4d7b4
commit 566c91cd8b
8 changed files with 304 additions and 60 deletions

View file

@ -17,6 +17,8 @@ typedef struct upgrade_config_req_s upgrade_config_req_t;
typedef struct heartbeat_msg_s heartbeat_msg_t;
typedef struct ctrl_hello_req_s ctrl_hello_req_t;
typedef struct ctrl_hello_reply_s ctrl_hello_reply_t;
typedef struct wal_catchup_entry wal_catchup_entry_t;
typedef struct snapshot_transfer_s snapshot_transfer_t;
typedef struct {
char* resname;
@ -192,6 +194,15 @@ typedef struct {
uint64_t config_tag;
} state_report_t;
/* WAL apply ACK — sent by standby to primary after applying a WAL catch-up
* entry (Task 3.1, ha-wal-replication). Must be declared before xce_reply_t
* so the walackreplymsg union arm compiles correctly. */
typedef struct {
uint64_t term;
uint64_t lsn;
int success;
} wal_ack_reply_t;
typedef struct {
uint64_t seq;
uint32_t opcode;
@ -208,6 +219,7 @@ typedef struct {
ctrl_hello_reply_t* ctrlhelloreplymsg;
request_vote_reply_t* requestvotereplymsg;
state_report_t* state_report;
wal_ack_reply_t* walackreplymsg;
} data;
/* Req 7: standby redirect fields — populated when status == XCE_ERR_STANDBY */
char *redirect_host;
@ -244,8 +256,8 @@ typedef struct {
heartbeat_msg_t* heartbeatmsg;
ctrl_hello_req_t* ctrlhellomsg;
request_vote_req_t* requestvotemsg;
void* walcatchupentrymsg; /* wal_catchup_entry_t* */
void* snapshottransfermsg; /* snapshot_transfer_t* */
wal_catchup_entry_t* walcatchupentrymsg;
snapshot_transfer_t* snapshottransfermsg;
} body;
} xce_request_t;
@ -269,34 +281,43 @@ typedef struct {
uint64_t lsn;
} wal_ack_req_t;
typedef struct {
uint64_t term;
uint64_t lsn;
int success;
} wal_ack_reply_t;
typedef struct {
uint64_t term;
uint64_t acked_tag;
int success;
} upgrade_config_ack_t;
typedef struct {
struct snapshot_transfer_s {
uint64_t snapshot_lsn; /* checkpoint LSN this snapshot corresponds to */
xce_data_t *payload; /* chunk payload (64 KB max) */
xce_data_t *payload; /* legacy decoded field — broken for raw bytes
* (decode_Data_ptr misinterprets List(UInt8));
* kept NULL on send, do not use */
uint32_t chunk_index; /* 0-based chunk number */
uint64_t chunk_offset; /* byte offset in the full snapshot */
uint64_t total_size; /* total snapshot size in bytes */
int is_last; /* true (non-zero) for the final chunk */
} snapshot_transfer_t;
/* Raw chunk bytes — same pattern as repl_config_push_req_t.
* Send side: filled by the sender, encoded by xce_snapshot_chunk_req_raw.
* Receive side: extracted by xce_decode() before capn_free(); malloc'd,
* owned by the struct, freed by xce_free_request(). */
uint8_t *raw_payload;
size_t raw_payload_len;
};
typedef struct wal_catchup_entry {
struct wal_catchup_entry {
uint64_t lsn;
uint8_t entry_type;
xce_data_t *payload;
xce_data_t *payload; /* legacy decoded field — broken for
* raw bytes; kept NULL, do not use */
int n_entries; /* batch: number of sub-entries */
struct wal_catchup_entry **entries; /* batch: array of sub-entry pointers */
} wal_catchup_entry_t;
/* Raw WAL entry payload bytes — same pattern as repl_config_push_req_t.
* Send side: filled from the WAL segment file, encoded per sub-entry by
* xce_wal_batch_req_raw. Receive side: extracted by xce_decode() before
* capn_free(); malloc'd, owned, freed by xce_free_request(). */
uint8_t *raw_payload;
size_t raw_payload_len;
};
/* ── Persistence Cap'n Proto mapped types (P0-9) ─────────────────────
* These are the C-side counterparts for the capnp encode/decode shims.