]> granicus.if.org Git - postgresql/commitdiff
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);