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:
parent
d39500ba48
commit
a166ecb45b
9 changed files with 842 additions and 5 deletions
64
src/controller/testsuite/walcompare.h
Normal file
64
src/controller/testsuite/walcompare.h
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
#pragma once
|
||||
/*
|
||||
* walcompare.h — cross-member WAL committed-prefix divergence detector
|
||||
* (ha-term-safety R6.1/R6.2/R6.3).
|
||||
*
|
||||
* Reuses the canonical waldump.c WAL decoder (via waldump_path_visit) to index
|
||||
* each member's log by `(lsn -> term, pcrc)`, then asserts that every member's
|
||||
* COMMITTED prefix is identical by `(term, pcrc)` — not merely by LSN range.
|
||||
*
|
||||
* The decisive signal for bug-851: two members can report the same committed
|
||||
* LSN over a contiguous, CRC-intact WAL yet hold DIFFERENT entries at the same
|
||||
* LSN (same lsn, different term and/or payload). Comparing LSN ranges alone
|
||||
* masks that; comparing `(term, pcrc)` per LSN surfaces it (R6.2).
|
||||
*
|
||||
* Strictly read-only — opens member WAL dirs O_RDONLY, mutates nothing. Safe to
|
||||
* run against a live cluster's data dirs.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* A single member's WAL source and its committed boundary. */
|
||||
typedef struct {
|
||||
const char* path; /* WAL dir / data dir / seg-*.wal (waldump rules) */
|
||||
uint64_t committed_lsn; /* highest committed LSN for this member; 0 =
|
||||
* "derive" (use the shared boundary, see below) */
|
||||
} walcompare_member_t;
|
||||
|
||||
/* Identity of the first divergent entry, filled on a WALCMP_DIVERGENT result. */
|
||||
typedef struct {
|
||||
uint64_t lsn; /* the diverging LSN within the committed prefix */
|
||||
int n_members; /* members compared at this LSN */
|
||||
uint64_t member_term[16]; /* per-member matched term at lsn */
|
||||
uint32_t member_pcrc[16]; /* per-member payload CRC at lsn */
|
||||
int member_present[16]; /* 1 if the member holds this LSN, else 0 */
|
||||
} walcompare_divergence_t;
|
||||
|
||||
/* Result codes. */
|
||||
enum {
|
||||
WALCMP_OK = 0, /* all members' committed prefixes are identical */
|
||||
WALCMP_DIVERGENT = 1, /* a committed-prefix divergence was found */
|
||||
/* negative values are -errno (a load/usage error: missing WAL, bad args) */
|
||||
};
|
||||
|
||||
/* Compare `n` members' committed WAL prefixes by `(lsn -> term, pcrc)`.
|
||||
*
|
||||
* Committed boundary: each member with `committed_lsn == 0` adopts the SHARED
|
||||
* boundary = the minimum recovered tip (highest CRC-intact LSN) across all
|
||||
* members, i.e. the largest prefix every member can be expected to hold. A
|
||||
* member with an explicit `committed_lsn` uses that. An LSN in `[1..boundary]`
|
||||
* is compared only against the members whose own boundary covers it; a member
|
||||
* that is legitimately AHEAD (longer log) or behind the shared boundary is not
|
||||
* flagged for the uncommitted tail it doesn't share (R6.1 is the committed
|
||||
* prefix, not the full log).
|
||||
*
|
||||
* Legacy-zero term (R1.8) is mapped to WAL_LEGACY_TERM for matching, so two
|
||||
* pre-feature entries are not spuriously divergent.
|
||||
*
|
||||
* On the FIRST divergent LSN, fills `*div` (when non-NULL) and prints a report
|
||||
* to `out`, then returns WALCMP_DIVERGENT. Returns WALCMP_OK on identical
|
||||
* committed prefixes, or a negative errno on a load/usage error. `out` may be
|
||||
* NULL to suppress the report.
|
||||
*/
|
||||
int walcompare(const walcompare_member_t* members, int n, FILE* out,
|
||||
walcompare_divergence_t* div);
|
||||
Loading…
Add table
Add a link
Reference in a new issue