Skip to content

Commit 41fb3f5

Browse files
author
Amit Kapila
committed
Fix a deadlock during ALTER SUBSCRIPTION ... DROP PUBLICATION.
A deadlock can occur when the DDL command and the apply worker acquire catalog locks in different orders while dropping replication origins. The issue is rare in PG16 and higher branches because, in most cases, the tablesync worker performs the origin drop in those branches, and its locking sequence does not conflict with DDL operations. This patch ensures consistent lock acquisition to prevent such deadlocks. As per buildfarm. Reported-by: Alexander Lakhin <exclusion@gmail.com> Author: Ajin Cherian <itsajin@gmail.com> Reviewed-by: Hayato Kuroda <kuroda.hayato@fujitsu.com> Reviewed-by: vignesh C <vignesh21@gmail.com> Reviewed-by: Amit Kapila <amit.kapila16@gmail.com> Backpatch-through: 14, where it was introduced Discussion: https://postgr.es/m/bab95e12-6cc5-4ebb-80a8-3e41956aa297@gmail.com
1 parent 7ee7c1c commit 41fb3f5

File tree

3 files changed

+55
-7
lines changed

3 files changed

+55
-7
lines changed

src/backend/catalog/pg_subscription.c

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -281,18 +281,33 @@ AddSubscriptionRelState(Oid subid, Oid relid, char state,
281281
* Update the state of a subscription table.
282282
*/
283283
void
284-
UpdateSubscriptionRelState(Oid subid, Oid relid, char state,
285-
XLogRecPtr sublsn)
284+
UpdateSubscriptionRelStateEx(Oid subid, Oid relid, char state,
285+
XLogRecPtr sublsn, bool already_locked)
286286
{
287287
Relation rel;
288288
HeapTuple tup;
289289
bool nulls[Natts_pg_subscription_rel];
290290
Datum values[Natts_pg_subscription_rel];
291291
bool replaces[Natts_pg_subscription_rel];
292292

293-
LockSharedObject(SubscriptionRelationId, subid, 0, AccessShareLock);
293+
if (already_locked)
294+
{
295+
#ifdef USE_ASSERT_CHECKING
296+
LOCKTAG tag;
294297

295-
rel = table_open(SubscriptionRelRelationId, RowExclusiveLock);
298+
Assert(CheckRelationOidLockedByMe(SubscriptionRelRelationId,
299+
RowExclusiveLock, true));
300+
SET_LOCKTAG_OBJECT(tag, InvalidOid, SubscriptionRelationId, subid, 0);
301+
Assert(LockHeldByMe(&tag, AccessShareLock));
302+
#endif
303+
304+
rel = table_open(SubscriptionRelRelationId, NoLock);
305+
}
306+
else
307+
{
308+
LockSharedObject(SubscriptionRelationId, subid, 0, AccessShareLock);
309+
rel = table_open(SubscriptionRelRelationId, RowExclusiveLock);
310+
}
296311

297312
/* Try finding existing mapping. */
298313
tup = SearchSysCacheCopy2(SUBSCRIPTIONRELMAP,
@@ -326,6 +341,16 @@ UpdateSubscriptionRelState(Oid subid, Oid relid, char state,
326341
table_close(rel, NoLock);
327342
}
328343

344+
/*
345+
* Update the state of a subscription table.
346+
*/
347+
void
348+
UpdateSubscriptionRelState(Oid subid, Oid relid, char state,
349+
XLogRecPtr sublsn)
350+
{
351+
UpdateSubscriptionRelStateEx(subid, relid, state, sublsn, false);
352+
}
353+
329354
/*
330355
* Get state of subscription table.
331356
*

src/backend/replication/logical/tablesync.c

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ process_syncing_tables_for_apply(XLogRecPtr current_lsn)
366366
static HTAB *last_start_times = NULL;
367367
ListCell *lc;
368368
bool started_tx = false;
369+
Relation rel = NULL;
369370

370371
Assert(!IsTransactionState());
371372

@@ -463,7 +464,16 @@ process_syncing_tables_for_apply(XLogRecPtr current_lsn)
463464
* refresh for the subscription where we remove the table
464465
* state and its origin and by this time the origin might be
465466
* already removed. So passing missing_ok = true.
467+
*
468+
* Lock the subscription and origin in the same order as we
469+
* are doing during DDL commands to avoid deadlocks. See
470+
* AlterSubscription_refresh.
466471
*/
472+
LockSharedObject(SubscriptionRelationId, MyLogicalRepWorker->subid,
473+
0, AccessShareLock);
474+
if (!rel)
475+
rel = table_open(SubscriptionRelRelationId, RowExclusiveLock);
476+
467477
ReplicationOriginNameForTablesync(MyLogicalRepWorker->subid,
468478
rstate->relid,
469479
originname,
@@ -473,9 +483,9 @@ process_syncing_tables_for_apply(XLogRecPtr current_lsn)
473483
/*
474484
* Update the state to READY only after the origin cleanup.
475485
*/
476-
UpdateSubscriptionRelState(MyLogicalRepWorker->subid,
477-
rstate->relid, rstate->state,
478-
rstate->lsn);
486+
UpdateSubscriptionRelStateEx(MyLogicalRepWorker->subid,
487+
rstate->relid, rstate->state,
488+
rstate->lsn, true);
479489
}
480490
}
481491
else
@@ -526,7 +536,14 @@ process_syncing_tables_for_apply(XLogRecPtr current_lsn)
526536
* This is required to avoid any undetected deadlocks
527537
* due to any existing lock as deadlock detector won't
528538
* be able to detect the waits on the latch.
539+
*
540+
* Also close any tables prior to the commit.
529541
*/
542+
if (rel)
543+
{
544+
table_close(rel, NoLock);
545+
rel = NULL;
546+
}
530547
CommitTransactionCommand();
531548
pgstat_report_stat(false);
532549
}
@@ -586,6 +603,10 @@ process_syncing_tables_for_apply(XLogRecPtr current_lsn)
586603
}
587604
}
588605

606+
/* Close table if opened */
607+
if (rel)
608+
table_close(rel, NoLock);
609+
589610
if (started_tx)
590611
{
591612
CommitTransactionCommand();

src/include/catalog/pg_subscription_rel.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ extern void AddSubscriptionRelState(Oid subid, Oid relid, char state,
8585
XLogRecPtr sublsn);
8686
extern void UpdateSubscriptionRelState(Oid subid, Oid relid, char state,
8787
XLogRecPtr sublsn);
88+
extern void UpdateSubscriptionRelStateEx(Oid subid, Oid relid, char state,
89+
XLogRecPtr sublsn, bool already_locked);
8890
extern char GetSubscriptionRelState(Oid subid, Oid relid, XLogRecPtr *sublsn);
8991
extern void RemoveSubscriptionRel(Oid subid, Oid relid);
9092

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy