Re: Re-read subscription state after lock in AlterSubscription

From: Shlok Kyal <shlok(dot)kyal(dot)oss(at)gmail(dot)com>
To: Bertrand Drouvot <bertranddrouvot(dot)pg(at)gmail(dot)com>
Cc: Amit Kapila <amit(dot)kapila16(at)gmail(dot)com>, "Zhijie Hou (Fujitsu)" <houzj(dot)fnst(at)fujitsu(dot)com>, Dilip Kumar <dilipbalaut(at)gmail(dot)com>, "Hayato Kuroda (Fujitsu)" <kuroda(dot)hayato(at)fujitsu(dot)com>, "pgsql-hackers(at)lists(dot)postgresql(dot)org" <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: Re: Re-read subscription state after lock in AlterSubscription
Date: 2026-08-05 11:28:41
Message-ID: CANhcyEVAqvm+ONcghSGbq4m94PuQ2JqB4sykVQv-iLKuiEO60A@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Tue, 4 Aug 2026 at 11:25, Bertrand Drouvot
<bertranddrouvot(dot)pg(at)gmail(dot)com> wrote:
>
> Hi,
>
> On Mon, Jul 06, 2026 at 02:53:39PM +0000, Bertrand Drouvot wrote:
> > Hi,
> >
> > On Mon, Jul 06, 2026 at 03:07:24PM +0530, Amit Kapila wrote:
> >
> > DROP SUBSCRIPTION however has its own dedicated code path and does not go through
> > get_object_address(): 0003 adds the retry loop for it. And if DROP already uses
> > the retry loop then ALTER should probably use it too (also done in 0003 and 0004).
>
> Mandatory rebase attached.
>
Hi Bertrand,

While reviewing another patch, I found a bug on HEAD. It occurs when
ALTER SUBSCRIPTION ... REFRESH PUBLICATION and DROP SUBSCRIPTION runs
concurrently.
Suppose we have a logical replication setup between subscriber 'sub1'
and publisher 'pub1'.

Initially, we have:
postgres=# select oid, subname from pg_subscription;
oid | subname
-------+---------
16389 | sub1
(1 row)

postgres=# select * from pg_subscription_rel;
srsubid | srrelid | srsubstate | srsublsn
---------+---------+------------+------------
16389 | 16384 | r | 0/01750B90
(1 row)

Suppose we have two sessions S1 and S2 (attached GDB in S1).
S1: ALTER SUBSCRIPTION sub1 REFRESH PUBLICATION. (stops at a
breakpoint at 'LockSharedObject(SubscriptionRelationId, subid, 0,
AccessExclusiveLock)')
S2: DROP SUBSCRIPTION sub1;
S1: continue the execution

Both ALTER and DROP executes successfully.

After execution:
postgres=# select oid, subname from pg_subscription;
oid | subname
-----+---------
(0 rows)

postgres=# select * from pg_subscription_rel;
srsubid | srrelid | srsubstate | srsublsn
---------+---------+------------+----------
16389 | 16384 | i |
(1 row)

The subscription has been removed from pg_subscription, but entries
for that subscription remain in pg_subscription_rel. In other words,
DROP SUBSCRIPTION succeeds, yet orphaned rows are recreated in
pg_subscription_rel. I believe this is a bug.
The issue occurs because ALTER SUBSCRIPTION fetches the subscription
info before acquiring the subscription lock. If the subscription is
dropped in the meantime, ALTER SUBSCRIPTION continues using the stale
info. Although DROP SUBSCRIPTION removes the existing rows from
pg_subscription_rel, the still-running ALTER SUBSCRIPTION fetches the
publication table list from the publisher and recreates the
corresponding pg_subscription_rel entries in the 'init' state.

I believe the root cause is the same as the issue discussed in this
thread, so I'm reporting it here.
I tested this with the v5 patch series, and it resolves the issue.

Thanks,
Shlok Kyal

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Amit Kapila 2026-08-05 11:29:58 Re: Proposal: Conflict log history table for Logical Replication
Previous Message Amit Kapila 2026-08-05 11:17:06 Re: CREATE SUBSCRIPTION ... SERVER vs. pg_dump, etc.