test(ha-term-safety): cross-member walcompare divergence tool (task 5.3)

Diffs member WALs by (lsn -> term, pcrc) over the committed prefix, exits non-zero
on any committed-prefix divergence with the diverging LSN + per-member entry
identities. Reuses the canonical waldump decoder via a new per-entry visitor seam
(no second WAL parser). Detects same-LSN/diff-term and same-LSN/diff-content
divergences (the bug-851 class) that an LSN-range check would mask.
This commit is contained in:
Rongsong Shen 2026-06-22 13:05:23 +00:00
parent d39500ba48
commit a166ecb45b
9 changed files with 842 additions and 5 deletions

View file

@ -197,7 +197,9 @@ static int collect_segments(const char* wal_dir, uint64_t* seg_lsns, int max)
static void scan_segment(const char* seg_path, FILE* out,
uint32_t* last_crc, uint64_t* prev_lsn,
uint64_t* prev_submit_jobid, uint32_t* prev_submit_pcrc,
waldump_stats_t* st)
waldump_stats_t* st,
waldump_visit_fn visit, void* visit_ctx,
int* visit_stop)
{
int fd = open(seg_path, O_RDONLY);
if (fd < 0) {
@ -282,6 +284,25 @@ static void scan_segment(const char* seg_path, FILE* out,
? crc32(0L, (const Bytef*)payload, hdr.payload_len)
: 0;
/* Surface the CRC-valid entry to the visitor so a caller can index the
* log by (lsn -> term, pcrc) — the single canonical decoder, no second
* parser. */
if (visit) {
waldump_entry_t e = {
.lsn = hdr.lsn,
.term = hdr.term,
.type = hdr.type,
.payload_len = hdr.payload_len,
.pcrc = pcrc,
};
if (visit(visit_ctx, &e) != 0) {
if (visit_stop)
*visit_stop = 1;
free(payload);
break; /* visitor asked to stop */
}
}
/* Per-entry line, with jobid/subtime for submits. */
char info[96] = "";
int is_dup = 0;
@ -347,6 +368,12 @@ static void scan_segment(const char* seg_path, FILE* out,
/* Public entry point */
/* ------------------------------------------------------------------ */
int waldump_path(const char* path, FILE* out, waldump_stats_t* stats)
{
return waldump_path_visit(path, out, stats, NULL, NULL);
}
int waldump_path_visit(const char* path, FILE* out, waldump_stats_t* stats,
waldump_visit_fn visit, void* ctx)
{
if (!path || !out)
return -EINVAL;
@ -417,12 +444,14 @@ int waldump_path(const char* path, FILE* out, waldump_stats_t* stats)
uint64_t prev_lsn = 0;
uint64_t prev_submit_jobid = 0;
uint32_t prev_submit_pcrc = 0;
for (int i = 0; i < nseg; i++) {
int visit_stop = 0;
for (int i = 0; i < nseg && !visit_stop; i++) {
if (single_seg[0] == '\0')
snprintf(seg_path, sizeof(seg_path), WAL_SEG_FMT, wal_dir,
seg_lsns[i]);
scan_segment(seg_path, out, &last_crc, &prev_lsn,
&prev_submit_jobid, &prev_submit_pcrc, &st);
&prev_submit_jobid, &prev_submit_pcrc, &st,
visit, ctx, &visit_stop);
}
fprintf(out, "-- summary --\n");