summaryrefslogtreecommitdiff
path: root/src/backend/access/transam/xact.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/transam/xact.c')
-rw-r--r--src/backend/access/transam/xact.c151
1 files changed, 86 insertions, 65 deletions
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 2e972d56f60..02b064179f2 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.248 2007/09/05 18:10:47 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.249 2007/09/07 20:59:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -747,6 +747,8 @@ AtSubStart_ResourceOwner(void)
/*
* RecordTransactionCommit
+ *
+ * This is exported only to support an ugly hack in VACUUM FULL.
*/
void
RecordTransactionCommit(void)
@@ -1552,46 +1554,53 @@ CommitTransaction(void)
*/
RecordTransactionCommit();
- /*----------
+ PG_TRACE1(transaction__commit, MyProc->lxid);
+
+ /*
* Let others know about no transaction in progress by me. Note that
* this must be done _before_ releasing locks we hold and _after_
* RecordTransactionCommit.
*
- * LWLockAcquire(ProcArrayLock) is required; consider this example:
- * UPDATE with xid 0 is blocked by xid 1's UPDATE.
- * xid 1 is doing commit while xid 2 gets snapshot.
- * If xid 2's GetSnapshotData sees xid 1 as running then it must see
- * xid 0 as running as well, or it will be able to see two tuple versions
- * - one deleted by xid 1 and one inserted by xid 0. See notes in
- * GetSnapshotData.
- *
* Note: MyProc may be null during bootstrap.
- *----------
*/
if (MyProc != NULL)
{
- /*
- * Lock ProcArrayLock because that's what GetSnapshotData uses.
- * You might assume that we can skip this step if we had no
- * transaction id assigned, because the failure case outlined
- * in GetSnapshotData cannot happen in that case. This is true,
- * but we *still* need the lock guarantee that two concurrent
- * computations of the *oldest* xmin will get the same result.
- */
- LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
- MyProc->xid = InvalidTransactionId;
- MyProc->lxid = InvalidLocalTransactionId;
- MyProc->xmin = InvalidTransactionId;
- MyProc->inVacuum = false; /* must be cleared with xid/xmin */
+ if (TransactionIdIsValid(MyProc->xid))
+ {
+ /*
+ * We must lock ProcArrayLock while clearing MyProc->xid, so
+ * that we do not exit the set of "running" transactions while
+ * someone else is taking a snapshot. See discussion in
+ * src/backend/access/transam/README.
+ */
+ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
- /* Clear the subtransaction-XID cache too while holding the lock */
- MyProc->subxids.nxids = 0;
- MyProc->subxids.overflowed = false;
+ MyProc->xid = InvalidTransactionId;
+ MyProc->lxid = InvalidLocalTransactionId;
+ MyProc->xmin = InvalidTransactionId;
+ MyProc->inVacuum = false; /* must be cleared with xid/xmin */
- LWLockRelease(ProcArrayLock);
- }
+ /* Clear the subtransaction-XID cache too while holding the lock */
+ MyProc->subxids.nxids = 0;
+ MyProc->subxids.overflowed = false;
- PG_TRACE1(transaction__commit, s->transactionId);
+ LWLockRelease(ProcArrayLock);
+ }
+ else
+ {
+ /*
+ * If we have no XID, we don't need to lock, since we won't
+ * affect anyone else's calculation of a snapshot. We might
+ * change their estimate of global xmin, but that's OK.
+ */
+ MyProc->lxid = InvalidLocalTransactionId;
+ MyProc->xmin = InvalidTransactionId;
+ MyProc->inVacuum = false; /* must be cleared with xid/xmin */
+
+ Assert(MyProc->subxids.nxids == 0);
+ Assert(MyProc->subxids.overflowed == false);
+ }
+ }
/*
* This is all post-commit cleanup. Note that if an error is raised here,
@@ -1815,28 +1824,21 @@ PrepareTransaction(void)
* Let others know about no transaction in progress by me. This has to be
* done *after* the prepared transaction has been marked valid, else
* someone may think it is unlocked and recyclable.
+ *
+ * We can skip locking ProcArrayLock here, because this action does not
+ * actually change anyone's view of the set of running XIDs: our entry
+ * is duplicate with the gxact that has already been inserted into the
+ * ProcArray.
*/
-
- /*
- * Lock ProcArrayLock because that's what GetSnapshotData uses.
- * You might assume that we can skip this step if we have no
- * transaction id assigned, because the failure case outlined
- * in GetSnapshotData cannot happen in that case. This is true,
- * but we *still* need the lock guarantee that two concurrent
- * computations of the *oldest* xmin will get the same result.
- */
- LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
MyProc->xid = InvalidTransactionId;
MyProc->lxid = InvalidLocalTransactionId;
MyProc->xmin = InvalidTransactionId;
MyProc->inVacuum = false; /* must be cleared with xid/xmin */
- /* Clear the subtransaction-XID cache too while holding the lock */
+ /* Clear the subtransaction-XID cache too */
MyProc->subxids.nxids = 0;
MyProc->subxids.overflowed = false;
- LWLockRelease(ProcArrayLock);
-
/*
* This is all post-transaction cleanup. Note that if an error is raised
* here, it's too late to abort the transaction. This should be just
@@ -1987,36 +1989,55 @@ AbortTransaction(void)
*/
RecordTransactionAbort(false);
+ PG_TRACE1(transaction__abort, MyProc->lxid);
+
/*
* Let others know about no transaction in progress by me. Note that this
* must be done _before_ releasing locks we hold and _after_
* RecordTransactionAbort.
+ *
+ * Note: MyProc may be null during bootstrap.
*/
if (MyProc != NULL)
{
- /*
- * Lock ProcArrayLock because that's what GetSnapshotData uses.
- * You might assume that we can skip this step if we have no
- * transaction id assigned, because the failure case outlined
- * in GetSnapshotData cannot happen in that case. This is true,
- * but we *still* need the lock guarantee that two concurrent
- * computations of the *oldest* xmin will get the same result.
- */
- LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
- MyProc->xid = InvalidTransactionId;
- MyProc->lxid = InvalidLocalTransactionId;
- MyProc->xmin = InvalidTransactionId;
- MyProc->inVacuum = false; /* must be cleared with xid/xmin */
- MyProc->inCommit = false; /* be sure this gets cleared */
-
- /* Clear the subtransaction-XID cache too while holding the lock */
- MyProc->subxids.nxids = 0;
- MyProc->subxids.overflowed = false;
-
- LWLockRelease(ProcArrayLock);
- }
+ if (TransactionIdIsValid(MyProc->xid))
+ {
+ /*
+ * We must lock ProcArrayLock while clearing MyProc->xid, so
+ * that we do not exit the set of "running" transactions while
+ * someone else is taking a snapshot. See discussion in
+ * src/backend/access/transam/README.
+ */
+ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
- PG_TRACE1(transaction__abort, s->transactionId);
+ MyProc->xid = InvalidTransactionId;
+ MyProc->lxid = InvalidLocalTransactionId;
+ MyProc->xmin = InvalidTransactionId;
+ MyProc->inVacuum = false; /* must be cleared with xid/xmin */
+ MyProc->inCommit = false; /* be sure this gets cleared */
+
+ /* Clear the subtransaction-XID cache too while holding the lock */
+ MyProc->subxids.nxids = 0;
+ MyProc->subxids.overflowed = false;
+
+ LWLockRelease(ProcArrayLock);
+ }
+ else
+ {
+ /*
+ * If we have no XID, we don't need to lock, since we won't
+ * affect anyone else's calculation of a snapshot. We might
+ * change their estimate of global xmin, but that's OK.
+ */
+ MyProc->lxid = InvalidLocalTransactionId;
+ MyProc->xmin = InvalidTransactionId;
+ MyProc->inVacuum = false; /* must be cleared with xid/xmin */
+ MyProc->inCommit = false; /* be sure this gets cleared */
+
+ Assert(MyProc->subxids.nxids == 0);
+ Assert(MyProc->subxids.overflowed == false);
+ }
+ }
/*
* Post-abort cleanup. See notes in CommitTransaction() concerning