Fix old visibility bug in HeapTupleSatisfiesDirty
authorAlvaro Herrera <[email protected]>
Fri, 2 Aug 2013 18:34:56 +0000 (14:34 -0400)
committerAlvaro Herrera <[email protected]>
Fri, 2 Aug 2013 21:02:36 +0000 (17:02 -0400)
If a tuple is locked but not updated by a concurrent transaction,
HeapTupleSatisfiesDirty would return that transaction's Xid in xmax,
causing callers to wait on it, when it is not necessary (in fact, if the
other transaction had used a multixact instead of a plain Xid to mark
the tuple, HeapTupleSatisfiesDirty would have behave differently and
*not* returned the Xmax).

This bug was introduced in commit 3f7fbf85dc5b42, dated December 1998,
so it's almost 15 years old now.  However, it's hard to see this
misbehave, because before we had NOWAIT the only consequence of this is
that transactions would wait for slightly more time than necessary; so
it's not surprising that this hasn't been reported yet.

Craig Ringer and Andres Freund

src/backend/utils/time/tqual.c

index 38bb704a4d8ae4a2a7ab21ac5dfbf749de3e3b5e..ed66c49a91fb4a214763817cf80268945f00c03c 100644 (file)
@@ -803,7 +803,8 @@ HeapTupleSatisfiesDirty(HeapTuple htup, Snapshot snapshot,
 
        if (TransactionIdIsInProgress(HeapTupleHeaderGetRawXmax(tuple)))
        {
-               snapshot->xmax = HeapTupleHeaderGetRawXmax(tuple);
+               if (!HEAP_XMAX_IS_LOCKED_ONLY(tuple->t_infomask))
+                       snapshot->xmax = HeapTupleHeaderGetRawXmax(tuple);
                return true;
        }