test(raft-ha-core-safety): machine-checkable walcompare report (task 1.1)

Per-member (lsn,term,pcrc,present) report + committed-vs-uncommitted
divergence classification via walcompare_report()/--report. Soak signal
(OK/exit-code) preserved. 4 new unit tests, all GREEN.
This commit is contained in:
Rongsong Shen 2026-06-27 04:53:32 +00:00
parent 227f592250
commit b028d25dbd
5 changed files with 453 additions and 120 deletions

View file

@ -721,41 +721,54 @@ int cmd_waldump(int argc, char* argv[])
return rc;
}
/* walcompare [--committed N] <memberA> <memberB> [more...] — diff member WAL
* committed prefixes by (lsn -> term, pcrc) and FAIL (nonzero) on any
/* walcompare [--report] [--committed N] <memberA> <memberB> [more...] — diff
* member WAL committed prefixes by (lsn -> term, pcrc) and FAIL (nonzero) on any
* committed-prefix divergence (ha-term-safety R6.1/R6.2/R6.3), reusing the
* waldump decoder. Each member path may be a seg-*.wal file, a wal/ dir, or a
* node/data dir (same resolution as waldump). With no --committed, the shared
* committed boundary = the minimum CRC-intact tip across members. The diverging
* LSN and per-member (term, pcrc) identities are reported. Exit 0 = identical,
* nonzero = divergence or load error — so it doubles as a scripted assertion. */
* LSN and per-member (term, pcrc) identities are reported. With --report, also
* emit a machine-checkable per-member `(lsn, term, pcrc, status)` table and a
* committed-vs-uncommitted classification for each divergence (task 1.1). Exit
* 0 = identical, nonzero = divergence or load error — so it doubles as a
* scripted assertion. */
int cmd_walcompare(int argc, char* argv[])
{
uint64_t committed = 0; /* 0 = derive the shared boundary */
uint64_t committed = 0; /* 0 = derive the shared boundary */
int report = 0; /* --report => full per-member machine table */
int ai = 1;
/* Optional global committed boundary applied to every member. */
if (argc > ai && strcmp(argv[ai], "--committed") == 0) {
if (argc <= ai + 1) {
fprintf(stderr, "walcompare: --committed needs an LSN\n");
return -1;
/* Optional flags (any order): --report, --committed N. */
for (;;) {
if (argc > ai && strcmp(argv[ai], "--report") == 0) {
report = 1;
ai += 1;
continue;
}
char* end = NULL;
unsigned long v = strtoul(argv[ai + 1], &end, 10);
if (end == argv[ai + 1] || *end != '\0') {
fprintf(stderr, "walcompare: bad --committed LSN '%s'\n",
argv[ai + 1]);
return -1;
if (argc > ai && strcmp(argv[ai], "--committed") == 0) {
if (argc <= ai + 1) {
fprintf(stderr, "walcompare: --committed needs an LSN\n");
return -1;
}
char* end = NULL;
unsigned long v = strtoul(argv[ai + 1], &end, 10);
if (end == argv[ai + 1] || *end != '\0') {
fprintf(stderr, "walcompare: bad --committed LSN '%s'\n",
argv[ai + 1]);
return -1;
}
committed = (uint64_t)v;
ai += 2;
continue;
}
committed = (uint64_t)v;
ai += 2;
break;
}
int n = argc - ai;
if (n < 2) {
fprintf(stderr,
"usage: walcompare [--committed N] <memberA> <memberB> "
"[more...]\n");
"usage: walcompare [--report] [--committed N] <memberA> "
"<memberB> [more...]\n");
return -1;
}
if (n > 16) {
@ -770,7 +783,8 @@ int cmd_walcompare(int argc, char* argv[])
}
walcompare_divergence_t div;
int rc = walcompare(members, n, stdout, &div);
int rc = report ? walcompare_report(members, n, stdout, &div)
: walcompare(members, n, stdout, &div);
if (rc == WALCMP_OK)
return 0;
if (rc == WALCMP_DIVERGENT) {