forked from lei.chen/myxce
docs(ha-commit-durability): pin boot-policy decision table + pending skeleton tests (task 3.2)
This commit is contained in:
parent
dd4d70863b
commit
6483ee8afd
3 changed files with 511 additions and 1 deletions
|
|
@ -990,6 +990,135 @@ static void test_recover_verdict_snapshot_sentinel_clean(void)
|
|||
printf("test_recover_verdict_snapshot_sentinel_clean: PASS\n");
|
||||
}
|
||||
|
||||
/* ================================================================== *
|
||||
* task 3.2 — Boot Policy Decision Table (DECISION ONLY) *
|
||||
* *
|
||||
* Task 3.2 pins the fail-loud-vs-fence boot policy as a DECISION and *
|
||||
* encodes it as a table of input states -> expected outcome. It makes *
|
||||
* NO production behavior change: the FATAL branch is implemented by *
|
||||
* task 3.3 and the promotion fence + release by task 4.3. *
|
||||
* *
|
||||
* The decision table lives in design.md ("Boot Policy Decision Table *
|
||||
* (task 3.2)"). The skeletons below mirror it ONE TEST PER ROW. Each *
|
||||
* skeleton documents the row's inputs + the expected outcome it WILL *
|
||||
* assert once 3.3/4.3 land, then TEST_IGNORE_MESSAGE()-skips so the *
|
||||
* row is REGISTERED and reported as IGNORED (not failed) — the suite *
|
||||
* stays GREEN. These become the RED tests 3.3/4.3 turn GREEN. *
|
||||
* *
|
||||
* Inputs (boot / promotion-eligibility evaluation): *
|
||||
* verdict : CLEAN | TRUNCATED (from task 3.1) *
|
||||
* durable-vs-HWM : at/above | below (durable position) *
|
||||
* healthy peer : yes | no (catch-up source) *
|
||||
* catch-up : succeeds | fails (bounded window) *
|
||||
* Outcomes: *
|
||||
* ELIGIBLE | FENCE+CATCH-UP -> ELIGIBLE | FATAL *
|
||||
* INVARIANT: never a silent indefinite fence — a truncated/behind *
|
||||
* member either catches up (-> eligible) or FATALs on a BOUNDED *
|
||||
* failure. (Req 2.2, 2.4) *
|
||||
* ------------------------------------------------------------------ */
|
||||
|
||||
/* Row 1: CLEAN + durable at/above HWM -> ELIGIBLE.
|
||||
* A structurally intact log that is not behind the cluster boundary is
|
||||
* a normal promotable member: the promotion gate (4.3) must NOT fence
|
||||
* it. WILL ASSERT (4.3): the eligibility predicate returns "eligible"
|
||||
* for a CLEAN, at/above member; promotion proceeds. (Req 2.3) */
|
||||
static void test_boot_policy_row1_clean_at_or_above_eligible(void)
|
||||
{
|
||||
TEST_IGNORE_MESSAGE(
|
||||
"row 1 (CLEAN + at/above HWM -> ELIGIBLE): pending task 4.3 "
|
||||
"(promotion-eligibility gate). Will assert the gate admits a clean, "
|
||||
"not-behind member.");
|
||||
}
|
||||
|
||||
/* Row 2: CLEAN + durable below HWM + healthy peer + catch-up succeeds
|
||||
* -> FENCE+CATCH-UP -> ELIGIBLE.
|
||||
* Intact but behind: must NOT lead below the boundary; fence, catch up
|
||||
* from a healthy peer, regain eligibility. WILL ASSERT (4.3): a
|
||||
* below-HWM member is denied promotion until catch-up passes the last
|
||||
* committed boundary, then regains eligibility. (Req 2.2, 2.3, 2.6) */
|
||||
static void test_boot_policy_row2_clean_below_peer_catchup_eligible(void)
|
||||
{
|
||||
TEST_IGNORE_MESSAGE(
|
||||
"row 2 (CLEAN + below HWM + peer + catch-up ok -> FENCE+CATCH-UP -> "
|
||||
"ELIGIBLE): pending task 4.3 (fence + release). Will assert denied "
|
||||
"until caught up, then re-eligible.");
|
||||
}
|
||||
|
||||
/* Row 3: TRUNCATED + healthy peer + catch-up succeeds
|
||||
* -> FENCE+CATCH-UP -> ELIGIBLE.
|
||||
* Structurally truncated (task-3.1 verdict) but a healthy peer exists:
|
||||
* fence, catch up, regain eligibility — NEVER FATAL when a peer is
|
||||
* reachable. WILL ASSERT (4.3): a recovery_truncated member is denied
|
||||
* promotion, catches up from the peer, and is re-enabled; FATAL is NOT
|
||||
* triggered. (Req 2.2, 2.6) */
|
||||
static void test_boot_policy_row3_truncated_peer_catchup_eligible(void)
|
||||
{
|
||||
TEST_IGNORE_MESSAGE(
|
||||
"row 3 (TRUNCATED + peer + catch-up ok -> FENCE+CATCH-UP -> "
|
||||
"ELIGIBLE): pending tasks 3.3/4.3. Will assert truncated member "
|
||||
"fences, catches up, re-eligible; no FATAL when a peer is reachable.");
|
||||
}
|
||||
|
||||
/* Row 4: TRUNCATED + below HWM + NO healthy peer + catch-up fails
|
||||
* (bounded window elapses) -> FATAL.
|
||||
* Cannot recover locally AND cannot catch up within the bounded window:
|
||||
* fail loud rather than serve divergent state. WILL ASSERT (3.3): the
|
||||
* member terminates loudly (FATAL) with the truncation boundary logged
|
||||
* when the bounded catch-up window elapses without a committed-consistent
|
||||
* state. (Req 2.4) */
|
||||
static void test_boot_policy_row4_truncated_no_peer_bounded_fatal(void)
|
||||
{
|
||||
TEST_IGNORE_MESSAGE(
|
||||
"row 4 (TRUNCATED + below + no peer + bounded catch-up fails -> "
|
||||
"FATAL): pending task 3.3 (FATAL branch). Will assert loud "
|
||||
"termination with the truncation boundary logged on bounded failure.");
|
||||
}
|
||||
|
||||
/* Row 4b: CLEAN + below HWM + NO healthy peer + catch-up fails (bounded
|
||||
* window elapses) -> FATAL.
|
||||
* Behind the HWM with no peer to advance from within the bounded window:
|
||||
* same bounded-failure terminal as row 4 — never a silent indefinite
|
||||
* fence. WILL ASSERT (3.3): a behind member with no reachable peer FATALs
|
||||
* once the bounded window elapses. (Req 2.4, 2.2) */
|
||||
static void test_boot_policy_row4b_clean_below_no_peer_bounded_fatal(void)
|
||||
{
|
||||
TEST_IGNORE_MESSAGE(
|
||||
"row 4b (CLEAN + below + no peer + bounded catch-up fails -> FATAL): "
|
||||
"pending task 3.3. Will assert the behind-no-peer member FATALs on "
|
||||
"bounded failure — never a silent indefinite fence.");
|
||||
}
|
||||
|
||||
/* Row 5: CLEAN snapshot-sentinel (committed at sentinel LSN, NO
|
||||
* sub-sentinel entries) + below + healthy peer + catch-up succeeds
|
||||
* -> FENCE+CATCH-UP -> ELIGIBLE.
|
||||
* A legitimate sentinel snapshot is CLEAN-but-behind, NOT corruption:
|
||||
* treat as must-catch-up, NEVER FATAL on a legitimate sentinel. WILL
|
||||
* ASSERT (4.3): a snapshot-sentinel member is fenced+caught-up like any
|
||||
* behind member and is NEVER routed to the FATAL branch. (Req 2.1, 2.2)
|
||||
* (3.1 already verifies the verdict itself is CLEAN — see
|
||||
* test_recover_verdict_snapshot_sentinel_clean; this row pins the
|
||||
* downstream promotion-fence outcome.) */
|
||||
static void test_boot_policy_row5_snapshot_sentinel_catchup_never_fatal(void)
|
||||
{
|
||||
TEST_IGNORE_MESSAGE(
|
||||
"row 5 (snapshot-sentinel CLEAN + below + peer -> FENCE+CATCH-UP -> "
|
||||
"ELIGIBLE, NEVER FATAL): pending task 4.3. Will assert a legitimate "
|
||||
"sentinel snapshot is treated as behind-must-catch-up, not FATAL.");
|
||||
}
|
||||
|
||||
/* Row 6: CLEAN empty first-boot WAL (durable=0, HWM=0, fresh cold start)
|
||||
* -> ELIGIBLE.
|
||||
* An empty first-boot WAL is not behind anything — cold-start members
|
||||
* are promotable. WILL ASSERT (4.3): the eligibility gate admits a
|
||||
* fresh cold-start member (no fence, no FATAL). (Req 2.1, 2.3) */
|
||||
static void test_boot_policy_row6_empty_first_boot_eligible(void)
|
||||
{
|
||||
TEST_IGNORE_MESSAGE(
|
||||
"row 6 (empty first-boot WAL CLEAN, durable=0/HWM=0 -> ELIGIBLE): "
|
||||
"pending task 4.3. Will assert a fresh cold-start member is "
|
||||
"promotable (no fence, no FATAL).");
|
||||
}
|
||||
|
||||
#endif /* XCE_TESTING */
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
|
@ -1016,6 +1145,16 @@ void test_commit_durability(void)
|
|||
RUN_TEST(test_recover_verdict_empty_first_boot_clean);
|
||||
RUN_TEST(test_recover_verdict_crc_break_first_entry_truncated);
|
||||
RUN_TEST(test_recover_verdict_snapshot_sentinel_clean);
|
||||
/* task 3.2 — Boot Policy Decision Table skeletons (IGNORED, pending
|
||||
* 3.3/4.3). Registered so each row is reported as IGNORED, not failed;
|
||||
* the suite stays GREEN. See design.md "Boot Policy Decision Table". */
|
||||
RUN_TEST(test_boot_policy_row1_clean_at_or_above_eligible);
|
||||
RUN_TEST(test_boot_policy_row2_clean_below_peer_catchup_eligible);
|
||||
RUN_TEST(test_boot_policy_row3_truncated_peer_catchup_eligible);
|
||||
RUN_TEST(test_boot_policy_row4_truncated_no_peer_bounded_fatal);
|
||||
RUN_TEST(test_boot_policy_row4b_clean_below_no_peer_bounded_fatal);
|
||||
RUN_TEST(test_boot_policy_row5_snapshot_sentinel_catchup_never_fatal);
|
||||
RUN_TEST(test_boot_policy_row6_empty_first_boot_eligible);
|
||||
#else
|
||||
printf("test_commit_durability: skipped (no XCE_TESTING)\n");
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue