@@ -392,10 +392,11 @@ static HTAB *LocalPredicateLockHash = NULL;
392392
393393/*
394394 * Keep a pointer to the currently-running serializable transaction (if any)
395- * for quick reference.
396- *TODO SSI: Remove volatile qualifier and the then-unnecessary casts?
395+ * for quick reference. Also, remember if we have written anything that could
396+ *cause a rw-conflict.
397397 */
398- static volatile SERIALIZABLEXACT * MySerializableXact = InvalidSerializableXact ;
398+ static SERIALIZABLEXACT * MySerializableXact = InvalidSerializableXact ;
399+ static bool MyXactDidWrite = false;
399400
400401/* local functions */
401402
@@ -1424,20 +1425,30 @@ GetSafeSnapshot(Snapshot origSnapshot)
14241425if (MySerializableXact == InvalidSerializableXact )
14251426return snapshot ;/* no concurrent r/w xacts; it's safe */
14261427
1427- MySerializableXact -> flags |= SXACT_FLAG_DEFERRABLE_WAITING ;
1428+ LWLockAcquire ( SerializableXactHashLock , LW_EXCLUSIVE ) ;
14281429
14291430/*
14301431 * Wait for concurrent transactions to finish. Stop early if one of
14311432 * them marked us as conflicted.
14321433 */
1434+ MySerializableXact -> flags |=SXACT_FLAG_DEFERRABLE_WAITING ;
14331435while (!(SHMQueueEmpty ((SHM_QUEUE * )
14341436& MySerializableXact -> possibleUnsafeConflicts )||
14351437SxactIsROUnsafe (MySerializableXact )))
1438+ {
1439+ LWLockRelease (SerializableXactHashLock );
14361440ProcWaitForSignal ();
1437-
1441+ LWLockAcquire (SerializableXactHashLock ,LW_EXCLUSIVE );
1442+ }
14381443MySerializableXact -> flags &= ~SXACT_FLAG_DEFERRABLE_WAITING ;
1444+
14391445if (!SxactIsROUnsafe (MySerializableXact ))
1446+ {
1447+ LWLockRelease (SerializableXactHashLock );
14401448break ;/* success */
1449+ }
1450+
1451+ LWLockRelease (SerializableXactHashLock );
14411452
14421453/* else, need to retry... */
14431454ereport (DEBUG2 ,
@@ -1600,6 +1611,7 @@ RegisterSerializableTransactionInt(Snapshot snapshot)
16001611}
16011612
16021613MySerializableXact = sxact ;
1614+ MyXactDidWrite = false;/* haven't written anything yet */
16031615
16041616LWLockRelease (SerializableXactHashLock );
16051617
@@ -1635,24 +1647,24 @@ RegisterPredicateLockingXid(const TransactionId xid)
16351647if (MySerializableXact == InvalidSerializableXact )
16361648return ;
16371649
1638- /* This should only be done once per transaction. */
1639- Assert (MySerializableXact -> topXid == InvalidTransactionId );
1640-
16411650/* We should have a valid XID and be at the top level. */
16421651Assert (TransactionIdIsValid (xid ));
16431652
1653+ LWLockAcquire (SerializableXactHashLock ,LW_EXCLUSIVE );
1654+
1655+ /* This should only be done once per transaction. */
1656+ Assert (MySerializableXact -> topXid == InvalidTransactionId );
1657+
16441658MySerializableXact -> topXid = xid ;
16451659
16461660sxidtag .xid = xid ;
1647- LWLockAcquire (SerializableXactHashLock ,LW_EXCLUSIVE );
16481661sxid = (SERIALIZABLEXID * )hash_search (SerializableXidHash ,
16491662& sxidtag ,
16501663HASH_ENTER ,& found );
1651- Assert (sxid != NULL );
16521664Assert (!found );
16531665
16541666/* Initialize the structure. */
1655- sxid -> myXact = ( SERIALIZABLEXACT * ) MySerializableXact ;
1667+ sxid -> myXact = MySerializableXact ;
16561668LWLockRelease (SerializableXactHashLock );
16571669}
16581670
@@ -1881,7 +1893,7 @@ DeleteChildTargetLocks(const PREDICATELOCKTARGETTAG *newtargettag)
18811893PREDICATELOCK * predlock ;
18821894
18831895LWLockAcquire (SerializablePredicateLockListLock ,LW_SHARED );
1884- sxact = ( SERIALIZABLEXACT * ) MySerializableXact ;
1896+ sxact = MySerializableXact ;
18851897predlock = (PREDICATELOCK * )
18861898SHMQueueNext (& (sxact -> predicateLocks ),
18871899& (sxact -> predicateLocks ),
@@ -2200,8 +2212,7 @@ PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
22002212locallock -> childLocks = 0 ;
22012213
22022214/* Actually create the lock */
2203- CreatePredicateLock (targettag ,targettaghash ,
2204- (SERIALIZABLEXACT * )MySerializableXact );
2215+ CreatePredicateLock (targettag ,targettaghash ,MySerializableXact );
22052216
22062217/*
22072218 * Lock has been acquired. Check whether it should be promoted to a
@@ -3042,7 +3053,7 @@ ReleasePredicateLocks(const bool isCommit)
30423053Assert (IsolationIsSerializable ());
30433054
30443055/* We'd better not already be on the cleanup list. */
3045- Assert (!SxactIsOnFinishedList (( SERIALIZABLEXACT * ) MySerializableXact ));
3056+ Assert (!SxactIsOnFinishedList (MySerializableXact ));
30463057
30473058topLevelIsDeclaredReadOnly = SxactIsReadOnly (MySerializableXact );
30483059
@@ -3070,7 +3081,7 @@ ReleasePredicateLocks(const bool isCommit)
30703081MySerializableXact -> flags |=SXACT_FLAG_COMMITTED ;
30713082MySerializableXact -> commitSeqNo = ++ (PredXact -> LastSxactCommitSeqNo );
30723083/* Recognize implicit read-only transaction (commit without write). */
3073- if (!( MySerializableXact -> flags & SXACT_FLAG_DID_WRITE ) )
3084+ if (!MyXactDidWrite )
30743085MySerializableXact -> flags |=SXACT_FLAG_READ_ONLY ;
30753086}
30763087else
@@ -3218,7 +3229,7 @@ ReleasePredicateLocks(const bool isCommit)
32183229
32193230/* Mark conflicted if necessary. */
32203231if (isCommit
3221- && ( MySerializableXact -> flags & SXACT_FLAG_DID_WRITE )
3232+ && MyXactDidWrite
32223233&& SxactHasConflictOut (MySerializableXact )
32233234&& (MySerializableXact -> SeqNo .earliestOutConflictCommit
32243235<=roXact -> SeqNo .lastCommitBeforeSnapshot ))
@@ -3282,15 +3293,15 @@ ReleasePredicateLocks(const bool isCommit)
32823293 (SHM_QUEUE * )& (MySerializableXact -> finishedLink ));
32833294
32843295if (!isCommit )
3285- ReleaseOneSerializableXact ((SERIALIZABLEXACT * )MySerializableXact ,
3286- false, false);
3296+ ReleaseOneSerializableXact (MySerializableXact , false, false);
32873297
32883298LWLockRelease (SerializableFinishedListLock );
32893299
32903300if (needToClear )
32913301ClearOldPredicateLocks ();
32923302
32933303MySerializableXact = InvalidSerializableXact ;
3304+ MyXactDidWrite = false;
32943305
32953306/* Delete per-transaction lock table */
32963307if (LocalPredicateLockHash != NULL )
@@ -3851,7 +3862,7 @@ CheckForSerializableConflictOut(const bool visible, const Relation relation,
38513862return ;
38523863}
38533864
3854- if (RWConflictExists (( SERIALIZABLEXACT * ) MySerializableXact ,sxact ))
3865+ if (RWConflictExists (MySerializableXact ,sxact ))
38553866{
38563867/* We don't want duplicate conflict records in the list. */
38573868LWLockRelease (SerializableXactHashLock );
@@ -3862,7 +3873,7 @@ CheckForSerializableConflictOut(const bool visible, const Relation relation,
38623873 * Flag the conflict. But first, if this conflict creates a dangerous
38633874 * structure, ereport an error.
38643875 */
3865- FlagRWConflict (( SERIALIZABLEXACT * ) MySerializableXact ,sxact );
3876+ FlagRWConflict (MySerializableXact ,sxact );
38663877LWLockRelease (SerializableXactHashLock );
38673878}
38683879
@@ -3944,7 +3955,7 @@ CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
39443955&& (!SxactIsCommitted (sxact )
39453956|| TransactionIdPrecedes (GetTransactionSnapshot ()-> xmin ,
39463957sxact -> finishedBefore ))
3947- && !RWConflictExists (sxact , ( SERIALIZABLEXACT * ) MySerializableXact ))
3958+ && !RWConflictExists (sxact ,MySerializableXact ))
39483959{
39493960LWLockRelease (SerializableXactHashLock );
39503961LWLockAcquire (SerializableXactHashLock ,LW_EXCLUSIVE );
@@ -3957,10 +3968,9 @@ CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
39573968&& (!SxactIsCommitted (sxact )
39583969|| TransactionIdPrecedes (GetTransactionSnapshot ()-> xmin ,
39593970sxact -> finishedBefore ))
3960- && !RWConflictExists (sxact ,
3961- (SERIALIZABLEXACT * )MySerializableXact ))
3971+ && !RWConflictExists (sxact ,MySerializableXact ))
39623972{
3963- FlagRWConflict (sxact ,( SERIALIZABLEXACT * ) MySerializableXact );
3973+ FlagRWConflict (sxact ,MySerializableXact );
39643974}
39653975
39663976LWLockRelease (SerializableXactHashLock );
@@ -4065,7 +4075,11 @@ CheckForSerializableConflictIn(const Relation relation, const HeapTuple tuple,
40654075errdetail ("Cancelled on identification as a pivot, during conflict in checking." ),
40664076errhint ("The transaction might succeed if retried." )));
40674077
4068- MySerializableXact -> flags |=SXACT_FLAG_DID_WRITE ;
4078+ /*
4079+ * We're doing a write which might cause rw-conflicts now or later.
4080+ * Memorize that fact.
4081+ */
4082+ MyXactDidWrite = true;
40694083
40704084/*
40714085 * It is important that we check for locks from the finest granularity to
@@ -4150,6 +4164,12 @@ CheckTableForSerializableConflictIn(const Relation relation)
41504164if (SkipSerialization (relation ))
41514165return ;
41524166
4167+ /*
4168+ * We're doing a write which might cause rw-conflicts now or later.
4169+ * Memorize that fact.
4170+ */
4171+ MyXactDidWrite = true;
4172+
41534173Assert (relation -> rd_index == NULL );/* not an index relation */
41544174
41554175dbId = relation -> rd_node .dbNode ;
@@ -4192,10 +4212,10 @@ CheckTableForSerializableConflictIn(const Relation relation)
41924212 offsetof(PREDICATELOCK ,targetLink ));
41934213
41944214if (predlock -> tag .myXact != MySerializableXact
4195- && !RWConflictExists (predlock -> tag .myXact ,
4196- ( SERIALIZABLEXACT * ) MySerializableXact ))
4197- FlagRWConflict (predlock -> tag .myXact ,
4198- ( SERIALIZABLEXACT * ) MySerializableXact );
4215+ && !RWConflictExists (predlock -> tag .myXact ,MySerializableXact ))
4216+ {
4217+ FlagRWConflict (predlock -> tag .myXact ,MySerializableXact );
4218+ }
41994219
42004220predlock = nextpredlock ;
42014221}
@@ -4506,7 +4526,7 @@ AtPrepare_PredicateLocks(void)
45064526TwoPhasePredicateXactRecord * xactRecord ;
45074527TwoPhasePredicateLockRecord * lockRecord ;
45084528
4509- sxact = ( SERIALIZABLEXACT * ) MySerializableXact ;
4529+ sxact = MySerializableXact ;
45104530xactRecord = & (record .data .xactRecord );
45114531lockRecord = & (record .data .lockRecord );
45124532
@@ -4583,6 +4603,7 @@ PostPrepare_PredicateLocks(TransactionId xid)
45834603LocalPredicateLockHash = NULL ;
45844604
45854605MySerializableXact = InvalidSerializableXact ;
4606+ MyXactDidWrite = false;
45864607}
45874608
45884609/*
@@ -4609,6 +4630,8 @@ PredicateLockTwoPhaseFinish(TransactionId xid, bool isCommit)
46094630
46104631/* Release its locks */
46114632MySerializableXact = sxid -> myXact ;
4633+ MyXactDidWrite = true;/* conservatively assume that we wrote
4634+ * something */
46124635ReleasePredicateLocks (isCommit );
46134636}
46144637