Repair some flakiness in CheckTargetForConflictsIn.

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.
This commit is contained in:
Robert Haas 2011-04-05 15:16:59 -04:00
parent 38d15f1651
commit 632f0faa7c

View 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);