Skip to content

Commit 434d2d1

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 22f126d commit 434d2d1

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
@@ -323,18 +323,33 @@ AddSubscriptionRelState(Oid subid, Oid relid, char state,
323323
* Update the state of a subscription table.
324324
*/
325325
void
326-
UpdateSubscriptionRelState(Oid subid, Oid relid, char state,
327-
XLogRecPtr sublsn)
326+
UpdateSubscriptionRelStateEx(Oid subid, Oid relid, char state,
327+
XLogRecPtr sublsn, bool already_locked)
328328
{
329329
Relation rel;
330330
HeapTuple tup;
331331
bool nulls[Natts_pg_subscription_rel];
332332
Datum values[Natts_pg_subscription_rel];
333333
bool replaces[Natts_pg_subscription_rel];
334334

335-
LockSharedObject(SubscriptionRelationId, subid, 0, AccessShareLock);
335+
if (already_locked)
336+
{
337+
#ifdef USE_ASSERT_CHECKING
338+
LOCKTAG tag;
336339

337-
rel = table_open(SubscriptionRelRelationId, RowExclusiveLock);
340+
Assert(CheckRelationOidLockedByMe(SubscriptionRelRelationId,
341+
RowExclusiveLock, true));
342+
SET_LOCKTAG_OBJECT(tag, InvalidOid, SubscriptionRelationId, subid, 0);
343+
Assert(LockHeldByMe(&tag, AccessShareLock));
344+
#endif
345+
346+
rel = table_open(SubscriptionRelRelationId, NoLock);
347+
}
348+
else
349+
{
350+
LockSharedObject(SubscriptionRelationId, subid, 0, AccessShareLock);
351+
rel = table_open(SubscriptionRelRelationId, RowExclusiveLock);
352+
}
338353

339354
/* Try finding existing mapping. */
340355
tup = SearchSysCacheCopy2(SUBSCRIPTIONRELMAP,
@@ -368,6 +383,16 @@ UpdateSubscriptionRelState(Oid subid, Oid relid, char state,
368383
table_close(rel, NoLock);
369384
}
370385

386+
/*
387+
* Update the state of a subscription table.
388+
*/
389+
void
390+
UpdateSubscriptionRelState(Oid subid, Oid relid, char state,
391+
XLogRecPtr sublsn)
392+
{
393+
UpdateSubscriptionRelStateEx(subid, relid, state, sublsn, false);
394+
}
395+
371396
/*
372397
* Get state of subscription table.
373398
*

src/backend/replication/logical/tablesync.c

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ process_syncing_tables_for_apply(XLogRecPtr current_lsn)
379379
static HTAB *last_start_times = NULL;
380380
ListCell *lc;
381381
bool started_tx = false;
382+
Relation rel = NULL;
382383

383384
Assert(!IsTransactionState());
384385

@@ -470,7 +471,16 @@ process_syncing_tables_for_apply(XLogRecPtr current_lsn)
470471
* refresh for the subscription where we remove the table
471472
* state and its origin and by this time the origin might be
472473
* already removed. So passing missing_ok = true.
474+
*
475+
* Lock the subscription and origin in the same order as we
476+
* are doing during DDL commands to avoid deadlocks. See
477+
* AlterSubscription_refresh.
473478
*/
479+
LockSharedObject(SubscriptionRelationId, MyLogicalRepWorker->subid,
480+
0, AccessShareLock);
481+
if (!rel)
482+
rel = table_open(SubscriptionRelRelationId, RowExclusiveLock);
483+
474484
ReplicationOriginNameForTablesync(MyLogicalRepWorker->subid,
475485
rstate->relid,
476486
originname,
@@ -480,9 +490,9 @@ process_syncing_tables_for_apply(XLogRecPtr current_lsn)
480490
/*
481491
* Update the state to READY only after the origin cleanup.
482492
*/
483-
UpdateSubscriptionRelState(MyLogicalRepWorker->subid,
484-
rstate->relid, rstate->state,
485-
rstate->lsn);
493+
UpdateSubscriptionRelStateEx(MyLogicalRepWorker->subid,
494+
rstate->relid, rstate->state,
495+
rstate->lsn, true);
486496
}
487497
}
488498
else
@@ -533,7 +543,14 @@ process_syncing_tables_for_apply(XLogRecPtr current_lsn)
533543
* This is required to avoid any undetected deadlocks
534544
* due to any existing lock as deadlock detector won't
535545
* be able to detect the waits on the latch.
546+
*
547+
* Also close any tables prior to the commit.
536548
*/
549+
if (rel)
550+
{
551+
table_close(rel, NoLock);
552+
rel = NULL;
553+
}
537554
CommitTransactionCommand();
538555
pgstat_report_stat(false);
539556
}
@@ -593,6 +610,10 @@ process_syncing_tables_for_apply(XLogRecPtr current_lsn)
593610
}
594611
}
595612

613+
/* Close table if opened */
614+
if (rel)
615+
table_close(rel, NoLock);
616+
596617
if (started_tx)
597618
{
598619
CommitTransactionCommand();

src/include/catalog/pg_subscription_rel.h

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

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