Skip to content
Snippets Groups Projects
Commit e4828e9c authored by Alvaro Herrera's avatar Alvaro Herrera
Browse files

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.
parent c235a6a5
No related branches found
No related tags found
No related merge requests found
...@@ -4814,6 +4814,7 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid, ...@@ -4814,6 +4814,7 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
old_infomask; old_infomask;
TransactionId xmax, TransactionId xmax,
new_xmax; new_xmax;
TransactionId priorXmax = InvalidTransactionId;
ItemPointerCopy(tid, &tupid); ItemPointerCopy(tid, &tupid);
...@@ -4839,6 +4840,18 @@ l4: ...@@ -4839,6 +4840,18 @@ l4:
CHECK_FOR_INTERRUPTS(); CHECK_FOR_INTERRUPTS();
LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE); LockBuffer(buf, BUFFER_LOCK_EXCLUSIVE);
/*
* Check the tuple XMIN against prior XMAX, if any. If we reached
* the end of the chain, we're done, so return success.
*/
if (TransactionIdIsValid(priorXmax) &&
!TransactionIdEquals(HeapTupleHeaderGetXmin(mytup.t_data),
priorXmax))
{
UnlockReleaseBuffer(buf);
return HeapTupleMayBeUpdated;
}
old_infomask = mytup.t_data->t_infomask; old_infomask = mytup.t_data->t_infomask;
xmax = HeapTupleHeaderGetRawXmax(mytup.t_data); xmax = HeapTupleHeaderGetRawXmax(mytup.t_data);
...@@ -4939,6 +4952,7 @@ l4: ...@@ -4939,6 +4952,7 @@ l4:
} }
/* tail recursion */ /* tail recursion */
priorXmax = HeapTupleHeaderGetUpdateXid(mytup.t_data);
ItemPointerCopy(&(mytup.t_data->t_ctid), &tupid); ItemPointerCopy(&(mytup.t_data->t_ctid), &tupid);
UnlockReleaseBuffer(buf); UnlockReleaseBuffer(buf);
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment