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

@ -32,12 +32,12 @@
#include "xce/cluster_def.h"
#ifdef XCE_TESTING
/* Declared in cluster.c under #ifdef XCE_TESTING — test seam for
* ha_apply_wal_catchup_entry: applies a single WAL catch-up entry to
* persistent storage and advances ha->applied_lsn on success.
* On error: logs ERROR, returns non-zero, does not crash. */
/* Declared in ha.h — test seam for ha_apply_wal_catchup_entry.
* ep and c are passed as NULL in unit tests (ACK path is skipped when
* either is NULL — Task 3.1, ha-wal-replication). */
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);
#endif
/* Per-test directory helpers — not Unity setUp/tearDown (those are in
@ -974,7 +974,7 @@ static void test_wal_catchup_entry_advances_applied_lsn(void)
entry.entries = NULL;
/* GREEN will implement ha_apply_wal_catchup_entry() */
int rc = ha_apply_wal_catchup_entry(&ha, p, &entry);
int rc = ha_apply_wal_catchup_entry(&ha, p, &entry, NULL, NULL);
TEST_ASSERT_EQUAL_INT(0, rc);
/* applied_lsn must advance to lsn+1 = 43 (mirrors persist->current_lsn) */
TEST_ASSERT_EQUAL_UINT64(43,
@ -1014,7 +1014,7 @@ static void test_wal_catchup_entry_error_skipped_no_crash(void)
entry.entries = NULL;
/* Handler must NOT crash; must log ERROR; applied_lsn must remain at 10 */
int rc = ha_apply_wal_catchup_entry(&ha, /*persist=*/NULL, &entry);
int rc = ha_apply_wal_catchup_entry(&ha, /*persist=*/NULL, &entry, NULL, NULL);
/* rc is non-zero (error propagated from apply_wal_entry(-EINVAL)) */
TEST_ASSERT_TRUE(rc != 0);
/* applied_lsn must not advance on failure */
@ -1038,7 +1038,7 @@ static void test_wal_catchup_entry_null_entry_no_crash(void)
ha_init(&ha, &cfg, 0);
/* NULL entry — must not crash, must return error */
int rc = ha_apply_wal_catchup_entry(&ha, NULL, NULL);
int rc = ha_apply_wal_catchup_entry(&ha, NULL, NULL, NULL, NULL);
TEST_ASSERT_TRUE(rc != 0);
ha_fini(&ha);
@ -1084,7 +1084,7 @@ static void test_wal_catchup_batch_advances_applied_lsn(void)
outer.n_entries = 3;
outer.entries = batch_entries;
int rc = ha_apply_wal_catchup_entry(&ha, p, &outer);
int rc = ha_apply_wal_catchup_entry(&ha, p, &outer, NULL, NULL);
TEST_ASSERT_EQUAL_INT(0, rc);
/* applied_lsn must advance to last_entry->lsn + 1 = 13 */
@ -1132,7 +1132,7 @@ static void test_wal_catchup_partial_batch(void)
outer.n_entries = 2;
outer.entries = batch_entries;
int rc = ha_apply_wal_catchup_entry(&ha, p, &outer);
int rc = ha_apply_wal_catchup_entry(&ha, p, &outer, NULL, NULL);
TEST_ASSERT_EQUAL_INT(0, rc);
/* applied_lsn must advance to 21+1=22 */
@ -1182,7 +1182,7 @@ static void test_wal_catchup_batch_error_entry_skipped(void)
outer.entries = batch_entries;
/* Handler must not crash; applied_lsn advances for successful entries */
int rc = ha_apply_wal_catchup_entry(&ha, p, &outer);
int rc = ha_apply_wal_catchup_entry(&ha, p, &outer, NULL, NULL);
/* Overall rc == 0: outer batch call succeeds even with inner skips */
TEST_ASSERT_EQUAL_INT(0, rc);
@ -1223,7 +1223,7 @@ static void test_wal_catchup_batch_zero_entries_fallback(void)
entry.n_entries = 0;
entry.entries = NULL;
int rc = ha_apply_wal_catchup_entry(&ha, p, &entry);
int rc = ha_apply_wal_catchup_entry(&ha, p, &entry, NULL, NULL);
TEST_ASSERT_EQUAL_INT(0, rc);
/* Single-entry path: applied_lsn = 50+1 = 51 */
TEST_ASSERT_EQUAL_UINT64(51,
@ -1281,7 +1281,7 @@ static void test_wal_catchup_batch_256_entries(void)
TEST_ASSERT_EQUAL_UINT64(0,
(uint64_t)atomic_load_explicit(&ha.applied_lsn, memory_order_acquire));
int rc = ha_apply_wal_catchup_entry(&ha, p, &outer);
int rc = ha_apply_wal_catchup_entry(&ha, p, &outer, NULL, NULL);
TEST_ASSERT_EQUAL_INT(0, rc);
/* applied_lsn must advance to last_entry->lsn + 1 = 1000+255+1 = 1256 */
@ -1343,7 +1343,7 @@ static void test_wal_catchup_batch_applied_lsn_only_after_full_batch(void)
outer.n_entries = 4;
outer.entries = ptrs;
int rc = ha_apply_wal_catchup_entry(&ha, p, &outer);
int rc = ha_apply_wal_catchup_entry(&ha, p, &outer, NULL, NULL);
TEST_ASSERT_EQUAL_INT(0, rc);
/* applied_lsn must be exactly 204 (203+1) — the post-batch value.