amcheck: detect corruption from the recent snapshot-export bug

Started by Andrey Borodin19 days ago3 messageshackers
Beta feature

Hackorum builds and tests every patch posted to the lists, not only commitfest submissions. This is Hackorum's own CI rather than the PostgreSQL project's, and it is still under testing - please report anything that looks wrong.

appliessuccessCI history

You can run a PostgreSQL built from this patch straight from Docker, with no checkout and no build:

docker run --rm -p 5432:5432 ghcr.io/hackorum-dev/postgres-patch:t254051
psql -h localhost -U postgres

Built from patchset v3 (message #3), October 23, 2026 at 11:41 PM.

Every patchset is also pushed to a branch of our PostgreSQL fork, so you can check out the same tree CI built. Without a PostgreSQL checkout:

git clone --branch t254051_3 https://github.com/hackorum-dev/postgres.git

In a checkout you already have, add the fork once:

git remote add hackorum https://github.com/hackorum-dev/postgres.git

then, for this patchset and every later one:

git fetch hackorum t254051_3 && git checkout t254051_3

Patchset v3 (message #3) is on t254051_3

Jump to latest
#1Andrey Borodin
amborodin@acm.org

Hi hackers!

I was investigating foreign-key violations reported by a user after
failover. Some tuples had HEAP_XMIN_INVALID set despite their xmin being
committed in pg_xact. During the investigation I found the recent
snapshot-export bug thread [0]/messages/by-id/CAH2-WzmHVeYY=pjz9x8DhhxVjXHX0pvoQ-MdiB1Tt6=o2GTiKg@mail.gmail.com, with a fix already committed.

pg_visibility reported the affected tuples on the standby, but
verify_heapam() did not. We routinely run verify_heapam() and would like
it to catch this damage without having to scan the same tables again
with pg_visibility.

PFA a two-patch series. 0001 detects this damage by reporting
HEAP_XMIN_INVALID when xmin is known to have committed. It excludes
old-style VACUUM FULL tuples and does not treat an assumed commit after
pg_xact truncation as evidence of corruption.

I think it would be good to have such check backpatched along with the
corruption fix.

0002 revisits the related xmin/xmax checks I proposed in 2024 [1]/messages/by-id/BE90C4F8-9A37-40AD-A5CC-9818BBE59BCC@yandex-team.ru. It
checks committed hints against aborted transactions, and invalid xmax
hints against committed updaters, including multixact members. I kept
these separate so that we can address the known corruption first.

The first patch's test also covers HEAP_MOVED_IN, though I'm not sure
it's worth adding coverage for this old VACUUM FULL format.

I am still thinking about how best to repair the existing damage.

Thank you!

Best regards, Andrey Borodin.

[0]: /messages/by-id/CAH2-WzmHVeYY=pjz9x8DhhxVjXHX0pvoQ-MdiB1Tt6=o2GTiKg@mail.gmail.com
[1]: /messages/by-id/BE90C4F8-9A37-40AD-A5CC-9818BBE59BCC@yandex-team.ru

Attachments:

t254051_1
v1-0001-Detect-incorrect-HEAP_XMIN_INVALID-hints-in-verif.patchapplication/octet-stream; name=v1-0001-Detect-incorrect-HEAP_XMIN_INVALID-hints-in-verif.patch; x-unix-mode=0644Download+103-10
v1-0002-Detect-more-inconsistent-transaction-hints-in-ver.patchapplication/octet-stream; name=v1-0002-Detect-more-inconsistent-transaction-hints-in-ver.patch; x-unix-mode=0644Download+165-7
#2Mark Dilger
mark.dilger@enterprisedb.com
In reply to: Andrey Borodin (#1)
Re: amcheck: detect corruption from the recent snapshot-export bug

On Sun, Oct 4, 2026 at 6:51 AM Andrey Borodin <x4mmm@yandex-team.ru> wrote:

Hi hackers!

I was investigating foreign-key violations reported by a user after
failover. Some tuples had HEAP_XMIN_INVALID set despite their xmin being
committed in pg_xact. During the investigation I found the recent
snapshot-export bug thread [0], with a fix already committed.

pg_visibility reported the affected tuples on the standby, but
verify_heapam() did not. We routinely run verify_heapam() and would like
it to catch this damage without having to scan the same tables again
with pg_visibility.

PFA a two-patch series. 0001 detects this damage by reporting
HEAP_XMIN_INVALID when xmin is known to have committed. It excludes
old-style VACUUM FULL tuples and does not treat an assumed commit after
pg_xact truncation as evidence of corruption.

This also affects HEAP_XMAX_INVALID for committed deletions.

I think it would be good to have such check backpatched along with the
corruption fix.

0002 revisits the related xmin/xmax checks I proposed in 2024 [1]. It
checks committed hints against aborted transactions, and invalid xmax
hints against committed updaters, including multixact members. I kept
these separate so that we can address the known corruption first.

The first patch's test also covers HEAP_MOVED_IN, though I'm not sure
it's worth adding coverage for this old VACUUM FULL format.

A minor nit: the new error messages do not follow existing style.

I believe this patch set fixes a real bug. Thanks for finding it.

-- Mark Dilger

#3Andrey Borodin
amborodin@acm.org
In reply to: Mark Dilger (#2)
Re: amcheck: detect corruption from the recent snapshot-export bug

Hi Mark,

On 5 Oct 2026, Mark Dilger wrote:

This also affects HEAP_XMAX_INVALID for committed deletions.

Yesterday in an off-list conversation I replied that: "Users reported
disappearing rows. So I wasn’t looking for emerging rows..."

Coincidentally, another production case reached me today: an old tuple
version has HEAP_XMAX_INVALID set for a committed updater, and VACUUM
fails with "cannot freeze committed xmax", just like in 2024. We have
not yet established whether snapshot export caused it, but likely so.
A cluster at hand has lots of savepoints and exprted snapshots, but
offending rows emerged in May.

That check was in 0002. In the attached v2 I moved it and its tests into
0001, so the first patch covers both invalid hints. I also adjusted the
diagnostic wording.

Thank you!

Best regards, Andrey Borodin.

Attachments:

t254051_3
v2-0001-Detect-incorrect-invalid-transaction-hints-in-ver.patchapplication/octet-stream; name=v2-0001-Detect-incorrect-invalid-transaction-hints-in-ver.patch; x-unix-mode=0644Download+218-12
v2-0002-Detect-incorrect-committed-transaction-hints-in-v.patchapplication/octet-stream; name=v2-0002-Detect-incorrect-committed-transaction-hints-in-v.patch; x-unix-mode=0644Download+57-4