forked from lei.chen/myxce
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
|
|
@ -1,6 +1,7 @@
|
|||
#include <argp.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <inttypes.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -22,6 +23,7 @@
|
|||
#include "delay.h"
|
||||
#include "idgen.h"
|
||||
#include "preason.h"
|
||||
#include "walcompare.h" /* cross-member committed-prefix divergence (cmd_walcompare) */
|
||||
#include "waldump.h" /* offline WAL inspector (cmd_waldump) */
|
||||
#include "xce/cluster.h" /* xce_parse_peers, xce_cluster_config_t */
|
||||
#include "xce/types.h"
|
||||
|
|
@ -124,6 +126,7 @@ extern int cmd_expect_job(int, char*[]);
|
|||
extern int cmd_wait_primary(int, char*[]);
|
||||
extern int cmd_ctrlstatus(int, char*[]);
|
||||
extern int cmd_waldump(int, char*[]);
|
||||
extern int cmd_walcompare(int, char*[]);
|
||||
static int worker_house_keeping(void*);
|
||||
|
||||
/* Session verdict / loop state (xce-test-e2e-primitives task 1.1).
|
||||
|
|
@ -182,6 +185,7 @@ static command_t top_commands[] = {
|
|||
{ "set", cmd_set, "Show/Set settings" },
|
||||
{ "echo", cmd_echo, "Print a message" },
|
||||
{ "waldump", cmd_waldump, "Inspect WAL segments" },
|
||||
{ "walcompare", cmd_walcompare, "Diff member committed WAL prefixes" },
|
||||
{ "quit", cmd_quit, "Quit xce test" },
|
||||
{ (char*)NULL, (cmd_func_t)NULL, (char*)NULL }
|
||||
};
|
||||
|
|
@ -220,6 +224,7 @@ static command_t client_commands[] = {
|
|||
"wait until a primary serves [timeout_ms]" },
|
||||
{ "ctrlstatus", cmd_ctrlstatus, "show controller/cluster status" },
|
||||
{ "waldump", cmd_waldump, "Inspect WAL segments" },
|
||||
{ "walcompare", cmd_walcompare, "Diff member committed WAL prefixes" },
|
||||
{ "shutdown", cmd_shutdown, "shutdown xce controller" },
|
||||
{ "jobrun", cmd_jobrun, "run a job" },
|
||||
{ "jobsub", cmd_jobsub, "submit a job" },
|
||||
|
|
@ -716,6 +721,69 @@ 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
|
||||
* 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. */
|
||||
int cmd_walcompare(int argc, char* argv[])
|
||||
{
|
||||
uint64_t committed = 0; /* 0 = derive the shared boundary */
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
int n = argc - ai;
|
||||
if (n < 2) {
|
||||
fprintf(stderr,
|
||||
"usage: walcompare [--committed N] <memberA> <memberB> "
|
||||
"[more...]\n");
|
||||
return -1;
|
||||
}
|
||||
if (n > 16) {
|
||||
fprintf(stderr, "walcompare: at most 16 members\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
walcompare_member_t members[16];
|
||||
for (int i = 0; i < n; i++) {
|
||||
members[i].path = argv[ai + i];
|
||||
members[i].committed_lsn = committed; /* 0 => derive shared boundary */
|
||||
}
|
||||
|
||||
walcompare_divergence_t div;
|
||||
int rc = walcompare(members, n, stdout, &div);
|
||||
if (rc == WALCMP_OK)
|
||||
return 0;
|
||||
if (rc == WALCMP_DIVERGENT) {
|
||||
fprintf(stderr,
|
||||
"walcompare: FAIL — committed-prefix divergence at LSN %" PRIu64
|
||||
"\n",
|
||||
div.lsn);
|
||||
return -1; /* nonzero session verdict */
|
||||
}
|
||||
fprintf(stderr, "walcompare: error: %s\n", strerror(-rc));
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cmd_up(int argc, char* argv[])
|
||||
{
|
||||
if (active_ctx->parent != NULL) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue