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

@ -1008,8 +1008,33 @@ static int ha_apply_single_entry(persist_t *p, wal_catchup_entry_t *e)
return apply_wal_entry(p, &hdr, e->raw_payload);
}
/* ha_send_wal_ack_reply: send WalAckReply {term, lsn, success=1} back to
* the primary over ep. Skipped when ep or c is NULL (test/offline path).
* Task 3.1 (ha-wal-replication): ACK each successfully applied WAL entry. */
static void ha_send_wal_ack_reply(ha_state_t *ha, struct endpoint_t *ep,
cluster_t *c, uint64_t lsn)
{
if (!ep || !c)
return;
wal_ack_reply_t ack;
ack.term = (uint64_t)atomic_load_explicit(&ha->term, memory_order_acquire);
ack.lsn = lsn;
ack.success = 1;
xce_reply_t reply;
memset(&reply, 0, sizeof(reply));
reply.opcode = OPCode_walAck;
reply.status = 0;
reply.data_which = RequestReply_data_walackreplymsg;
reply.data.walackreplymsg = &ack;
xce_reply(ep, c->myhost, &reply);
}
int ha_apply_wal_catchup_entry(ha_state_t *ha, persist_t *p,
wal_catchup_entry_t *entry)
wal_catchup_entry_t *entry,
struct endpoint_t *ep, cluster_t *c)
{
if (!ha || !p || !entry)
return -EINVAL;
@ -1037,9 +1062,13 @@ int ha_apply_wal_catchup_entry(ha_state_t *ha, persist_t *p,
"for batch index %d lsn=%" PRIu64 " type=%u rc=%d "
"— skipping entry",
i, sub->lsn, (unsigned)sub->entry_type, rc);
/* Task 3.2: no ACK for failed entries */
continue;
}
/* Task 3.1: ACK each successfully applied sub-entry */
ha_send_wal_ack_reply(ha, ep, c, sub->lsn);
last_good_lsn = sub->lsn;
had_good = 1;
}
@ -1058,12 +1087,16 @@ int ha_apply_wal_catchup_entry(ha_state_t *ha, persist_t *p,
ERROR("ha_apply_wal_catchup_entry: apply_wal_entry failed for "
"lsn=%" PRIu64 " type=%u rc=%d — skipping entry",
entry->lsn, (unsigned)entry->entry_type, rc);
/* Task 3.2: no ACK on apply failure */
return rc;
}
/* Advance applied_lsn atomically (lsn+1 mirrors persist->current_lsn
* after a successful apply). */
ha_advance_applied_lsn(ha, entry->lsn + 1);
/* Task 3.1: ACK the successfully applied single entry */
ha_send_wal_ack_reply(ha, ep, c, entry->lsn);
return 0;
}