On Tue, 8 Sept 2026 at 10:54, Zhijie Hou (Fujitsu) <[email protected]> wrote: > > > On Monday, September 7, 2026 8:56 PM vignesh C <[email protected]> wrote: > > > > The underlying issue appears to be that publication DDL naming a table takes > > ShareUpdateExclusiveLock, which does not conflict with the > > RowExclusiveLock held by a concurrent UPDATE. This allows the publication > > definition to change while the UPDATE is in progress: the UPDATE uses the > > old > > definition when checking the operation and generating WAL, while logical > > decoding uses the new definition. > > Thanks for reporting the issue. > > > > > There may be other variations of this race ex: adding column list, but the > > underlying problem is the same: an UPDATE can proceed based on stale > > publication information and produce a logical replication change that is > > rejected only later on the subscriber. > > > > I fixed the issue by changing the lock taken by publication DDL from > > ShareUpdateExclusiveLock to ShareRowExclusiveLock. This makes the DDL > > conflict with the RowExclusiveLock held by concurrent data-modifying > > statements, preventing the publication definition from changing while the > > UPDATE is in progress. > > I think this fix is not sufficient, as it does not address the ALTER > PUBLICATION > SET (options) cases, where the publication action can also be altered > concurrently with DMLs, IIUC. The publication data in the relcache is also > affected by pubaction changes, so those should be blocked as well. > > Addressing the above should be sufficient for the row filter and column list > cases. However, for the replica identity check on UPDATE and DELETE > operations, > further analysis may be needed - especially for the TABLES IN SCHEMA and ALL > TABLES cases, where tables are not explicitly published.
One approach could be: For "TABLES IN SCHEMA", lock the schema's namespace OID. LockSchemaList() already takes a lock on the schema to prevent DROP SCHEMA, so upgrade it from AccessShareLock to ShareRowExclusiveLock. This keeps the existing protection and also prevents concurrent writers from racing with CREATE PUBLICATION ... FOR TABLES IN SCHEMA and ALTER PUBLICATION ... ADD/SET TABLES IN SCHEMA. For "FOR ALL TABLES", lock the pg_publication relation with ShareRowExclusiveLock. Take this lock in CreatePublication() when enabling FOR ALL TABLES, and in AlterPublicationAllFlags() when changing puballtables from false to true. On the DML side(UPDATE and DELETE), CheckCmdReplicaIdentity() takes a matching RowExclusiveLock on the table's namespace and pg_publication before using the publication descriptor. This is needed only for tables without a local replica identity; tables with a replica identity or REPLICA IDENTITY FULL are not affected by this race. RowExclusiveLock is self-compatible, so normal concurrent DML does not block other DML. It conflicts with the ShareRowExclusiveLock taken by the publication DDL, ensuring that the DDL and DML cannot race. The attached POC demonstrates the changes for the same. Does this approach look reasonable, or is there a better way to handle this synchronization? Regards, Vignesh
Concurrent_publication_Replica_identity_check_issue.patch
Description: Binary data
