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

From: Amit Kapila <amit(dot)kapila16(at)gmail(dot)com>
To: Masahiko Sawada <sawada(dot)mshk(at)gmail(dot)com>
Cc: Srinath Reddy Sadipiralla <srinath2133(at)gmail(dot)com>, pgsql-hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: Fix "unexpected logical decoding status change" error; from concurrent logical decoding activation
Date: 2026-07-29 05:28:34
Message-ID: CAA4eK1JCF2A+CiWVV_oTNOAu_sA7qcztGQkJpWU4wyMuFOOpUw@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Mon, Jul 27, 2026 at 9:36 PM Masahiko Sawada <sawada(dot)mshk(at)gmail(dot)com> wrote:
>
> On Fri, Jul 24, 2026 at 12:20 AM Amit Kapila <amit(dot)kapila16(at)gmail(dot)com> wrote:
> >
> > The other observation I had while looking at this patch was: On a
> > standby, InvalidateObsoleteReplicationSlots() can disable logical
> > decoding whenever it invalidates the last valid logical slot via
> > following check:
> >
> > if (invalidated_logical && !found_valid_logicalslot)
> > RequestDisableLogicalDecoding();
> > RequestDisableLogicalDecoding() isn't guarded against recovery, so a
> > purely local invalidation (RS_INVAL_HORIZON/WAL_REMOVED/IDLE_TIMEOUT)
> > makes the standby disable decoding even though the primary still has
> > it enabled. The standby's status is supposed to follow the primary via
> > XLOG_LOGICAL_DECODING_STATUS_CHANGE replay, and there's no
> > self-healing since the primary never sends an "enable". So, won't that
> > be a problem because after that no new slots will be allowed to be
> > created on standby and slotsync also won't be able perform sync. Am, I
> > missing something? If not then probable the above check needs
> > additional check: "!RecoveryInProgress()".
>
> In this case, the checkpointer will try to disable logical decoding
> but does nothing as it's still in recovery. See the
> RecoveryInProgress() check in DisableLogicalDecodingIfNecessary().
>
> If we skip calling RequestDisableLogicalDecoding() in this case, we
> would end up missing the disable request as it can be interleaved with
> the promotion process. Imagine:
>
> 1. the startup process begins the promotion, decides the
> new_status=true as there is a logical slot (in
> UpdateLogicalDecodingStatusEndOfRecovery()).
> 2. a backend process drops the last logical slot and skips calling
> RequestDisableLogicalDecoding() as the recovery status is still
> in-progress.
> 3. the startup completes the
> UpdateLogicalDecodingStatusEndOfRecovery(). The logical decoding is
> enabled even though there is no logical slot.
>

Thanks, I missed the check in DisableLogicalDecodingIfNecessary(). But
will it be better to add a comment atop that check and also atop
RequestDisableLogicalDecoding()? If so, how about something like
attached?

--
With Regards,
Amit Kapila.

Attachment Content-Type Size
v1_fix_comments_1.patch application/octet-stream 1.3 KB

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Ayush Tiwari 2026-07-29 05:41:24 Re: Prove a NOT IN's left-hand expressions non-nullable from quals
Previous Message shveta malik 2026-07-29 05:22:49 Re: A new C function `get_partition_root`.