fix(controller): stop a failed test from hanging the unit suite (bug-1429); mkstemp for upgrade temp file (bug-1861)

A failing TEST_ASSERT longjmps out and skips the fixture teardown, leaving
the commit engine's sweep thread and persist's fsync_worker asleep on a
static struct. The next test re-inits it underneath them, corrupting the
condvar, and a later teardown blocks in pthread_cond_destroy/join until
the 300s meson timeout. The failure line itself was lost because stdout
was fully buffered.

- controller_test: line-buffer stdout; tearDown() reaps what a failed test
  leaked via new XCE_TESTING registries (persist_test_reap_unstopped, then
  commit_test_reap_unfinalized_engines -- persist_stop before engine fini).
  Clean run reaps 0; an injected failure now fails in 2s instead of hanging.
- persist: flusher_flush_once reports only its own durable advance, so
  fsync_worker no longer re-fires the durable callback for an advance a
  concurrent persist_flush made (flaky "must not re-fire" test). Regression
  test test_flusher_pass_does_not_claim_concurrent_flush_advance.
- tests: jap observer is atomic and waits (bounded) for a continuation that
  may resolve on the flusher thread; pump catch-up tests wait for trailing
  replies instead of a single scan.
- config_repl: upgrade decode temp file via mkstemp instead of a
  pthread_self()-derived /tmp name (same value across processes, opened
  without O_EXCL -- collisions and a symlink target).

Verified: controller_unit_test 1222/1222; 24 parallel runs (6x4), no
hangs or ASAN errors.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Rongsong Shen 2026-09-25 02:54:09 +00:00
parent 44c1981cff
commit b5d59253e5
Signed by untrusted user: rshen
GPG key ID: 80533536B0EB651C
9 changed files with 316 additions and 23 deletions

View file

@ -1022,6 +1022,21 @@ uint64_t persist_test_durable_lsn_on_disk(persist_t* p);
* Compiled out of production (xce_controller links without it). */
void persist_test_set_force_fsync_fail(persist_t* p, int fail);
/* bug-1429: run one flusher pass (the fsync_worker's flush step) and report
* whether THAT pass advanced durable_lsn -- the worker fires the
* durable-advance callback only on its own advance, never on one a
* concurrent persist_flush() made. Returns the durable watermark. */
uint64_t persist_test_flusher_flush_once(persist_t* p, bool* advanced);
/* bug-1429: persist_stop() every instance persist_start()ed but never
* stopped -- a failed TEST_ASSERT skips the fixture teardown, and the next
* test re-inits the same static persist under its live fsync_worker
* (corrupting fsync_cond; persist_fini then hangs). Called from the test
* runner's tearDown() before commit_test_reap_unfinalized_engines(), the
* documented persist_stop-before-commit_engine_fini order. Stack-local
* instances are skipped. Returns the number stopped. */
int persist_test_reap_unstopped(void);
/* Read the standby-path fdatasync counter (task 2.3, persist-before-ACK
* regression). Counts the inline fdatasync calls made by
* persist_wal_write_replicated. A test snapshots this before the call and