mirror of
https://github.com/postgres/postgres.git
synced 2025-11-15 03:41:20 +03:00
Don't take ProcArrayLock while exiting a transaction that has no XID; there is
no need for serialization against snapshot-taking because the xact doesn't affect anyone else's snapshot anyway. Per discussion. Also, move various info about the interlocking of transactions and snapshots out of code comments and into a hopefully-more-cohesive discussion in access/transam/README. Also, remove a couple of now-obsolete comments about having to force some WAL to be written to persuade RecordTransactionCommit to do its thing.
This commit is contained in:
@@ -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,47 +1554,54 @@ 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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
PG_TRACE1(transaction__commit, s->transactionId);
|
||||
|
||||
/*
|
||||
* This is all post-commit cleanup. Note that if an error is raised here,
|
||||
* it's too late to abort the transaction. This should be just
|
||||
@@ -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,37 +1989,56 @@ 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 */
|
||||
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 */
|
||||
MyProc->inCommit = false; /* be sure this gets cleared */
|
||||
|
||||
LWLockRelease(ProcArrayLock);
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
PG_TRACE1(transaction__abort, s->transactionId);
|
||||
|
||||
/*
|
||||
* Post-abort cleanup. See notes in CommitTransaction() concerning
|
||||
* ordering.
|
||||
|
||||
Reference in New Issue
Block a user