Re: Why clearing the VM doesn't require registering vm buffer in wal record

From: Melanie Plageman <melanieplageman(at)gmail(dot)com>
To: Andres Freund <andres(at)anarazel(dot)de>
Cc: Matthias van de Meent <boekewurm+postgres(at)gmail(dot)com>, PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>, Robert Haas <robertmhaas(at)gmail(dot)com>, Heikki Linnakangas <hlinnaka(at)iki(dot)fi>
Subject: Re: Why clearing the VM doesn't require registering vm buffer in wal record
Date: 2026-09-21 21:44:04
Message-ID: CAAKRu_b+Wr3j9z9G=f55PagFvtBCmwXQnsAG5rxy7fE-Bb6MFg@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Wed, Sep 16, 2026 at 12:10 PM Melanie Plageman
<melanieplageman(at)gmail(dot)com> wrote:
>
> There is an interaction between CREATE DATABASE STRATEGY WAL_LOG and
> this fix that causes data corruption (identified while investigating
> [1]). The scenario is you have a heap page set PD_ALL_VISIBLE and a
> corresponding VM page set all-visible, you do a CREATE DATABASE
> STRATEGY WAL_LOG using that database as a template. The primary has
> the heap page set PDV (PD_ALL_VISIBLE) set and VM page AV set but the
> standby does NOT have the page set all-visible in the VM (it does have
> the heap page set PDV). After failover you have a primary with heap
> page PDV set and VM page not set. You modify a tuple on the page.
> Because the VM was already clear, we do not register the VM block in
> the WAL record. The standby replays this and clears the heap page
> PD_ALL_VISIBLE but leaves the VM set. This is data corruption leading
> to wrong results from index scans and worse if that standby is later
> promoted back to primary.
>
> We didn't have this problem before ed62d26caca because it cleared the
> VM during replay as long as PD_ALL_VISIBLE needed clearing. I mention
> in the thread [2] that I think we have to fix
> RelationCopyStorageUsingBuffer() to avoid producing this scenario
> because tuple locking already caused data corruption before
> ed62d26caca. However, for update/delete, etc, I'm wondering if we
> should harden this a bit and go back to registering a vm clear
> operation whenever PD_ALL_VISIBLE was set on the heap page. If this is
> a no-op on the primary for the VM, we register it with
> REBGUF_NO_CHANGE. Vacuum works very hard to never end up with
> PD_ALL_VISIBLE cleared and the VM set. Perhaps we should do everything
> we can to avoid this happening with page modifications as well.

We can't WAL-log all pages that might possibly be out-of-sync on the
standby even if we didn't need to modify them on the primary. And the
above approach would kind of set that precedent. As an alternative,
the attached patch makes sure the VM is clear on the standby even when
the VM block was not registered and emits a warning. It isn't
resilient to torn pages since we won't have emitted an FPI on the
primary, however, since it is making a best attempt to repair
corruption, I think that's fine.

This would only need to be backpatched to 19.

- Melanie

Attachment Content-Type Size
0001-Clear-divergent-visibility-map-bits-during-heap-redo.patch text/x-patch 8.3 KB

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Alberto Piai 2026-09-21 21:48:03 Re: Adding a stored generated column without long-lived locks
Previous Message Zsolt Parragi 2026-09-21 21:38:56 Re: Stabilize and shorten test_checksums/013_rewind test