Skip to content

Commit 8c29832

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 1ca1889 commit 8c29832

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
@@ -287,18 +287,33 @@ AddSubscriptionRelState(Oid subid, Oid relid, char state,
287287
* Update the state of a subscription table.
288288
*/
289289
void
290-
UpdateSubscriptionRelState(Oid subid, Oid relid, char state,
291-
XLogRecPtr sublsn)
290+
UpdateSubscriptionRelStateEx(Oid subid, Oid relid, char state,
291+
XLogRecPtr sublsn, bool already_locked)
292292
{
293293
Relation rel;
294294
HeapTuple tup;
295295
bool nulls[Natts_pg_subscription_rel];
296296
Datum values[Natts_pg_subscription_rel];
297297
bool replaces[Natts_pg_subscription_rel];
298298

299-
LockSharedObject(SubscriptionRelationId, subid, 0, AccessShareLock);
299+
if (already_locked)
300+
{
301+
#ifdef USE_ASSERT_CHECKING
302+
LOCKTAG tag;
300303

301-
rel = table_open(SubscriptionRelRelationId, RowExclusiveLock);
304+
Assert(CheckRelationOidLockedByMe(SubscriptionRelRelationId,
305+
RowExclusiveLock, true));
306+
SET_LOCKTAG_OBJECT(tag, InvalidOid, SubscriptionRelationId, subid, 0);
307+
Assert(LockHeldByMe(&tag, AccessShareLock, true));
308+
#endif
309+
310+
rel = table_open(SubscriptionRelRelationId, NoLock);
311+
}
312+
else
313+
{
314+
LockSharedObject(SubscriptionRelationId, subid, 0, AccessShareLock);
315+
rel = table_open(SubscriptionRelRelationId, RowExclusiveLock);
316+
}
302317

303318
/* Try finding existing mapping. */
304319
tup = SearchSysCacheCopy2(SUBSCRIPTIONRELMAP,
@@ -332,6 +347,16 @@ UpdateSubscriptionRelState(Oid subid, Oid relid, char state,
332347
table_close(rel, NoLock);
333348
}
334349

350+
/*
351+
* Update the state of a subscription table.
352+
*/
353+
void
354+
UpdateSubscriptionRelState(Oid subid, Oid relid, char state,
355+
XLogRecPtr sublsn)
356+
{
357+
UpdateSubscriptionRelStateEx(subid, relid, state, sublsn, false);
358+
}
359+
335360
/*
336361
* Get state of subscription table.
337362
*

src/backend/replication/logical/tablesync.c

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ process_syncing_tables_for_apply(XLogRecPtr current_lsn)
426426
ListCell *lc;
427427
bool started_tx = false;
428428
bool should_exit = false;
429+
Relation rel = NULL;
429430

430431
Assert(!IsTransactionState());
431432

@@ -493,7 +494,16 @@ process_syncing_tables_for_apply(XLogRecPtr current_lsn)
493494
* worker to remove the origin tracking as if there is any
494495
* error while dropping we won't restart it to drop the
495496
* origin. So passing missing_ok = true.
497+
*
498+
* Lock the subscription and origin in the same order as we
499+
* are doing during DDL commands to avoid deadlocks. See
500+
* AlterSubscription_refresh.
496501
*/
502+
LockSharedObject(SubscriptionRelationId, MyLogicalRepWorker->subid,
503+
0, AccessShareLock);
504+
if (!rel)
505+
rel = table_open(SubscriptionRelRelationId, RowExclusiveLock);
506+
497507
ReplicationOriginNameForLogicalRep(MyLogicalRepWorker->subid,
498508
rstate->relid,
499509
originname,
@@ -503,9 +513,9 @@ process_syncing_tables_for_apply(XLogRecPtr current_lsn)
503513
/*
504514
* Update the state to READY only after the origin cleanup.
505515
*/
506-
UpdateSubscriptionRelState(MyLogicalRepWorker->subid,
507-
rstate->relid, rstate->state,
508-
rstate->lsn);
516+
UpdateSubscriptionRelStateEx(MyLogicalRepWorker->subid,
517+
rstate->relid, rstate->state,
518+
rstate->lsn, true);
509519
}
510520
}
511521
else
@@ -556,7 +566,14 @@ process_syncing_tables_for_apply(XLogRecPtr current_lsn)
556566
* This is required to avoid any undetected deadlocks
557567
* due to any existing lock as deadlock detector won't
558568
* be able to detect the waits on the latch.
569+
*
570+
* Also close any tables prior to the commit.
559571
*/
572+
if (rel)
573+
{
574+
table_close(rel, NoLock);
575+
rel = NULL;
576+
}
560577
CommitTransactionCommand();
561578
pgstat_report_stat(false);
562579
}
@@ -623,6 +640,10 @@ process_syncing_tables_for_apply(XLogRecPtr current_lsn)
623640
}
624641
}
625642

643+
/* Close table if opened */
644+
if (rel)
645+
table_close(rel, NoLock);
646+
626647
if (started_tx)
627648
{
628649
/*

src/include/catalog/pg_subscription_rel.h

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

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