forked from lei.chen/myxce
feat(ha-entity-snapshots): track in-flight snapshot transfer LSN per peer (task 4.1)
Adds snapshot_inflight_lsn[MAX_HA_CANDIDATES] to ha_state_t, alongside the existing snapshot_inflight[] flag it mirrors exactly: set to the checkpoint's LSN at ha_snapshot_send_dispatch before a transfer's first byte goes out, cleared to 0 at every completion/failure path (snapshot_lane_fn's normal completion, and all 3 early-return failure sites: malloc failure, slowlane dedup-refuse, slowlane submit failure). This is the foundation task 4.3 will consult from rotate_snapshots to avoid deleting a checkpoint file a peer is still mid-transfer reading from -- the one genuinely new retention guard this feature needs (the existing write_snapshot-before-trim_wal_segments sequencing already satisfies the WAL-trim side of Requirement 3). Proven via a new gated unit test (test_ha_liveness.c) that observes the tracked LSN mid-flight while the send body is parked at a test gate, not just before/after -- confirms the lifecycle ordering, not just the endpoints. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JDYFbrgyDHbvNYcxApKhrX
This commit is contained in:
parent
eac7bb8ad8
commit
8d1ee8b761
4 changed files with 108 additions and 3 deletions
|
|
@ -1969,6 +1969,68 @@ static void test_snapshot_offload_dedups_per_peer(void)
|
|||
printf("test_snapshot_offload_dedups_per_peer: PASS\n");
|
||||
}
|
||||
|
||||
/* ───────────────────────────────────────────────────────────────────────
|
||||
* ha-entity-snapshots Task 4.1 (Req 3.1-3.3): the in-flight-LSN tracking
|
||||
* array must be set to the checkpoint's position BEFORE a transfer's first
|
||||
* byte goes out, and cleared once the transfer completes -- proven with the
|
||||
* same gate mechanism the dedup test above uses to observe the tracker
|
||||
* mid-flight (parked), not just before/after.
|
||||
* ─────────────────────────────────────────────────────────────────────── */
|
||||
static void test_snapshot_inflight_lsn_set_before_send_cleared_after(void)
|
||||
{
|
||||
cluster_t c;
|
||||
memset(&c, 0, sizeof(c));
|
||||
ha_init(&c.ha, &g_cfg, 0);
|
||||
TEST_ASSERT_EQUAL_INT(0, slowlane_init(&c.slowlane, 2, 4));
|
||||
c.persist.checkpoint_lsn = 42;
|
||||
|
||||
endpoint_t ep;
|
||||
memset(&ep, 0, sizeof(ep));
|
||||
|
||||
snap_reset_probe();
|
||||
atomic_store(&g_snap_gate_on, 1); /* lane body parks at the gate */
|
||||
ha_repl_send_snapshot_hook = snap_probe;
|
||||
ha_set_snapshot_offload_for_test(1);
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT64_MESSAGE(0,
|
||||
atomic_load_explicit(&c.ha.snapshot_inflight_lsn[0], memory_order_acquire),
|
||||
"Req 3.1-3.3: no transfer in flight yet -- tracked LSN must be unset");
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, snap_dispatch_once(&c, &ep, 0));
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(0, snap_wait_parked(2000),
|
||||
"the snapshot body must reach the gate (running on the lane)");
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT64_MESSAGE(42,
|
||||
atomic_load_explicit(&c.ha.snapshot_inflight_lsn[0], memory_order_acquire),
|
||||
"Req 3.1-3.3: while the transfer is in flight (parked before its "
|
||||
"first byte is released), the tracked LSN must equal the checkpoint "
|
||||
"position this transfer references");
|
||||
|
||||
snap_release_gate();
|
||||
TEST_ASSERT_EQUAL_INT_MESSAGE(1, snap_wait_runs(1, 2000),
|
||||
"the parked snapshot body must complete after release");
|
||||
|
||||
/* Bounded poll: snapshot_lane_fn clears the LSN then the flag after the
|
||||
* send body returns -- give it a moment to finish its own cleanup. */
|
||||
uint64_t cleared = 1;
|
||||
for (int i = 0; i < 2000; i++) {
|
||||
cleared = atomic_load_explicit(&c.ha.snapshot_inflight_lsn[0],
|
||||
memory_order_acquire);
|
||||
if (cleared == 0) break;
|
||||
struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000L };
|
||||
nanosleep(&ts, NULL);
|
||||
}
|
||||
TEST_ASSERT_EQUAL_UINT64_MESSAGE(0, cleared,
|
||||
"Req 3.1-3.3: once the transfer completes, the tracked LSN must be "
|
||||
"cleared so rotate_snapshots never sees a stale in-flight LSN");
|
||||
|
||||
ha_set_snapshot_offload_for_test(0); /* restore production default (OFF) */
|
||||
ha_repl_send_snapshot_hook = NULL;
|
||||
slowlane_fini(&c.slowlane);
|
||||
ha_fini(&c.ha);
|
||||
printf("test_snapshot_inflight_lsn_set_before_send_cleared_after: PASS\n");
|
||||
}
|
||||
|
||||
/* ───────────────────────────────────────────────────────────────────────
|
||||
* Task 3.3 — requester-less ConfigPush slow-lane offload (Req 1.1, 1.5; bug-1198).
|
||||
*
|
||||
|
|
@ -2214,6 +2276,8 @@ void test_ha_liveness(void)
|
|||
RUN_TEST(test_snapshot_offload_runs_on_lane);
|
||||
RUN_TEST(test_snapshot_inline_when_flag_off);
|
||||
RUN_TEST(test_snapshot_offload_dedups_per_peer);
|
||||
/* ha-entity-snapshots Task 4.1 — in-flight snapshot LSN tracking (Req 3.1-3.3) */
|
||||
RUN_TEST(test_snapshot_inflight_lsn_set_before_send_cleared_after);
|
||||
/* raft-drive-async Task 3.3 — requester-less ConfigPush slow-lane offload (Req 1.1, 1.5, 6.x) */
|
||||
RUN_TEST(test_configpush_offload_runs_on_lane);
|
||||
RUN_TEST(test_configpush_inline_when_flag_off);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue