Skip to content

Commit 2a4b6ee

Browse files
committed
Compare Xmin to previous Xmax when locking an update chain
Not doing so causes us to traverse an update chain that has been broken by concurrent page pruning. All other code that traverses update chains uses this check as one of the cases in which to stop iterating, so replicate it here too. Failure to do so leads to erroneous CLOG, subtrans or multixact lookups. Per discussion following the bug report by J Smith in CADFUPgc5bmtv-yg9znxV-vcfkb+JPRqs7m2OesQXaM_4Z1JpdQ@mail.gmail.com as diagnosed by Andres Freund.
1 parent 4ed0640 commit 2a4b6ee

File tree

1 file changed

+14
-0
lines changed

1 file changed

+14
-0
lines changed

src/backend/access/heap/heapam.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4797,6 +4797,7 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
47974797
old_infomask;
47984798
TransactionId xmax,
47994799
new_xmax;
4800+
TransactionId priorXmax = InvalidTransactionId;
48004801

48014802
ItemPointerCopy(tid, &tupid);
48024803

@@ -4822,6 +4823,18 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
48224823
CHECK_FOR_INTERRUPTS();
48234824
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
48244825

4826+
/*
4827+
* Check the tuple XMIN against prior XMAX, if any. If we reached
4828+
* the end of the chain, we're done, so return success.
4829+
*/
4830+
if (TransactionIdIsValid(priorXmax) &&
4831+
!TransactionIdEquals(HeapTupleHeaderGetXmin(mytup.t_data),
4832+
priorXmax))
4833+
{
4834+
UnlockReleaseBuffer(buf);
4835+
return HeapTupleMayBeUpdated;
4836+
}
4837+
48254838
old_infomask = mytup.t_data->t_infomask;
48264839
xmax = HeapTupleHeaderGetRawXmax(mytup.t_data);
48274840

@@ -4922,6 +4935,7 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
49224935
}
49234936

49244937
/* tail recursion */
4938+
priorXmax = HeapTupleHeaderGetUpdateXid(mytup.t_data);
49254939
ItemPointerCopy(&(mytup.t_data->t_ctid), &tupid);
49264940
UnlockReleaseBuffer(buf);
49274941
}

0 commit comments

Comments
 (0)