diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c index 0c58ef6d5e5..575b296baaa 100644 --- a/src/backend/commands/publicationcmds.c +++ b/src/backend/commands/publicationcmds.c @@ -2241,11 +2241,21 @@ LockTablesWithoutReplicaIdentity(Form_pg_publication pubform, List *schemas) /* * Serialize with concurrent publication descriptor builds. ShareLock is - * the weakest mode that conflicts with the RowExclusiveLock those take on - * this catalog, and, unlike ShareRowExclusiveLock, it does not needlessly - * serialize concurrent publication DDLs against each other. + * the weakest mode that conflicts with the RowExclusiveLock those take, + * and, unlike ShareRowExclusiveLock, it does not needlessly serialize + * concurrent publication DDLs against each other. + * + * This uses a dedicated LockDatabaseObject() tag on pg_publication + * (keyed by the reserved InvalidOid, which is never a real publication + * OID, so it cannot collide with AlterPublication()'s own per-publication + * lock on this same catalog) rather than LockRelationOid() on the + * catalog's relation lock. Reusing the relation lock would make this + * wait collide with the ordinary RowExclusiveLock every unrelated + * CREATE/ALTER/DROP PUBLICATION already takes to modify its own + * pg_publication row, producing spurious deadlocks between publications + * that share nothing but this catalog. */ - LockRelationOid(PublicationRelationId, ShareLock); + LockDatabaseObject(PublicationRelationId, InvalidOid, 0, ShareLock); } /* diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index da99c3c62bc..3b93f9b0a02 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -5868,11 +5868,15 @@ RelationBuildPublicationDesc(Relation relation, PublicationDesc *pubdesc) /* * Prevent concurrent publication DDL to publish the table lacking replica - * identity (see LockTablesWithoutReplicaIdentity). + * identity (see LockTablesWithoutReplicaIdentity). This uses a dedicated + * LockDatabaseObject() tag on pg_publication, not LockRelationOid() on + * the catalog's relation lock, so that this wait cannot collide with the + * ordinary RowExclusiveLock any unrelated CREATE/ALTER/DROP PUBLICATION + * already takes to modify its own pg_publication row. */ if (!OidIsValid(RelationGetReplicaIndex(relation)) && relation->rd_rel->relreplident != REPLICA_IDENTITY_FULL) - LockRelationOid(PublicationRelationId, RowExclusiveLock); + LockDatabaseObject(PublicationRelationId, InvalidOid, 0, RowExclusiveLock); memset(pubdesc, 0, sizeof(PublicationDesc)); pubdesc->rf_valid_for_update = true;