]> granicus.if.org Git - postgresql/commitdiff
Correctly detect SSI conflicts of prepared transactions after crash.
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>
Wed, 29 Feb 2012 13:22:49 +0000 (15:22 +0200)
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>
Wed, 29 Feb 2012 13:43:43 +0000 (15:43 +0200)
A prepared transaction can get new conflicts in and out after preparing, so
we cannot rely on the in- and out-flags stored in the statefile at prepare-
time. As a quick fix, make the conservative assumption that after a restart,
all prepared transactions are considered to have both in- and out-conflicts.
That can lead to unnecessary rollbacks after a crash, but that shouldn't be
a big problem in practice; you don't want prepared transactions to hang
around for a long time anyway.

Dan Ports

src/backend/storage/lmgr/predicate.c

index 27124672da94db39b114a8029a4b2ae20fd31f01..532dedf959bd2d262a38fb7cbcad8738c9fe0ecb 100644 (file)
@@ -4659,14 +4659,11 @@ AtPrepare_PredicateLocks(void)
        xactRecord->flags = MySerializableXact->flags;
 
        /*
-        * Tweak the flags. Since we're not going to output the inConflicts and
-        * outConflicts lists, if they're non-empty we'll represent that by
-        * setting the appropriate summary conflict flags.
+        * Note that we don't include the list of conflicts in our out in
+        * the statefile, because new conflicts can be added even after the
+        * transaction prepares. We'll just make a conservative assumption
+        * during recovery instead.
         */
-       if (!SHMQueueEmpty(&MySerializableXact->inConflicts))
-               xactRecord->flags |= SXACT_FLAG_SUMMARY_CONFLICT_IN;
-       if (!SHMQueueEmpty(&MySerializableXact->outConflicts))
-               xactRecord->flags |= SXACT_FLAG_SUMMARY_CONFLICT_OUT;
 
        RegisterTwoPhaseRecord(TWOPHASE_RM_PREDICATELOCK_ID, 0,
                                                   &record, sizeof(record));
@@ -4801,15 +4798,6 @@ predicatelock_twophase_recover(TransactionId xid, uint16 info,
 
                sxact->SeqNo.lastCommitBeforeSnapshot = RecoverySerCommitSeqNo;
 
-
-               /*
-                * We don't need the details of a prepared transaction's conflicts,
-                * just whether it had conflicts in or out (which we get from the
-                * flags)
-                */
-               SHMQueueInit(&(sxact->outConflicts));
-               SHMQueueInit(&(sxact->inConflicts));
-
                /*
                 * Don't need to track this; no transactions running at the time the
                 * recovered xact started are still active, except possibly other
@@ -4831,6 +4819,17 @@ predicatelock_twophase_recover(TransactionId xid, uint16 info,
                                   (MaxBackends + max_prepared_xacts));
                }
 
+               /*
+                * We don't know whether the transaction had any conflicts or
+                * not, so we'll conservatively assume that it had both a
+                * conflict in and a conflict out, and represent that with the
+                * summary conflict flags.
+                */
+               SHMQueueInit(&(sxact->outConflicts));
+               SHMQueueInit(&(sxact->inConflicts));
+               sxact->flags |= SXACT_FLAG_SUMMARY_CONFLICT_IN;
+               sxact->flags |= SXACT_FLAG_SUMMARY_CONFLICT_OUT;
+
                /* Register the transaction's xid */
                sxidtag.xid = xid;
                sxid = (SERIALIZABLEXID *) hash_search(SerializableXidHash,