test(config-upgrade-snapshot): prove WAL-trim safety + add fault-injection seam for marker trigger
Confirmed task 5's existing 6 tests already satisfy "exactly once", "safe under forced retry", and "does not re-home entities"; confirmed test_snapshot_recv_old_format_version_rejected_fail_loud (task 1) already covers format-mismatch rejection by proxy through load_snapshot's two shared callers (network-install, boot replay). Adds the two genuine gaps: (1) test_marker_triggered_checkpoint_trim_preserves_standby_mid_catchup_segments proves trim_wal_segments/repl_trim_lsn's standby-cursor retention guard (bug-1147) still holds when reached via the new marker-triggered checkpoint path, not just the old periodic/direct-call path -- guard itself untouched. (2) persist_marker_checkpoint_fault_hook (#ifdef XCE_TESTING, NULL default, true no-op in production) gates whether persist_checkpoint_marker_triggered runs, for task 8.7's later crash-before-checkpoint-durable injection; minimally proven here. Task 8.1 of 19. Requirements: 1.1, 1.5, 1.8, 5.2, 5.3, 5.6, 5.7, 6.3, 7.3, 7.4
This commit is contained in:
parent
41af05402d
commit
4aeae6e282
3 changed files with 291 additions and 2 deletions
|
|
@ -3369,6 +3369,33 @@ int apply_wal_entry(persist_t* p, uint32_t type, uint64_t lsn,
|
|||
* SYNCHRONOUSLY on this exact call stack, from this exact function. */
|
||||
static _Thread_local bool t_apply_seam_notifying = false;
|
||||
|
||||
#ifdef XCE_TESTING
|
||||
/* config-upgrade-snapshot task 8.1 (Req 6.3): deterministic fault-injection
|
||||
* seam at the marker-apply-to-checkpoint-durable boundary, for later use by
|
||||
* a crash/restart regression (task 8.7): "force a controller crash/restart
|
||||
* between a configuration-change marker's commit and that member's own
|
||||
* snapshot write becoming durable, and assert materialization resumes
|
||||
* correctly from the marker on restart." When non-NULL AND it returns
|
||||
* nonzero for the marker's own (p, lsn), the WAL_CONFIG_MARKER case below
|
||||
* skips its call into persist_checkpoint_marker_triggered() entirely --
|
||||
* simulating "the process crashes here, before the checkpoint write becomes
|
||||
* durable" (a real crash simply stops the process; the checkpoint call
|
||||
* never runs either way). The skip is deliberately routed through the SAME
|
||||
* rc!=0 handling an actual checkpoint failure already takes below (not a
|
||||
* new branch): last_applied_lsn is not advanced past this marker, so the
|
||||
* next kick/retry -- or, after a genuine restart, boot replay's independent
|
||||
* call into this same case (already proven idempotent by
|
||||
* test_marker_apply_retry_is_idempotent) -- resumes materialization from
|
||||
* the marker fresh, exactly matching Requirement 5.2's crash-safety
|
||||
* contract. NULL in production -- no behaviour change. Mirrors
|
||||
* ha_stream_body_read_fault_hook's shape (config_repl.c) and this same
|
||||
* spec's own xce_upgrade_marker_committed_hook placement convention
|
||||
* (defined here at file scope, declared extern in whichever test file
|
||||
* needs it -- never in a header). */
|
||||
int (*persist_marker_checkpoint_fault_hook)(persist_t *p,
|
||||
uint64_t marker_lsn) = NULL;
|
||||
#endif
|
||||
|
||||
int apply_committed_entry(persist_t* p, uint32_t wal_type, uint64_t lsn,
|
||||
const void* payload, uint32_t len)
|
||||
{
|
||||
|
|
@ -3780,7 +3807,20 @@ int apply_committed_entry(persist_t* p, uint32_t wal_type, uint64_t lsn,
|
|||
* checkpoint. `lsn` (this function's own parameter) is
|
||||
* already the marker's exact position, so it is passed
|
||||
* through explicitly instead of re-derived. */
|
||||
int rc = persist_checkpoint_marker_triggered(p, lsn);
|
||||
int rc;
|
||||
#ifdef XCE_TESTING
|
||||
if (persist_marker_checkpoint_fault_hook != NULL &&
|
||||
persist_marker_checkpoint_fault_hook(p, lsn)) {
|
||||
/* Simulated crash (task 8.1, Req 6.3): skip the checkpoint call
|
||||
* entirely and fall into the SAME genuine-failure handling below
|
||||
* a real checkpoint I/O error already takes -- see the fault
|
||||
* hook's own doc comment above for why that is the correct,
|
||||
* not merely convenient, simulation of "the process never got
|
||||
* to checkpoint". */
|
||||
rc = -ECANCELED;
|
||||
} else
|
||||
#endif
|
||||
rc = persist_checkpoint_marker_triggered(p, lsn);
|
||||
if (rc == -EBUSY) {
|
||||
/* Expected, self-resolving (Req 4.4/5.3): a concurrent
|
||||
* WAL-threshold-triggered or earlier marker-triggered
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue