mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
Replace the former method of determining snapshot xmax --- to wit, calling
ReadNewTransactionId from GetSnapshotData --- with a "latestCompletedXid" variable that is updated during transaction commit or abort. Since latestCompletedXid is written only in places that had to lock ProcArrayLock exclusively anyway, and is read only in places that had to lock ProcArrayLock shared anyway, it adds no new locking requirements to the system despite being cluster-wide. Moreover, removing ReadNewTransactionId from snapshot acquisition eliminates the need to take both XidGenLock and ProcArrayLock at the same time. Since XidGenLock is sometimes held across I/O this can be a significant win. Some preliminary benchmarking suggested that this patch has no effect on average throughput but can significantly improve the worst-case transaction times seen in pgbench. Concept by Florian Pflug, implementation by Tom Lane.
This commit is contained in:
@ -6,7 +6,7 @@
|
||||
* Copyright (c) 2000-2007, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/varsup.c,v 1.78 2007/02/15 23:23:22 alvherre Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/varsup.c,v 1.79 2007/09/08 20:31:14 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -31,7 +31,9 @@ VariableCache ShmemVariableCache = NULL;
|
||||
|
||||
|
||||
/*
|
||||
* Allocate the next XID for my new transaction.
|
||||
* Allocate the next XID for my new transaction or subtransaction.
|
||||
*
|
||||
* The new XID is also stored into MyProc before returning.
|
||||
*/
|
||||
TransactionId
|
||||
GetNewTransactionId(bool isSubXact)
|
||||
@ -43,7 +45,11 @@ GetNewTransactionId(bool isSubXact)
|
||||
* transaction id.
|
||||
*/
|
||||
if (IsBootstrapProcessingMode())
|
||||
{
|
||||
Assert(!isSubXact);
|
||||
MyProc->xid = BootstrapTransactionId;
|
||||
return BootstrapTransactionId;
|
||||
}
|
||||
|
||||
LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
|
||||
|
||||
@ -112,19 +118,19 @@ GetNewTransactionId(bool isSubXact)
|
||||
TransactionIdAdvance(ShmemVariableCache->nextXid);
|
||||
|
||||
/*
|
||||
* We must store the new XID into the shared PGPROC array before releasing
|
||||
* XidGenLock. This ensures that when GetSnapshotData calls
|
||||
* ReadNewTransactionId, all active XIDs before the returned value of
|
||||
* nextXid are already present in PGPROC. Else we have a race condition.
|
||||
* We must store the new XID into the shared ProcArray before releasing
|
||||
* XidGenLock. This ensures that every active XID older than
|
||||
* latestCompletedXid is present in the ProcArray, which is essential
|
||||
* for correct OldestXmin tracking; see src/backend/access/transam/README.
|
||||
*
|
||||
* XXX by storing xid into MyProc without acquiring ProcArrayLock, we are
|
||||
* relying on fetch/store of an xid to be atomic, else other backends
|
||||
* might see a partially-set xid here. But holding both locks at once
|
||||
* would be a nasty concurrency hit (and in fact could cause a deadlock
|
||||
* against GetSnapshotData). So for now, assume atomicity. Note that
|
||||
* readers of PGPROC xid field should be careful to fetch the value only
|
||||
* once, rather than assume they can read it multiple times and get the
|
||||
* same answer each time.
|
||||
* would be a nasty concurrency hit. So for now, assume atomicity.
|
||||
*
|
||||
* Note that readers of PGPROC xid fields should be careful to fetch the
|
||||
* value only once, rather than assume they can read a value multiple
|
||||
* times and get the same answer each time.
|
||||
*
|
||||
* The same comments apply to the subxact xid count and overflow fields.
|
||||
*
|
||||
@ -138,11 +144,10 @@ GetNewTransactionId(bool isSubXact)
|
||||
* race-condition window, in that the new XID will not appear as running
|
||||
* until its parent link has been placed into pg_subtrans. However, that
|
||||
* will happen before anyone could possibly have a reason to inquire about
|
||||
* the status of the XID, so it seems OK. (Snapshots taken during this
|
||||
* the status of the XID, so it seems OK. (Snapshots taken during this
|
||||
* window *will* include the parent XID, so they will deliver the correct
|
||||
* answer later on when someone does have a reason to inquire.)
|
||||
*/
|
||||
if (MyProc != NULL)
|
||||
{
|
||||
/*
|
||||
* Use volatile pointer to prevent code rearrangement; other backends
|
||||
|
Reference in New Issue
Block a user