Repository navigation
test: catalog work is counted in the measured statement's own transaction, not the shared view (#1298) - #1388
Conversation
…tion, not the shared view (#1298) catalog_delete_index and catalog_plan_index compare catalog buffer counts a few buffers apart, and read them from pg_statio_all_tables. That view is shared: another session's reads reach it whenever that session flushes or exits, and pg_stat_force_next_flush() flushes only the caller's own counts. Measured on PG18 with a second session scanning the catalogs during one compaction: the shared reading rose by 28 to 120 buffers, the transaction's own reading by -3 to +18. Noise on the reference side of a comparison lets a regression pass. The readings now come from pg_stat_get_xact_blocks_fetched (and, in the pytest twin, pg_stat_get_xact_numscans), taken before and after the measured statements in one transaction. lib.sh gains pgc_xact_blocks for the shell suites. The vacuum reading stays on the shared view, because VACUUM cannot run in a transaction block. Each suite gains an arm, red first in both twins: a statement that reads no catalog, inside which a second session (run by COPY ... TO PROGRAM) scans the catalogs and exits, must read zero. With the old helpers it read 31 and 10 buffers in the shell, and 4 and 2 in pytest. A control beside it shows the second session's reads do reach the shared view. The comparative arms still catch what they guard: with the size check removed, all seven comparative arms in catalog_delete_index fail in both twins (the small drop arm reads 0 against its floor of 100), and with the written-limit lookup scanning pgcolumnar.storage sequentially, the storage arms fail (newest 9 blocks against oldest 4). Ledger: four rows, two dated; 1893 -> 1895 never. cluster_tests 538 -> 540. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019VvWuX1zUwk6Y513waRd4N
0b6a6eb to
879305d
Compare
OffgridwithJD
left a comment
There was a problem hiding this comment.
Approved at 879305d, with full CI green.
I checked the one thing that could make the new reading measure less than the old. The reading is taken before the transaction commits, so catalog work deferred to pre-commit would drop out. pgcolumnar_xact_callback does run PgColumnarExtentPreCommit there, with extent_recompute_storage for storages whose groups went, which is what a compaction does. Measured on PG17 against this head: the same compaction read in-transaction (your helper) and after commit through the shared view, on a quiet cluster, three pairs:
| pair | in-transaction | after commit |
|---|---|---|
| 1 | 86 (delete_vector 81, row_group 5) | 86 |
| 2 | 89 | 88 |
| 3 | 91 | 88 |
Nothing in CATS is left for pre-commit, so the conversion loses no work. The drop's catalog cleanup runs in the drop hook, synchronously.
Reproduced (PG18): with the size check removed (pgcolumnar_scan_index_oid always probes), all seven comparative arms fail in the shell, from P1 … got [12] want [100] to the drop's default … got [-23]. pytest fails P1, the vacuum arm and the drop. Clean on PG15 and PG19 (CI covers 17/18): catalog_delete_index 36/36, catalog_plan_index 29/29, both pytest files 10 passed.
Nit, not blocking: the body says cluster_tests 538 → 540, but the branch is on f601281 and says 541 (539 + 2), which is right.
🤖 Generated with Claude Code
Closes #1298. For @OffgridwithJD to review. This is the plan posted on #1298, with one change: native_fetch_coalesce needs no conversion (see below).
The problem
catalog_delete_index and catalog_plan_index compare catalog buffer counts that are a few buffers apart. Examples: the small drop's 24 vs 27, and the storage arm's single block. Both read the counts from
pg_statio_all_tables. That view is shared across sessions, so noise on the reference side of a comparison lets a regression pass.Measured on PG18, one
compact()of a 40-group table per reading. Each pair has the same catalog size, and in the noisy run a second session scans the catalogs:(All six pairs are on #1298.)
The change
pg_stat_get_xact_blocks_fetched, before and after the measured statements, in one transaction. Nothing is flushed while a transaction is open, so the difference is the statements' own work. Pending counts from the fixture's writes cancel out, and other sessions can't reach the reading.pgc_xact_blocksinlib.sh, used bycat_blocks(compaction, drop),stor_blocksandplan_work._cat_blocksand_xact_work, with the storage scan counts frompg_stat_get_xact_numscans.cat_detailprints the breakdown of the same reading, so it always adds up to the total.seq_scan = 0arms keep their shared-view reading, as agreed on Planning-buffer counts wobbled in CI and the cause was never found: audit the other arms that count buffers #1298.Evidence
Red first, in both twins, both suites. The new arm measures a statement that reads no catalog. Inside it, a second session started by
COPY (SELECT 1) TO PROGRAM 'psql …'scans the catalogs and exits. The reading must be 0.got [31] want [0]got 4 want 0got [10] want [0]got 2 want 0A control beside each arm shows the second session's reads do reach the shared view.
Green:
The comparative arms still catch what they guard, under the new reading:
pgcolumnar_scan_index_oidalways probes): all seven comparative arms fail in the shell. The small drop givesgot [0] want [100]. pytest fails P1, the vacuum arm and the drop.pgcolumnar.storagesequentially (Every planned query scans pgcolumnar.storage twice; relation_oid has no index #1210 reverted):FAIL the newest columnar table costs no more catalog work than the oldest: got [-3] want [1](newest 9 blocks, oldest 4). pytest fails the seq-scan arm (newest 6, oldest 2).storage_pkeythrough the size check. That isn't the written-limit path, and the arms rightly stayed green.native_fetch_coalesce: no conversion. Its reading is
EXPLAIN (ANALYZE, BUFFERS), backend-local and warmed. Over 20 readings, 10 quiet and 10 with another session scanning the same table and the catalogs, the narrow fetch read 77 every time and the wide one 77 (once 79). Its failure is 15 pins over a 3-pin bound.Counts:
cluster_tests538 → 540 by collection.Conflicts: this collides with ci: the nightly's coverage job installs pg_partman, hll and tdigest (#1382) #1385 and test: the row-identity lock and its two settings, in both twins (#1341) #1368 on the budget and
cluster_tests. Whichever lands later restates.🤖 Generated with Claude Code
https://claude.ai/code/session_019VvWuX1zUwk6Y513waRd4N