1
0
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:
Tom Lane
2007-09-08 20:31:15 +00:00
parent 0a51e7073c
commit 6bd4f401b0
14 changed files with 331 additions and 213 deletions

View File

@ -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