Re: Fix "unexpected logical decoding status change" error; from concurrent logical decoding activation - Mailing list pgsql-hackers

From shveta malik
Subject Re: Fix "unexpected logical decoding status change" error; from concurrent logical decoding activation
Date
Msg-id CAJpy0uDBSiuhrJ-X0rMNRty9bzs3CLSchnrxHVyHZB6NC+G0-A@mail.gmail.com
Whole thread
In response to Re: Fix "unexpected logical decoding status change" error; from concurrent logical decoding activation  (Masahiko Sawada <sawada.mshk@gmail.com>)
List pgsql-hackers
On Sat, Sep 26, 2026 at 3:54 AM Masahiko Sawada <sawada.mshk@gmail.com> wrote:
>
> On Fri, Sep 25, 2026 at 2:28 AM shveta malik <shveta.malik@gmail.com> wrote:
> >
> > On Fri, Sep 25, 2026 at 3:39 AM Masahiko Sawada <sawada.mshk@gmail.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.
>
> You're right, if only the replay is delayed, it can end up waiting in
> read_local_xlog_page_guts(). But I think this is pre-existing behavior
> for a remote slot whose confirmed_lsn is ahead of the standby's replay
> position.

Yes. I agree.

>
> On the other hand, if the WAL has not even been flushed on the standby
> yet, we skip the slot with SS_SKIP_WAL_NOT_FLUSHED before reaching
> that point. The temporary slot is kept and we retry in the next cycle,
> so we don't get stuck there.

Right.

> >
> > --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.
>
> Sorry I forgot to mention about comment 1 and 2; since the updated
> patch renamed the field name to last_replayed_enable_lsn I think we
> don't necessarily need to reset it at
> UpdateLogicalDecodingStatusEndOfRecovery().

Okay. Works for me.

> Also it renamed the
> function name to StandbyLogicalDecodingEnabledSince() so it makes
> sense to me to leave the field. As for comment 2, I think it's better
> to have an shmem-init function for LogicalDecodingCtl rather than
> initializing the new field in StartupLogicalDecodingStatus(). So I
> prepared a patch for that (0001 patch).

Okay, makes sense.

> I've incorporated your comment suggestions, and updated cosmetic
> things.Please review them.
>

Okay, looks good. I can have a look again once Amit's suggestion is
incorporated.

thanks
Shveta



pgsql-hackers by date:

Previous
From: Henson Choi
Date:
Subject: Re: Row pattern recognition
Next
From: jian he
Date:
Subject: Re: NOT NULL NOT ENFORCED