Pin PostgreSQL 19 parallel autovacuum on a columnar table (#398) - #412
Pin PostgreSQL 19 parallel autovacuum on a columnar table (#398)#412jdatcmd wants to merge 1 commit into
Conversation
The question was whether a table access method participates in 19's parallel autovacuum at all. Measured: the per-table storage parameter autovacuum_parallel_workers is ACCEPTED on a columnar table and lands in pg_class.reloptions exactly as it does on heap, and it has no effect. pgcolumnar_relation_vacuum marks the visibility map and retires fully-deleted row groups. It does no parallel work and never reads the parameter, so a user can set it and nothing happens. It cannot simply be rejected, which was my stated preference on the issue. Storage-parameter validation belongs to PostgreSQL and is driven by relkind rather than by the access method, and pgColumnar has no reloptions hook to refuse it from. Documenting it is the honest option that is actually available. test/pg19_vacuum_options.sh, registered, gated to 19 with a visible skip below it, asserts all of that: the parameter is accepted on both access methods and recorded in reloptions, VACUUM and VACUUM (PARALLEL 2) and pgcolumnar.vacuum all succeed with it set, and rows and content hash are unchanged by any of them. The heap arm is a control rather than decoration. autovacuum_max_parallel_workers defaults to 0 on 19beta2, so without a table where parallel vacuum demonstrably does something, "the parameter does nothing here" cannot be told apart from "parallel autovacuum does nothing on this cluster". The control asserts VACUUM VERBOSE reports on heap while the columnar path is silent, because the AM path is ours. If a future release makes table AMs participate, that check flips and should be rewritten to assert we report workers too. docs/limitations.md says plainly that the parameter is accepted, does nothing, and cannot be refused. Gate: five-major matrix, ALL VERSIONS PASSED, pg19_vacuum_options PASS on all five. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ChronicallyJD
left a comment
There was a problem hiding this comment.
Approved. I checked both of the things you added that I had not established.
The answer matches what I measured, so I spent the review on the two claims that were
yours rather than re-running mine.
"We cannot reject it" holds
$ grep -nE "reloptions|amoptions" access/tableam.h
(nothing)
$ grep -nE "^extern bytea \*.*reloptions" access/reloptions.h
heap_reloptions(char relkind, ...)
view_reloptions(...)
partitioned_table_reloptions(...)
index_reloptions(amoptions_function amoptions, ...)
Index access methods get an amoptions function threaded into validation. Table access
methods get nothing: tableam.h has no reloptions entry point at all, and validation
goes through heap_reloptions(relkind, ...), keyed on relkind as you said.
So rejection needs a core change. Documenting is the honest option available, and I
withdraw the preference I stated on the issue.
The default is 0, and it changes the severity
name | setting | boot_val | source
---------------------------------+---------+----------+---------
autovacuum_max_parallel_workers | 0 | 0 | default
Checked on a cluster where I deliberately did not set it. I missed this, and it
matters: my issue framed a user setting the storage parameter and silently getting
nothing, which reads as a live footgun. With the cluster GUC at 0, parallel autovacuum is
off entirely unless someone opts in, so a user has to take two steps to reach the
confusing state rather than one.
That does not make it a non-issue, since the two-step user is exactly the one who has read
the 19 release notes and is trying to use the feature. But it is a smaller thing than I
implied, and the PR is right to say so.
I set the GUC to 8 in my own run without noting that this was not the default. Worth
recording, because a measurement that quietly configures away the safety margin can
overstate a problem.
The rest
The heap control is the part I would also not drop, for the reason we have both now hit
twice this week: without an arm where the mechanism demonstrably works, a negative is
unreadable. My first attempt at this measurement had one index per table and could not
have launched a worker in either arm, and it looked like a clean result.
docs/limitations.md gains the line, which is where a user will look.
Approving.
Closes #398. @ChronicallyJD for review. No benchmark needed.
The answer
You asked the simple question first: does a table access method participate in 19's
parallel autovacuum, or is it heap-specific? Measured on 19beta2:
ALTER TABLE ... SET (autovacuum_parallel_workers = 3)pg_class.reloptionsVACUUM (VERBOSE)reportsfinished vacuuming ...So it is your state (2), the one you called out as its own defect: the parameter is
settable and silently ignored.
pgcolumnar_relation_vacuummarks the visibility mapand retires fully-deleted row groups. It does no parallel work and never reads the
parameter.
The option I preferred is not available
On the issue I said I would rather reject it than ignore it, because our vacuum is not
the heap's and a parameter that cannot mean what it says should not be settable.
We cannot reject it. Storage-parameter validation belongs to PostgreSQL and is
driven by
relkind, not by the access method, and pgColumnar has no reloptions hook torefuse from. Rejecting would need a core change. So the available honest option is to
document it, which is what this does.
Worth noting
autovacuum_max_parallel_workersdefaults to 0 on 19beta2, soparallel autovacuum is opt-in at the cluster level too. Nobody gets this by accident
today.
The control is the part I would not drop
Without a heap arm, "the parameter does nothing here" cannot be told apart from
"parallel autovacuum does nothing on this cluster", and with the GUC defaulting to 0
the second reading would be true for everyone. The suite asserts
VACUUM VERBOSEreports on heap while the columnar path is silent, because the AM path is ours.
If a future release makes table AMs participate, that check flips, and it should
then be rewritten to assert we report workers too. That is the intended signal, same
shape as the REPACK suite in #409.
Tests
test/pg19_vacuum_options.sh, registered, 19-gated with a visible skip below it(verified on PG18:
SKIP parallel autovacuum requires PostgreSQL 19, exit 0). Twelvechecks: acceptance on both access methods, the reloptions record,
VACUUM,VACUUM (PARALLEL 2)andpgcolumnar.vacuumall succeeding with it set, and rows andcontent hash unchanged by any of them.
Gate
Five-major matrix,
ALL VERSIONS PASSED,pg19_vacuum_options=PASSon all five.docs/limitations.mdsays the parameter is accepted, does nothing, and cannot berefused.
🤖 Generated with Claude Code