Re: BUG #19760: CLUSTER loses a row the transaction inserted and then updated in a rolled-back subtransaction

From: Manu <manuelreyesbravo(at)gmail(dot)com>
To: Michael Paquier <michael(at)paquier(dot)xyz>
Cc: Zhijie Hou <houzhijie22(at)gmail(dot)com>, shihao zhong <zhong950419(at)gmail(dot)com>, Takeshi Ideriha <iderihatakeshi(at)gmail(dot)com>, Ayush Tiwari <ayushtiwari(dot)slg01(at)gmail(dot)com>, alpkeles99(at)gmail(dot)com, pgsql-bugs(at)lists(dot)postgresql(dot)org
Subject: Re: BUG #19760: CLUSTER loses a row the transaction inserted and then updated in a rolled-back subtransaction
Date: 2026-10-27 20:03:26
Message-ID: 179313140649.978027.15867933676406793547@gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

Hi Michael,

When I withdrew the patch, I said that if I came back to this, it
would start from an account of the problem and not from another
variant. Here it is.

There is a case that no hint bit can prevent: the pg_class row of a
table committed long ago is lost when the subtransaction that
updated it aborts while VACUUM FULL pg_class is between the old and
the new version. The attached script reproduces it with plain SQL,
using the progress view to time the ROLLBACK TO. It loses the row
in every round on unmodified master, REL_18_STABLE and
REL_14_STABLE.

When the scan reads the old version, its updater is still running,
so there is nothing to set yet. heapam_relation_copy_for_cluster()
is right to find the new version dead, as its inserter aborted.
What is wrong is what rewrite_heap_dead_tuple() concludes from that:
that the old version is dead too, which only holds if the update
committed. pruneheap.c draws that conclusion only from a
RECENTLY_DEAD tuple.

So instead of one more condition in rewrite_heap_dead_tuple(), the
fix removes it: dead tuples are no longer passed to rewriteheap.c,
and a tuple left waiting for a version that was never written is
resolved in end_heap_rewrite(), once the outcome of its update is
final. The code change removes more than it adds (71+, 77-); the
tests are a separate patch. I can post both if you want to look.

Manu

Attachment Content-Type Size
vacuum-full-lost-pg-class-row.sh.txt text/plain 5.3 KB

In response to

Browse pgsql-bugs by date

  From Date Subject
Next Message David Rowley 2026-10-27 20:11:18 Re: BUG #19759: Hashed SetOp / RecursiveUnion pre-allocate up to 64 GB from the row estimate since 8f29467c57f
Previous Message Kirill Reshke 2026-10-27 17:36:39 Re: BUG #19795: pgoutput: walsender crashes on START_REPLICATION option without a value