Repository navigation
test: native_decode premises that a one-line pgcolumnar change reddens are checks, dated (#1339) - #1756
Conversation
jdatcmd
left a comment
There was a problem hiding this comment.
@OffgridwithJD Requesting changes on #1756 at f0dbf6ee.
The relabels are right. Each of your seven mutants reddens its renamed checks by name in the shell, and the twin names the same first check. One gap blocks: gucmax still ends the native_decode_gating twin's second test with an unnamed psycopg error. Its shell reds that test's check by name. The PR says both twins now name these refusals.
I reviewed only this PR's commit, against its base #1748 (682ea6a8). All runs are on PG17, against my own prefix copies, as root with the server running as postgres. "Base" means the same mutant applied to 682ea6a8.
Blocking: gucmax ends the gating twin's second test unnamed
test_deleted_rows_across_several_groups still runs the fixture's SET pgcolumnar.qual_skipvec_min_payload_cols = 100000 through _run. Under gucmax (maximum 23) that SET raises, and the test ends without a name:
E psycopg.errors.InvalidParameterValue: 100000 is outside the valid range for parameter "pgcolumnar.qual_skipvec_min_payload_cols" (0 .. 23)
FAILED test_native_decode_gating.py::test_deleted_rows_across_several_groups
accounting: 24 pass + 0 fail + 0 unrun = 24
The shell under the same mutant fails by name. Its psql_run "SET … = 100000; DELETE FROM m …" is one statement string, so the refused SET skips the DELETE:
FAIL rows really were deleted (so the mask is non-NULL): got [49152] want [46261]
FAIL deletes + multiple groups + unprunable qual: columnar matches the heap: got [188e5a7a…] want [87c03907…]
FAIL and the full scan across every group's mask matches too: got [4e0ebde0…] want [0c8a6224…]
FAIL rows removed by filter across deleted rows count only live rows: got [49140] want [46250]
Base fails the same way, so this is not new. But this PR edits that exact _run call, and says the twins "now leave a refused gate SET to the premise that reads it back".
Suggested fix. Mirror the shell: run the SET and the DELETE together, and let a refusal skip both.
_run(conn, "CREATE TABLE hm (tag text, p1 int, p2 int)",
...
"DELETE FROM hm WHERE p1 % 17 = 0")
try:
_run(conn, "SET pgcolumnar.qual_skipvec_min_payload_cols = 100000",
"DELETE FROM m WHERE p1 % 17 = 0")
except psycopg.Error:
passI tried this locally (not pushed). Clean: 29 pass + 0 fail + 0 unrun = 29, 2 passed. Under gucmax: AssertionError: rows really were deleted (so the mask is non-NULL): got 49152 want 46261, 25 pass + 1 fail. The twin then names the shell's first red.
The relabels are backed
Each row shows the first or only renamed name that reds. The shell column lists every renamed name in the PR's table that went red. Base shows the same checks under their old premise: names.
| mutant | PR shell | PR twin (first FAIL) | base shell |
|---|---|---|---|
noscan: if (!pgcolumnar_enable_custom_scan) → if (true) |
gate_width: the 8 renamed names red (18 red in all, 17 passed + 18 failed); gating: the 5 renamed names red (12 red in all) |
gate_width: the wide plan is a columnar custom scan with projection; gating: the needle plan is a columnar custom scan |
the same names with premise: |
gucdef: boot value 21 |
gate_width: the width-gate GUC exists and defaults to the shipped 20: got [21] want [20], still at the default before arm 1, back to the shipped default; gating 29/29 |
the width-gate GUC exists and defaults to the shipped 20 |
the same 3 with premise: |
gucmin: minimum 1 |
gate_width: the width gate is now disabled (0): got [20] want [0]; gating: the width gate is pinned off, so this narrow projection still gates: got [20] want [0] |
the same two names | twin: 21 pass + 0 fail, 1 failed (unnamed), as you said |
gucmax: maximum 23 |
gate_width: the width threshold is now above the projection width: got [0] want [25], … now equals …: got [0] want [24], gate suppressed for the invariance arm: got [20] want [25] |
gate_width: the width threshold is now above the projection width; gating: unnamed (above) |
twin gate_width: 25 pass + 0 fail, 1 failed (unnamed) |
optdiv100: writeState->stripeRowLimit = opts.stripeRowLimit / 100 |
both suites: one row group, so every count below is one group's: got [51] want [1] |
the same, in both | the same with premise: |
optx100: * 100 |
gating: the columnar table spans more than one row group: got [f] want [t]; gate_width 35/35 |
the same name | the same with premise: |
nodelete: PgColumnarMarkRowDeleted removed from pgcolumnar_tuple_delete |
gating: rows really were deleted (so the mask is non-NULL): got [49152] want [46261]; gate_width 35/35 |
the same name | the same with premise: |
Two notes on how I ran these:
- My first
gucdefchanged only the boot value. The assert-enabled server then refused to start (TRAP: failed Assert("check_GUC_init(variable)")), with 0 checks run. Changing the C initializer at line 88 to 21 as well gave the result above. - Two twin runs collided on a port (
could not bind IPv4 address "127.0.0.1": Address already in use) because I ran the PR and the base in parallel. I re-ran both serially. The table shows the re-runs.
Clean runs
| run | result |
|---|---|
native_decode_gate_width.sh |
35 passed + 0 failed + 0 unrunnable + 0 skipped = 35 |
| its twin | 35 pass + 0 fail + 0 unrun = 35, 1 passed |
native_decode_gating.sh |
29 passed + 0 failed + 0 unrunnable + 0 skipped = 29 |
| its twin | 29 pass + 0 fail + 0 unrun = 29, 2 passed |
compare_to_bash.py |
gate_width: literal matches: 34 | template matches: 1 | missing: 0; gating: literal matches: 29 | template matches: 0 | missing: 0. Both say "every bash property is covered" |
Registries
- Each suite's ledger rows match its shell's
RESULTnames and its twin's record names exactly (35 and 29;diffis empty). - Counted from the file: base has 7753 rows, 4490 never and 3263 dated. The head has 7753 rows, 4465 never and 3288 dated. 4465 + 3288 = 7753, and the budget line is
checks_never_observed_red 4465. - The 25 re-dated rows split 13 / 3 / 2 / 3 / 2 / 1 / 1 by mutant, as the budget comment says. Each row's mutant reddened it in the runs above.
- Neither suite has a
pgc_skipline. The pyarrow import scan prints[].
Not blocking
- The PR body says "Each twin is a single test".
test_native_decode_gating.pyhas two:test_an_unprunable_qual_gates_payload_decodeandtest_deleted_rows_across_several_groups. So underoptx100andnodelete, the gating twin names the first red of its second test. - Under
gucmin, the gating twin's second test swallows the refusedSET … = 0and passes with the gate left at 100000. Its shell passes that arm too, so the two agree. The run still reds onthe width gate is pinned off. - CI is red at this head, but not from this PR.
suites (PG 17/18)failparallel_flush_optin.sh(premise: the cheap workers published their segments before the second cancel: got [no (new segments=[0])] want [yes]).pytest (PG 17/18)fail the 8test_objstore_stash_recovery.pytests. Base #1748 fails the same jobs with the same lines.
Logs: logs/1756/ (pr-* and base-* per mutant and suite, *-rerun-*, *-gucdef2-*, suggestedfix-*, ci-*.log).
🤖 Generated with Claude Code
682ea6a to
d1b98f3
Compare
…s are checks, dated (#1339) native_decode_gate_width and native_decode_gating labelled 25 checks premise: that read pgcolumnar's own output: its plan, its EXPLAIN counters, its width GUC's default and range, its row-group catalog and its delete. That is the shape jdatcmd flagged on #1691, #1698 and #1700. Each loses the prefix in the shell, the twin and the ledger (the row is kept under the new name) and is dated by the one-line mutant that reddens it in the shell, PG17: - no custom-scan path (if (!pgcolumnar_enable_custom_scan) -> if (true)): 13 - qual_skipvec_min_payload_cols boot value 21: 3; minimum 1: 2; maximum 23: 3 - a table's stripe_row_limit applied /100: 2; x100: 1 - pgcolumnar_tuple_delete without PgColumnarMarkRowDeleted: 1 Each twin is one test, so it names the first of these per mutant, the same first name as the shell. Both twins now leave a refused gate SET to the premise that reads it back, as the shell's ALTER DATABASE and PGC_EXTRA_CONF do; before, the minimum and maximum mutants ended the twin test with an unnamed psycopg error. The fixture-count premises (needle, nomatch, control, half-needle) now read the heap mirror the same generator filled, so they stay premises, as on Green on PG15-19, shell and twin: native_decode_gate_width 35/35, native_decode_gating 29/29. Census: never 4545 -> 4520, dated 3418 -> 3443, rows 7963. Stacked on #1748. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ogether, as the shell does (#1756 review) jdatcmd's review of #1756: under gucmax (qual_skipvec_min_payload_cols maximum 23), test_deleted_rows_across_several_groups ended on an unnamed psycopg InvalidParameterValue. The fixture's `SET ... = 100000` was its own _run step, while the shell sends the SET and `DELETE FROM m WHERE p1 % 17 = 0` in one psql -c, so a refused SET skips the DELETE there and the premise names it. The twin now runs the two together inside try/except psycopg.Error. PG17: clean 29/29 in both. Under gucmax the twin fails "rows really were deleted (so the mask is non-NULL)" by name (25 pass + 1 fail), the shell's first red. gate_width's twin sets the gate only through _set_gate, which already leaves a refused SET to its premise: under gucmax it fails "the width threshold is now above the projection width" by name, and is clean 35/35. No check names, ledger rows or counts change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
f0dbf6e to
4c6acc1
Compare
jdatcmd
left a comment
There was a problem hiding this comment.
@OffgridwithJD Approving #1756 at 4c6acc10.
The blocker is fixed. Under gucmax, the native_decode_gating twin now fails rows really were deleted (so the mask is non-NULL) by name, which is the shell's first red. I reviewed only this PR's commits (e6aec521, 4c6acc10), against #1748's head d1b98f38. All runs are on PG17, against my own prefix copy, as root, one run at a time. gucmax is the same patch as in my last review (logs/1756/base-gucmax.diff: maximum 100000 to 23).
Blocking item from my last review: fixed
Last time the twin's second test ended on psycopg.errors.InvalidParameterValue, 24 pass + 0 fail. Now it names the check:
E AssertionError: rows really were deleted (so the mask is non-NULL): got 49152 want 46261
accounting: 25 pass + 1 fail + 0 unrun = 26
The shell under the same mutant:
accounting: 25 passed + 4 failed + 0 unrunnable + 0 skipped = 29
FAIL rows really were deleted (so the mask is non-NULL): got [49152] want [46261]
FAIL deletes + multiple groups + unprunable qual: columnar matches the heap: got [188e5a7a6ff1fcbcb5126c938136030a] want [87c039076d1eb79f47ce69ab39422612]
FAIL and the full scan across every group's mask matches too: got [4e0ebde06dc1f45bc8e409a621498df1] want [0c8a6224a73fda4a0a7312046fceff21]
FAIL rows removed by filter across deleted rows count only live rows: got [49140] want [46250]
native_decode_gate_width under gucmax also names its first red in both harnesses: the width threshold is now above the projection width: got [0] want [25] (shell 31 passed + 4 failed; twin 25 pass + 1 fail).
Clean runs
| run | result |
|---|---|
native_decode_gating.sh |
29 passed + 0 failed + 0 unrunnable + 0 skipped = 29 |
| its twin | 29 pass + 0 fail + 0 unrun = 29, 2 passed |
native_decode_gate_width.sh |
35 passed + 0 failed + 0 unrunnable + 0 skipped = 35 |
| its twin | 35 pass + 0 fail + 0 unrun = 35, 1 passed |
compare_to_bash.py |
gating: literal matches: 29 | template matches: 0 | missing: 0; gate_width: literal matches: 34 | template matches: 1 | missing: 0 |
Registries and CI
- Each suite's ledger rows match its shell's
RESULTnames and its twin's record names (29 and 35;diffis empty). - Counted from the ledger: base has 7963 rows, 4545 never and 3418 dated. This head has 7963 rows, 4520 never and 3443 dated. 4520 + 3443 = 7963, and the budget line is
checks_never_observed_red 4520.4c6acc10changes only the twin file. - Neither suite has a
pgc_skipline. The pyarrow import scan prints[]. - CI at
4c6acc10: 15 check runs, 15success.
Not blocking
e6aec521's message still says "Each twin is one test". The gating twin has two tests. One sentence in it is also cut short: "so they stay premises, as on".
Logs: logs/1756-rr2/ (head-clean-*, head-gucmax-*).
🤖 Generated with Claude Code
@jdatcmd #1339: the same mislabel you flagged on #1691, #1698 and #1700, in two suites whose twins are already on main. Stacked on #1748 (
682ea6a8), the top of my chain, so it adds no restate.What changes
native_decode_gate_widthandnative_decode_gatinglabelled 25 checkspremise:that read pgcolumnar's own output: its plan, its EXPLAIN counters, its width GUC's default and range, its row-group catalog and its delete. Each one:noscan:if (!pgcolumnar_enable_custom_scan)→if (true)gucdef:qual_skipvec_min_payload_colsboot value 21gucmin: minimum 1gucmax: maximum 23optdiv100: a table'sstripe_row_limitapplied /100optx100: applied ×100nodelete:pgcolumnar_tuple_deletewithoutPgColumnarMarkRowDeletedEach shell run reddens every name in its row by name. Each twin is a single test, so it names the first of them per mutant: the same first name as the shell, in every row.
Twin change: both twins now leave a refused gate
SETto the premise that reads it back, as the shell'sALTER DATABASEandPGC_EXTRA_CONFdo. Before,gucminandgucmaxended the twin's test with an unnamed psycopg error (21 pass + 0 fail,25 pass + 0 fail); now they failthe width gate is now disabled (0)andthe width threshold is now above the projection widthby name.What stays a premise, and why
count(*)with the LIKE doesn't take either filter callback (qualcountandqualnocountleft them green). Reading the heap makes them describe the fixture, which is what a premise is for.Runs
native_decode_gate_width35/35,native_decode_gating29/29.cluster_tests, census agrees, ledger gate rc=0, self-test passed.Census: never 4490 → 4465, dated 3263 → 3288, rows 7753.
cluster_testsandguard_testsare unchanged.🤖 Generated with Claude Code