From b3a0fea0c7499d1db40754b77770f4d3cb7793e2 Mon Sep 17 00:00:00 2001 From: shihao zhong Date: Sun, 18 Oct 2026 22:50:32 -0400 Subject: [PATCH v1 1/2] Don't drop a live tuple when its successor's inserter aborted When CLUSTER saw the dead successor of a tuple it was holding back, rewrite_heap_dead_tuple() discarded that tuple too. If the successor's inserter aborted, the update never happened and the tuple is live. Keep it in that case. Discussion: https://postgr.es/m/19760-8f9a0eba17bc8c92@postgresql.org --- src/backend/access/heap/rewriteheap.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c index 0648e433031..a9cc21717fa 100644 --- a/src/backend/access/heap/rewriteheap.c +++ b/src/backend/access/heap/rewriteheap.c @@ -301,8 +301,8 @@ end_heap_rewrite(RewriteState state) UnresolvedTup unresolved; /* - * Write any remaining tuples in the UnresolvedTups table. If we have any - * left, they should in fact be dead, but let's err on the safe side. + * Write any remaining tuples in the UnresolvedTups table. Usually they + * are dead, but they are live if the update aborted. */ hash_seq_init(&seq_status, state->rs_unresolved_tups); @@ -310,6 +310,8 @@ end_heap_rewrite(RewriteState state) { ItemPointerSetInvalid(&unresolved->tuple->t_data->t_ctid); raw_heap_insert(state, unresolved->tuple); + logical_rewrite_heap_tuple(state, unresolved->old_tid, + unresolved->tuple); } /* Write the last page, if any */ @@ -574,6 +576,14 @@ rewrite_heap_dead_tuple(RewriteState state, HeapTuple old_tuple) if (unresolved != NULL) { + /* + * If the inserter of this tuple aborted, the update never happened + * and the earlier tuple is not dead. It will be written at the end. + */ + if (!HeapTupleHeaderXminCommitted(old_tuple->t_data) && + !TransactionIdDidCommit(HeapTupleHeaderGetXmin(old_tuple->t_data))) + return false; + /* Need to free the contained tuple as well as the hashtable entry */ heap_freetuple(unresolved->tuple); hash_search(state->rs_unresolved_tups, &hashkey, -- 2.37.1 (Apple Git-137.1)