aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlvaro Herrera <alvherre@alvh.no-ip.org>2013-11-27 17:49:12 -0300
committerAlvaro Herrera <alvherre@alvh.no-ip.org>2013-11-28 11:54:25 -0300
commit2a4b6eed0916a8fdc57b4778ecb1463fe752d369 (patch)
treeb8a6bafe6edb4d60ad41d27b10323fab1e52feea /src
parent4ed0640e5c356e0935c3a057de7361fc444c0056 (diff)
downloadpostgresql-2a4b6eed0916a8fdc57b4778ecb1463fe752d369.tar.gz
postgresql-2a4b6eed0916a8fdc57b4778ecb1463fe752d369.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/heap/heapam.c14
1 files changed, 14 insertions, 0 deletions
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 8e1a3bff192..493df9f6ccd 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -4797,6 +4797,7 @@ heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid,
old_infomask;
TransactionId xmax,
new_xmax;
+ TransactionId priorXmax = InvalidTransactionId;
ItemPointerCopy(tid, &tupid);
@@ -4822,6 +4823,18 @@ l4:
CHECK_FOR_INTERRUPTS();
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;
xmax = HeapTupleHeaderGetRawXmax(mytup.t_data);
@@ -4922,6 +4935,7 @@ l4:
}
/* tail recursion */
+ priorXmax = HeapTupleHeaderGetUpdateXid(mytup.t_data);
ItemPointerCopy(&(mytup.t_data->t_ctid), &tupid);
UnlockReleaseBuffer(buf);
}