Recovery conflict resolution misses backends that import snapshots

From: Scott Ray <scott(at)scottray(dot)io>
To: PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: Recovery conflict resolution misses backends that import snapshots
Date: 2026-07-25 23:03:52
Message-ID: QpAansP4iVg_ttSs9x81PFAptL2sqR3AS06u8Jksm3_bHJvUwQjHOocRajbxBc3iiLdf9ZMC6gtXjZsxdxvOmqp98hLZcZuWyBDuQxS6uZc=@scottray.io
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hello,

There is a silent bug in standby conflict resolution that can cause
incorrect results. In ResolveRecoveryConflictWithSnapshot, the standby
calls GetConflictingVirtualXIDs once, then waits for each returned VXID
to disappear. However, after GetConflictingVirtualXIDs releases the
ProcArrayLock, a backend may import a conflicting snapshot from one of
the backends GetConflictingVirtualXIDs identified as conflicting. The
resulting VXID conflicts with recovery, but
ResolveRecoveryConflictWithSnapshot doesn't know it has to wait for the
new VXID to disappear before proceeding, so the standby removes tuple
versions or index entries that the importing backend needs.

This problem has existed since PG 10 (6c2003f8a1b), which introduced
standby snapshot export and broke ResolveRecoveryConflictWithSnapshot's
assumption that after GetConflictingVirtualXIDs returns, no new
conflicting VXIDs can be created.

The first attached patch adds a TAP test that fails deterministically
on unpatched master. The second makes
ResolveRecoveryConflictWithSnapshot call GetConflictingVirtualXIDs
until the result is empty, at which point importing a conflicting
snapshot is impossible: acquiring a conflicting xmin requires a live,
conflicting VXID as a source.

--
Scott Ray

Attachment Content-Type Size
v1-0002-Fix-recovery-conflict-resolution-to-account-for-i.patch application/octet-stream 4.6 KB
v1-0001-Add-TAP-test-for-recovery-conflicts-from-imported.patch application/octet-stream 6.9 KB

Browse pgsql-hackers by date

  From Date Subject
Next Message Michael Paquier 2026-07-25 23:36:42 Re: NULL pointer dereference in syslogger with load_libraries() and -DEXEC_BACKEND at startup
Previous Message Tom Lane 2026-07-25 22:51:31 Re: Self-join elimination drops an equality qual