Skip to content

[PG18] Do not read the catalog in is_age_extension_exists() outside a live transaction (backport of #2581) - #2600

Open
ld-873233 wants to merge 1 commit into
apache:PG18from
ld-873233:pg18-backport-2581
Open

ld-873233 wants to merge 1 commit into
apache:PG18from
ld-873233:pg18-backport-2581

Conversation

@ld-873233

Copy link
Copy Markdown

Backport of #2581 (fixes #2580) to PG18.

#2581 is merged on master, but PostgreSQL 18 users run AGE from PG18 (newest tag PG18/v1.8.0-rc0, the
apache/age:release_PG18_1.8.0 image), which does not carry it. On those servers the failure described in #2580 leaves
PostgreSQL refusing new connections in every database (FATAL: failed to re-find shared lock object) until it restarts.

The change is #2581's commit, cherry-picked with -x (06ce678). It applies cleanly to
PG18 (one file, +9; only the line offset differs). access/xact.h is already included in ag_catalog.c on this branch.

Tested on PostgreSQL 18.6 (18.6-1.pgdg13+2, stock postgres:18.6-trixie), AGE built from source as in
installcheck.yaml (make COPT=-Werror install):

PG18 head (e43dc1a) this branch
build with COPT=-Werror ok ok
make installcheck EXTRA_TESTS="pgvector fuzzystrmatch pg_trgm" 45 of 45 passed 45 of 45 passed
reproduction (below), 90 s 99 ROLLBACKs failed with ResourceOwnerEnlarge called after release started, then FATAL: failed to re-find shared lock object and the client could not reconnect 4,157 statements stopped, every ROLLBACK succeeded, 30 of 30 new connections afterwards; the server logged only the statement timeouts

Reproduction (a different shape from #2580's, same mechanism): AGE NOT in shared_preload_libraries; two sessions run
LOAD 'age', then loop BEGIN; SET LOCAL statement_timeout = '40ms'; SELECT * FROM cypher(...) with a variable-length
match ([:L*1..6], 1,000 vertices, 4,000 edges) that the timeout stops, then ROLLBACK. A third session in another
database loops plain CREATE TABLE / CREATE INDEX / DROP TABLE (no AGE involved), which resets the other sessions'
caches.

Controls from the same series on PG18 head (release_PG18_1.8.0 image unless noted; the plain-DDL loop above unless
noted), 60-90 s each:

  • AGE loaded is required: a plain-SQL sort stopped by temp_file_limit failed its ROLLBACK 98 of 138 times with AGE
    preloaded, and 0 of 1,058 times on stock PostgreSQL 18.6 without AGE.
  • not every failure triggers it: a trivial error (SELECT 1/0, AGE preloaded) failed 0 of 197,155 ROLLBACKs, and
    successful reads followed by ROLLBACK 0 of 121,317 (that run's DDL loop was create_graph / drop_graph).
  • a session-level LOAD 'age' is enough: with AGE NOT preloaded, 98 of 112 failed — so leaving it out of
    shared_preload_libraries does not avoid the failure.

…ransaction (apache#2581)

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 2580.

Co-authored-by: Konstantin Serikov <constse@gmail.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
(cherry picked from commit 06ce678)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants