postgres.git / summary / log / commit / refs

commit    e46c2a65710f021e25bc0fcf404dd00c86aec1d7
Author:   Amit Kapila <akapila@postgresql.org>
Date:     Wed Jul 29 04:09:59 2026 +0000

    Avoid accumulating relation locks during sequence synchronization.
    
    While collecting the sequences to synchronize, the sequence sync worker
    opened each INIT sequence with RowExclusiveLock and held it until the
    transaction committed. With many such sequences, this could exhaust the
    shared lock table and fail with "out of shared memory".
    
    The worker only reads each sequence's identity (namespace and name) here
    and needs it to stay stable while read, for which AccessShareLock is
    enough, as it conflicts with the AccessExclusiveLock taken by DROP,
    RENAME, and SET SCHEMA. Take that lock instead and release it as soon as
    the identity is read. The later synchronization re-opens each sequence, so
    it does not rely on the lock being retained.
    
    Reported-by: Noah Misch <noah@leadboat.com>
    Author: vignesh C <vignesh21@gmail.com>
    Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com>
    Reviewed-by: Amit Kapila <amit.kapila16@gmail.com>
    Backpatch-through: 19, where it was introduced
    Discussion: https://postgr.es/m/20260710045217.f0.noahmisch@microsoft.com


src/backend/replication/logical/sequencesync.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/backend/replication/logical/sequencesync.c b/src/backend/replication/logical/sequencesync.c index 40f0f1c6973..bd74a17d28b 100644 --- a/src/backend/replication/logical/sequencesync.c +++ b/src/backend/replication/logical/sequencesync.c @@ -752,7 +752,16 @@ LogicalRepSyncSequences(void) subrel = (Form_pg_subscription_rel) GETSTRUCT(tup); - sequence_rel = try_table_open(subrel->srrelid, RowExclusiveLock); + /* + * Lock the sequence so its identity (namespace and name) cannot + * change under us via a concurrent DROP, RENAME or SET SCHEMA. The + * lock is released immediately rathen than at the transaction end. + * The later synchronization does not depend on this captured identity + * remaining valid, as it re-opens the sequence and tolerates + * concurrent changes. Releasing early also avoids holding one lock + * per sequence, which could exhaust the lock table. + */ + sequence_rel = try_table_open(subrel->srrelid, AccessShareLock); /* Skip if sequence was dropped concurrently */ if (!sequence_rel) @@ -761,7 +770,7 @@ LogicalRepSyncSequences(void) /* Skip if the relation is not a sequence */ if (sequence_rel->rd_rel->relkind != RELKIND_SEQUENCE) { - table_close(sequence_rel, NoLock); + table_close(sequence_rel, AccessShareLock); continue; } @@ -779,7 +788,7 @@ LogicalRepSyncSequences(void) MemoryContextSwitchTo(oldctx); - table_close(sequence_rel, NoLock); + table_close(sequence_rel, AccessShareLock); } /* Cleanup */ [parent: 9740c68ff7aa]