]> granicus.if.org Git - postgresql/commitdiff
Fix WAL replay of locking an updated tuple
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 27 Feb 2014 14:13:39 +0000 (11:13 -0300)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Thu, 27 Feb 2014 14:23:24 +0000 (11:23 -0300)
We were resetting the tuple's HEAP_HOT_UPDATED flag as well as t_ctid on
WAL replay of a tuple-lock operation, which is incorrect when the tuple
is already updated.

Back-patch to 9.3.  The clearing of both header elements was there
previously, but since no update could be present on a tuple that was
being locked, it was harmless.

Bug reported by Peter Geoghegan and Greg Stark in
CAM3SWZTMQiCi5PV5OWHb+bYkUcnCk=O67w0cSswPvV7XfUcU5g@mail.gmail.com and
CAM-w4HPTOeMT4KP0OJK+mGgzgcTOtLRTvFZyvD0O4aH-7dxo3Q@mail.gmail.com
respectively; diagnosis by Andres Freund.

src/backend/access/heap/heapam.c

index 33fc5a75c6fafaa0f23ca2bcb7cdc8f305c50c0e..d94980bbc16dc3062b2ada0c1e4076a6dc32dbe3 100644 (file)
@@ -7721,11 +7721,19 @@ heap_xlog_lock(XLogRecPtr lsn, XLogRecord *record)
 
        fix_infomask_from_infobits(xlrec->infobits_set, &htup->t_infomask,
                                                           &htup->t_infomask2);
-       HeapTupleHeaderClearHotUpdated(htup);
+
+       /*
+        * Clear relevant update flags, but only if the modified infomask says
+        * there's no update.
+        */
+       if (HEAP_XMAX_IS_LOCKED_ONLY(htup->t_infomask))
+       {
+               HeapTupleHeaderClearHotUpdated(htup);
+               /* Make sure there is no forward chain link in t_ctid */
+               htup->t_ctid = xlrec->target.tid;
+       }
        HeapTupleHeaderSetXmax(htup, xlrec->locking_xid);
        HeapTupleHeaderSetCmax(htup, FirstCommandId, false);
-       /* Make sure there is no forward chain link in t_ctid */
-       htup->t_ctid = xlrec->target.tid;
        PageSetLSN(page, lsn);
        MarkBufferDirty(buffer);
        UnlockReleaseBuffer(buffer);