Repository navigation
Fix the CI test flakes of K22 and the three of 2026-10-29 - #32
Merged
Merged
Conversation
Product (obop-storage, schema.rs and pg_hist.rs): a process that waited for the schema advisory lock looked at a catalogue cache older than the commit of the process before it, found the history part missing and ran its DDL again, which could deadlock (40P01) with obop_history_ensure_partition. schema::take_lock now reads pg_class once the lock is held. Tests: random 16 byte canary in backup_cli; bounded wait for the pool gauges and a 10 s bound for /readyz in pool.rs; bounded warm-up in the read-lane test; connections held until released and no wall-clock bounds in the lock pool test; kill_sessions waits for the server and a longer acquire window in the connection kill tests; each test port handed out once per binary and a server that exited is noticed in multi_process.rs and pool.rs. K22 in docs/ISSUES.md says which are fixed and what is left. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Product change (read this first)
crates/kernel/obop-storage/src/schema.rsandpg_hist.rschange product code. Release note: PostgreSQL: several server processes that start at the same time and first need the change-history tables no longer fail with a deadlock (SQLSTATE 40P01) while creating them.Everything else in this PR is tests, test helpers and docs/ISSUES.md (K22).
The flakes: cause, fix, numbers
"Before" and "after" are the same test run N times from a saved binary of the old and the new code (debug build, PostgreSQL 17 in
obop-pgand PostgreSQL 18 in a private container,--test-threads=1per run, several runs side by side). "Load" means that many busyyesprocesses on the 32-thread machine.pg_hist_tests::processes_that_need_the_part_together_make_it_once(40P01)schema::with_locktakes the schema advisory lock afterBEGIN. A process that waited for it asked the catalogue (to_regclass,to_regprocedure) from negative cache entries older than the commit of the process before it (advisory locks do not refresh the catalogue cache), so the history part looked missing; it ran the whole DDL again. ItsCREATE INDEX IF NOT EXISTStakes ShareLock on the history tables in the opposite order toobop_history_ensure_partition(the lock of a batch that writes history), and the two deadlock. Several server processes starting together can hit this on the first tracked write;install_on_demandthen backs off and refuses the write.schema::take_lock: lock, thenSELECT 1 FROM pg_catalog.pg_class LIMIT 0so the check sees what the previous process made.pg_hist::Import::flushuses it too. New regression testa_process_that_waited_for_the_schema_lock_sees_what_the_one_before_it_made(the maker holds the lock while the waiter queues; fails 3 of 3 on the old code, passes on the new).backup_cli::a_key_in_the_environment_makes_the_backup_sealed_and_restore_needs_itada(3 bytes) occurs by chance in the hex of the plain header (backup id, key id, nonce prefix, wrapped key).canary-<hex>); the control test with a plain backup uses the same canary and still fails the scan (200 of 200 runs).pool::an_exhausted_pool_answers_503_with_retry_after_never_a_401_and_the_server_recovers(in_use1 not 0)metrics_whenpolls every 50 ms, at most 30 s, untilin_useandwaitingread 0, and shows the last metrics at the deadline. A leaked connection still fails. Thein_usereading itself did not recur locally; the run showed a second flake in the same test: the/readyzbound of exactly 3 s is the product's ownREADY_TIMEOUT, and the answer came at 3.0016 s; the bound is now 10 s (a hanging probe still fails)./readyzbound)seams_tests::read_tx_takes_a_normal_connection_and_not_a_place_in_the_long_read_lanetime_budget(60)) until the three exist.pg_pool_tests::the_lock_pool_does_not_take_interactive_capacity_and_the_other_way_roundpg_sleep(2)and the test asserted 1 s and 2 s wall-clock bounds, an unboundedwhile in_use < 2.pg_pool_tests::a_connection_killed_by_the_server_is_noticed_and_replaced(andonly_a_statement_on_a_connection_that_broke_is_in_flight, same helper)pg_terminate_backend; replacement of the dead connection inside the default 2 s acquire window.kill_sessionswaits (bounded) untilpg_stat_activityshows no session; acquire window 30 s in these tests.multi_process::a_session_started_on_one_process_works_on_the_other_and_data_is_shared(401, once on CI)free_porthands each port out once per binary (multi_process.rs,pool.rs); the start-up loop panics with the log if the server exited. 15 runs of the whole binary pass.Method notes: flake 1 was reproduced first under unfixed code (12 % on PG17), and the mechanism was shown with a probe (BEGIN, wait for the lock while another session commits the DDL, then
to_regclassis stale; with thepg_classread it is fresh). No fix is a longer sleep or a retry of the test.Not fixed (and why)
obop-authbefore calling it a flake.obop_history_ensure_partitionof another process;ensure_schemahas no retry for 40P01 (a batch has one);require()checks a part outside the schema lock and can be briefly stale (it heals on the next call).Gates (run on this head)
cargo fmt --check: clean.cargo clippy --workspace --all-targets -- -D warnings: clean.cargo test --workspacewithout PostgreSQL: 2081 passed, 0 failed, 6 ignored (68 test binaries).cargo test --workspacewithOBOP_TEST_POSTGRES_URL(PostgreSQL 18): 2081 passed, 0 failed, 6 ignored.K22 in
docs/ISSUES.mdnow says which are fixed (with cause) and what is left; no change todocs/DECISIONS.md.🤖 Generated with Claude Code