Skip to content

Do not read the catalog in is_age_extension_exists() outside a live transaction - #2581

Open
SpongeRobert wants to merge 1 commit into
apache:masterfrom
SpongeRobert:fix-extension-check-outside-transaction
Open

SpongeRobert wants to merge 1 commit into
apache:masterfrom
SpongeRobert:fix-extension-check-outside-transaction

Conversation

@SpongeRobert

Copy link
Copy Markdown

Fixes #2580.

With age in shared_preload_libraries, the post_parse_analyze hook runs for the ROLLBACK of a failed transaction too. If the caches of that backend were reset in the meantime, is_age_extension_exists() reads pg_extension (and pg_class) in TBLOCK_ABORT, after the resource owner was released: ResourceOwnerEnlarge called after release started. The locks leak into the PGPROC, and every later backend on it fails at connect with failed to re-find shared lock object until the server restarts. The mechanism, a gdb stack of the failing path and a standalone reproduction are in #2580.

The fix returns false outside a live transaction and caches nothing, so the next live transaction asks the catalog again. In an aborted transaction only the statements that leave it reach the parser, and AGE has nothing to analyse in them.

Verified on PostgreSQL 18.6, master at fa109ef1dd:

No regression test is added: the failure needs a backend held stopped while another session overflows the shared invalidation queue, and then every free PGPROC taken, which pg_regress cannot express. The same change applies cleanly to PG18 (e43dc1a), where it was verified the same way.

🤖 Generated with Claude Code

…ransaction

With age in shared_preload_libraries, post_parse_analyze runs for every
statement, the ROLLBACK of a failed transaction included. When the caches of
that backend were reset (the shared invalidation queue overflowed while it
was not reading), the cached answer of is_age_extension_exists() is gone and
get_extension_oid() misses the catcache: pg_extension and pg_class are opened
in TBLOCK_ABORT, after the resource owner of the transaction was released.
The locks are granted on the fast path and ResourceOwnerEnlarge() then fails
("called after release started"). Nothing releases those locks any more; the
backend exits with them in its PGPROC, and every later backend on that PGPROC
fails at connect with "failed to re-find shared lock object" until the
server restarts. With --enable-cassert the same path trips
Assert(IsTransactionState()) in AssertCouldGetRelation().

Return false outside a live transaction and cache nothing, so the next live
transaction asks the catalog again. Only the statements that leave a failed
transaction reach the parser there, and AGE has nothing to analyse in them.

Fixes apache#2580.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant