Repair some flakiness in CheckTargetForConflictsIn.
authorRobert Haas <rhaas@postgresql.org>
Tue, 5 Apr 2011 19:16:59 +0000 (15:16 -0400)
committerRobert Haas <rhaas@postgresql.org>
Tue, 5 Apr 2011 19:17:25 +0000 (15:17 -0400)
When we release and reacquire SerializableXactHashLock, we must recheck
whether an R/W conflict still needs to be flagged, because it could have
changed under us in the meantime.  And when we release the partition
lock, we must re-walk the list of predicate locks from the beginning,
because our pointer could get invalidated under us.

Bug report #5952 by Yamamoto Takashi.  Patch by Kevin Grittner.

src/backend/storage/lmgr/predicate.c

index 401acdb4715f75481ff94591a89f26620b8dc237..5096ea0c1c1722d2d47a67387930f542644c9297 100644 (file)
@@ -3757,6 +3757,17 @@ CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
                    LWLockRelease(partitionLock);
                    LWLockRelease(SerializablePredicateLockListLock);
                    LWLockAcquire(partitionLock, LW_SHARED);
+
+                   /*
+                    * The list may have been altered by another process
+                    * while we weren't holding the partition lock.  Start
+                    * over at the front.
+                    */
+                   nextpredlock = (PREDICATELOCK *)
+                       SHMQueueNext(&(target->predicateLocks),
+                                    &(target->predicateLocks),
+                                    offsetof(PREDICATELOCK, targetLink));
+
                    LWLockAcquire(SerializableXactHashLock, LW_SHARED);
                }
            }
@@ -3770,7 +3781,19 @@ CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
            LWLockRelease(SerializableXactHashLock);
            LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
 
-           FlagRWConflict(sxact, (SERIALIZABLEXACT *) MySerializableXact);
+           /*
+            * Re-check after getting exclusive lock because the other
+            * transaction may have flagged a conflict.
+            */
+           if (!SxactIsRolledBack(sxact)
+               && (!SxactIsCommitted(sxact)
+                   || TransactionIdPrecedes(GetTransactionSnapshot()->xmin,
+                                            sxact->finishedBefore))
+               && !RWConflictExists(sxact,
+                                    (SERIALIZABLEXACT *) MySerializableXact))
+           {
+               FlagRWConflict(sxact, (SERIALIZABLEXACT *) MySerializableXact);
+           }
 
            LWLockRelease(SerializableXactHashLock);
            LWLockAcquire(SerializableXactHashLock, LW_SHARED);