feat: P2-1 repl.h/repl.c — replicator lifecycle, slot management, trim_lsn

Add replicator_t structure with per-standby connection slots (standby_conn_t),
lifecycle (repl_init/repl_fini), slot management (repl_add_standby,
repl_remove_standby, repl_expire_disconnect_slots), ACK tracking
(repl_on_ack), WAL trim guard (repl_trim_lsn), and stubs for
repl_broadcast/repl_wait_ack (wired in P2-3/P2-4).

Uses mylock_t (pthread_mutex_t alias) with mylock_lock/mylock_unlock.
snap_interval_s==0 in repl_expire_disconnect_slots forces immediate expiry
to support deterministic unit testing.

5 new Unity tests all pass; 115 pre-existing controller tests unchanged.
This commit is contained in:
Rongsong Shen 2026-05-07 16:25:03 +00:00
parent 05c00704d3
commit 8ef64a7ee7
5 changed files with 397 additions and 0 deletions

View file

@ -23,6 +23,7 @@ extern void test_ha_role(void);
extern void test_ha_cluster(void);
extern void test_ha_redirect(void);
extern void test_p1_integration(void);
extern void test_repl_unit(void);
void setUp(void) { return; }
@ -115,6 +116,7 @@ int main(int argc, char* argv[])
TEST(test_ha_cluster);
TEST(test_ha_redirect);
TEST(test_p1_integration);
TEST(test_repl_unit);
return UNITY_END();
}

View file

@ -0,0 +1,85 @@
#include <assert.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
/* Use the same Unity include pattern as other controller tests */
#include <unity/unity.h>
#include "repl.h"
#include "config.h"
static void test_repl_init_zeroes_nstandbys(void) {
replicator_t r;
TEST_ASSERT_EQUAL_INT(0, repl_init(&r));
TEST_ASSERT_EQUAL_INT(0, r.nstandbys);
repl_fini(&r);
printf("test_repl_init_zeroes_nstandbys: PASS\n");
}
static void test_repl_add_remove_standby(void) {
replicator_t r;
/* Use a dummy int as the endpoint pointer — repl.c only compares ep pointers */
int dummy_ep = 0;
repl_init(&r);
int idx = repl_add_standby(&r, (void*)&dummy_ep, "standby1", 7001);
TEST_ASSERT_TRUE(idx >= 0);
TEST_ASSERT_EQUAL_INT(1, r.nstandbys);
repl_remove_standby(&r, (void*)&dummy_ep);
TEST_ASSERT_EQUAL_INT(0, r.nstandbys);
repl_fini(&r);
printf("test_repl_add_remove_standby: PASS\n");
}
static void test_repl_add_standby_max(void) {
replicator_t r;
int eps[MAX_STANDBYS + 1];
repl_init(&r);
for (int i = 0; i < MAX_STANDBYS; i++) {
int rc = repl_add_standby(&r, (void*)&eps[i], "sb", 7000 + i);
TEST_ASSERT_TRUE(rc >= 0);
}
/* One over limit must fail */
int rc = repl_add_standby(&r, (void*)&eps[MAX_STANDBYS], "sb_extra", 9999);
TEST_ASSERT_TRUE(rc < 0);
repl_fini(&r);
printf("test_repl_add_standby_max: PASS\n");
}
static void test_repl_trim_lsn_no_standbys(void) {
replicator_t r;
repl_init(&r);
uint64_t trim = repl_trim_lsn(&r, 42, 60);
TEST_ASSERT_EQUAL_UINT64(42, trim);
repl_fini(&r);
printf("test_repl_trim_lsn_no_standbys: PASS\n");
}
static void test_repl_trim_lsn_disconnected_slot_expiry(void) {
replicator_t r;
int dummy_ep = 0;
repl_init(&r);
repl_add_standby(&r, (void*)&dummy_ep, "sb", 7001);
repl_on_ack(&r, (void*)&dummy_ep, 10);
repl_remove_standby(&r, (void*)&dummy_ep);
/* Immediately after disconnect: trim guard holds at last_disconnected_lsn=10 */
uint64_t trim = repl_trim_lsn(&r, 50, 60);
TEST_ASSERT_EQUAL_UINT64(10, trim);
/* After expiry (snap_interval_s=0 forces immediate expiry): trim == checkpoint */
repl_expire_disconnect_slots(&r, 999999, 0);
trim = repl_trim_lsn(&r, 50, 0);
TEST_ASSERT_EQUAL_UINT64(50, trim);
repl_fini(&r);
printf("test_repl_trim_lsn_disconnected_slot_expiry: PASS\n");
}
void test_repl_unit(void) {
UNITY_BEGIN();
RUN_TEST(test_repl_init_zeroes_nstandbys);
RUN_TEST(test_repl_add_remove_standby);
RUN_TEST(test_repl_add_standby_max);
RUN_TEST(test_repl_trim_lsn_no_standbys);
RUN_TEST(test_repl_trim_lsn_disconnected_slot_expiry);
UNITY_END();
}