Re: Fix "unexpected logical decoding status change" error; from concurrent logical decoding activation

From: shveta malik <shveta(dot)malik(at)gmail(dot)com>
To: Masahiko Sawada <sawada(dot)mshk(at)gmail(dot)com>
Cc: Nisha Moond <nisha(dot)moond412(at)gmail(dot)com>, Nikolay Samokhvalov <nik(at)postgres(dot)ai>, Srinath Reddy Sadipiralla <srinath2133(at)gmail(dot)com>, pgsql-hackers <pgsql-hackers(at)postgresql(dot)org>, shveta malik <shveta(dot)malik(at)gmail(dot)com>
Subject: Re: Fix "unexpected logical decoding status change" error; from concurrent logical decoding activation
Date: 2026-09-25 09:28:03
Message-ID: CAJpy0uBE_hjDA=dRdrwF8hLsqGJJtHWBTE4SGVzxJpHnnbd6cQ@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Fri, Sep 25, 2026 at 3:39 AM Masahiko Sawada <sawada(dot)mshk(at)gmail(dot)com> wrote:
>
> > I tested the patch and it fixes the problem. I found no critical
> > issues. A couple of comments:
> > 1) Now that a newly created synced slot is dropped on a failed new
> > check rather than kept as RS_TEMPORARY, a standby that is lagging in
> > replay can end up creating and dropping the slot on every sync cycle.
> > For example, replay is paused with pg_wal_replay_pause() or
> > recovery_min_apply_delay is large. After the primary turns logical
> > decoding off and then on again, the standby receives the activation
> > record but doesn't replay it. Meanwhile the slotsync worker keeps
> > fetching the failover slot, creates it, fails the new
> > IsLogicalDecodingEnabledSince() check, and drops it. This repeats
> > every cycle until the record is replayed.
> >
> > Each cycle creates the slot on disk and a pgstat entry, then removes
> > both again. I think this can be avoided with a cheaper pre-check,
> > IsLogicalDecodingEnabledSince(remote_slot->restart_lsn), before
> > ReplicationSlotCreate().
> >
> > Thoughts?
>
> I agree with your analysis. I think that in this case, the logical
> slot doesn't need to be dropped because WAL records after its
> restart_lsn are written with logical decoding information. Thinking on
> IsLogicalDecodingEnabledSince() further, I think it can work fine for
> the slot only when the replay LSN >= slot's restart_lsn. If the slot's
> restart_lsn > replay_lsn, we can leave the slot. Such a slot will be
> skipped for SS_SKIP_WAL_NOT_FLUSHED anyway. That way, the slot would
> have to be recreated only in the disable/re-enable case.

I agree with the problem and solution, but I don't think ths slot will
later be skipped with 'SS_SKIP_WAL_NOT_FLUSHED' as the WALs are
already flushed; it is the replay which is slow and that check
compares against GetStandbyFlushRecPtr(), not replay position I think
it will wait somewhere in
LogicalSlotAdvanceAndCheckSnapState()-->read_local_xlog_page_guts as
'wait_for_wal' is true and standy then waits for replay to happen. If
my understanding is correct, slotsync will be stuck on that one slot
untli replays happen, but let's see what Nisha has found in her tests.
I might be wrong too.

--I found that comments 1 and 2 in my previous email about set/reset
of 'last_replayed_enable_lsn' are missed to be addressed in v2.

--Also v2 does not apply through 'git am'.

--I have a suggestion about comment improvement in
synchronize_one_slot(), attached the patch. Please incorporate these
changes if you agree.

thanks
Shveta

Attachment Content-Type Size
0001-comment-change.patch.txt text/plain 4.2 KB

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Hayato Kuroda (Fujitsu) 2026-09-25 09:43:58 RE: Per-table resync for logical replication subscriptions
Previous Message Andrey Borodin 2026-09-25 09:25:22 Re: SSI: ON CONFLICT DO SELECT takes no predicate lock on the returned row