feat(ha-repl-hardening): primary snapshot chunk sender (task 3.5a)
ha_send_snapshot_to_standby reads snapshot file, splits into 64KB chunks, sends each via OPCode_snapshotTransfer with correct metadata (snapshotLsn, chunkIndex, chunkOffset, totalSize, isLast). Payload encoding deferred. Hook seam for unit testing. 2 tests: 128KB/2-chunks, small-file/1-chunk. Tasks 3.5b-3.5d remain.
This commit is contained in:
parent
6b69a47c50
commit
834ab4d5e7
5 changed files with 241 additions and 11 deletions
|
|
@ -1504,6 +1504,110 @@ static void test_wal_stream_empty_range_no_batches(void)
|
|||
printf("test_wal_stream_empty_range_no_batches: PASS\n");
|
||||
}
|
||||
|
||||
/* ── Task 3.5: Snapshot chunk transfer ──────────────────────── */
|
||||
|
||||
static snapshot_transfer_t g_snaptest_chunks[16];
|
||||
static int g_snaptest_chunk_count = 0;
|
||||
|
||||
static void snaptest_reset(void)
|
||||
{
|
||||
memset(g_snaptest_chunks, 0, sizeof(g_snaptest_chunks));
|
||||
g_snaptest_chunk_count = 0;
|
||||
}
|
||||
|
||||
static int snaptest_hook(endpoint_t *ep, xce_request_t *req)
|
||||
{
|
||||
(void)ep;
|
||||
if (g_snaptest_chunk_count >= 16) return -1;
|
||||
memcpy(&g_snaptest_chunks[g_snaptest_chunk_count],
|
||||
req->body.snapshottransfermsg, sizeof(snapshot_transfer_t));
|
||||
g_snaptest_chunk_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_snapshot_transfer_two_chunks(void)
|
||||
{
|
||||
char tmpdir[] = "/tmp/xcectest_snaptrans_XXXXXX";
|
||||
TEST_ASSERT_NOT_NULL(mkdtemp(tmpdir));
|
||||
|
||||
char snap_path[512];
|
||||
snprintf(snap_path, sizeof(snap_path), "%s/snap-0000000000000064.capnp", tmpdir);
|
||||
FILE *f = fopen(snap_path, "wb");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
char header[16] = "XCESNAP\0";
|
||||
uint64_t lsn = 100;
|
||||
memcpy(header + 8, &lsn, 8);
|
||||
fwrite(header, 1, 16, f);
|
||||
char zero[4096];
|
||||
memset(zero, 0, sizeof(zero));
|
||||
for (int i = 16; i < 131072; i += 4096)
|
||||
fwrite(zero, 1, (i + 4096 > 131072) ? (size_t)(131072 - i) : 4096, f);
|
||||
fclose(f);
|
||||
|
||||
extern int (*xce_snapshot_chunk_hook)(endpoint_t *, xce_request_t *);
|
||||
xce_snapshot_chunk_hook = snaptest_hook;
|
||||
snaptest_reset();
|
||||
|
||||
extern int ha_send_snapshot_to_standby(endpoint_t *, const char *, uint64_t, uint64_t);
|
||||
int rc = ha_send_snapshot_to_standby(NULL, tmpdir, lsn, 131072);
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(2, g_snaptest_chunk_count);
|
||||
TEST_ASSERT_EQUAL_UINT64(100, g_snaptest_chunks[0].snapshot_lsn);
|
||||
TEST_ASSERT_EQUAL_UINT32(0, g_snaptest_chunks[0].chunk_index);
|
||||
TEST_ASSERT_EQUAL_UINT64(0, g_snaptest_chunks[0].chunk_offset);
|
||||
TEST_ASSERT_EQUAL_UINT64(131072, g_snaptest_chunks[0].total_size);
|
||||
TEST_ASSERT_EQUAL_INT(0, g_snaptest_chunks[0].is_last);
|
||||
TEST_ASSERT_EQUAL_UINT64(131072, g_snaptest_chunks[1].total_size);
|
||||
TEST_ASSERT_EQUAL_UINT32(1, g_snaptest_chunks[1].chunk_index);
|
||||
TEST_ASSERT_EQUAL_UINT64(65536, g_snaptest_chunks[1].chunk_offset);
|
||||
TEST_ASSERT_EQUAL_INT(1, g_snaptest_chunks[1].is_last);
|
||||
|
||||
xce_snapshot_chunk_hook = NULL;
|
||||
char cmd[512];
|
||||
snprintf(cmd, sizeof(cmd), "rm -rf %s", tmpdir);
|
||||
system(cmd);
|
||||
printf("test_snapshot_transfer_two_chunks: PASS\n");
|
||||
}
|
||||
|
||||
static void test_snapshot_transfer_small_less_than_one_chunk(void)
|
||||
{
|
||||
char tmpdir[] = "/tmp/xcectest_snaptrans_XXXXXX";
|
||||
TEST_ASSERT_NOT_NULL(mkdtemp(tmpdir));
|
||||
|
||||
char snap_path[512];
|
||||
snprintf(snap_path, sizeof(snap_path), "%s/snap-000000000000000a.capnp", tmpdir);
|
||||
FILE *f = fopen(snap_path, "wb");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
char buf[64];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
memcpy(buf, "XCESNAP\0", 8);
|
||||
uint64_t lsn = 10;
|
||||
memcpy(buf + 8, &lsn, 8);
|
||||
fwrite(buf, 1, sizeof(buf), f);
|
||||
fclose(f);
|
||||
|
||||
extern int (*xce_snapshot_chunk_hook)(endpoint_t *, xce_request_t *);
|
||||
xce_snapshot_chunk_hook = snaptest_hook;
|
||||
snaptest_reset();
|
||||
|
||||
extern int ha_send_snapshot_to_standby(endpoint_t *, const char *, uint64_t, uint64_t);
|
||||
int rc = ha_send_snapshot_to_standby(NULL, tmpdir, lsn, 64);
|
||||
TEST_ASSERT_EQUAL_INT(0, rc);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(1, g_snaptest_chunk_count);
|
||||
TEST_ASSERT_EQUAL_UINT64(10, g_snaptest_chunks[0].snapshot_lsn);
|
||||
TEST_ASSERT_EQUAL_UINT32(0, g_snaptest_chunks[0].chunk_index);
|
||||
TEST_ASSERT_EQUAL_UINT64(64, g_snaptest_chunks[0].total_size);
|
||||
TEST_ASSERT_EQUAL_INT(1, g_snaptest_chunks[0].is_last);
|
||||
|
||||
xce_snapshot_chunk_hook = NULL;
|
||||
char cmd[512];
|
||||
snprintf(cmd, sizeof(cmd), "rm -rf %s", tmpdir);
|
||||
system(cmd);
|
||||
printf("test_snapshot_transfer_small_less_than_one_chunk: PASS\n");
|
||||
}
|
||||
|
||||
#endif /* XCE_TESTING */
|
||||
|
||||
/* ── dispatch ───────────────────────────────────── */
|
||||
|
|
@ -1548,6 +1652,9 @@ void test_config_repl(void)
|
|||
RUN_TEST(test_wal_stream_500_entries_two_batches);
|
||||
RUN_TEST(test_wal_stream_partial_batch);
|
||||
RUN_TEST(test_wal_stream_empty_range_no_batches);
|
||||
/* Task 3.5: snapshot chunk transfer */
|
||||
RUN_TEST(test_snapshot_transfer_two_chunks);
|
||||
RUN_TEST(test_snapshot_transfer_small_less_than_one_chunk);
|
||||
#endif
|
||||
/* Task A: raw capnp shims */
|
||||
RUN_TEST(test_replconfig_req_ssl_encode);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue