Update comments that became out-of-date with the PGXACT struct.

When the "hot" members of PGPROC were split off to separate PGXACT structs,
many PGPROC fields referred to in comments were moved to PGXACT, but the
comments were neglected in the commit. Mostly this is just a search/replace
of PGPROC with PGXACT, but the way the dummy PGPROC entries are created for
prepared transactions changed more, making some of the comments totally
bogus.

Noah Misch
This commit is contained in:
Heikki Linnakangas 2012-05-14 10:22:44 +03:00
parent 64f09ca386
commit 9e4637bf89
11 changed files with 56 additions and 66 deletions

View File

@ -251,7 +251,7 @@ enforce, and it assists with some other issues as explained below.) The
implementation of this is that GetSnapshotData takes the ProcArrayLock in
shared mode (so that multiple backends can take snapshots in parallel),
but ProcArrayEndTransaction must take the ProcArrayLock in exclusive mode
while clearing MyProc->xid at transaction end (either commit or abort).
while clearing MyPgXact->xid at transaction end (either commit or abort).
ProcArrayEndTransaction also holds the lock while advancing the shared
latestCompletedXid variable. This allows GetSnapshotData to use
@ -275,12 +275,12 @@ present in the ProcArray, or not running anymore. (This guarantee doesn't
apply to subtransaction XIDs, because of the possibility that there's not
room for them in the subxid array; instead we guarantee that they are
present or the overflow flag is set.) If a backend released XidGenLock
before storing its XID into MyProc, then it would be possible for another
before storing its XID into MyPgXact, then it would be possible for another
backend to allocate and commit a later XID, causing latestCompletedXid to
pass the first backend's XID, before that value became visible in the
ProcArray. That would break GetOldestXmin, as discussed below.
We allow GetNewTransactionId to store the XID into MyProc->xid (or the
We allow GetNewTransactionId to store the XID into MyPgXact->xid (or the
subxid array) without taking ProcArrayLock. This was once necessary to
avoid deadlock; while that is no longer the case, it's still beneficial for
performance. We are thereby relying on fetch/store of an XID to be atomic,
@ -293,7 +293,7 @@ ensure that the C compiler does exactly what you tell it to.)
Another important activity that uses the shared ProcArray is GetOldestXmin,
which must determine a lower bound for the oldest xmin of any active MVCC
snapshot, system-wide. Each individual backend advertises the smallest
xmin of its own snapshots in MyProc->xmin, or zero if it currently has no
xmin of its own snapshots in MyPgXact->xmin, or zero if it currently has no
live snapshots (eg, if it's between transactions or hasn't yet set a
snapshot for a new transaction). GetOldestXmin takes the MIN() of the
valid xmin fields. It does this with only shared lock on ProcArrayLock,
@ -320,7 +320,7 @@ too expensive. Note that while it is certain that two concurrent
executions of GetSnapshotData will compute the same xmin for their own
snapshots, as argued above, it is not certain that they will arrive at the
same estimate of RecentGlobalXmin. This is because we allow XID-less
transactions to clear their MyProc->xmin asynchronously (without taking
transactions to clear their MyPgXact->xmin asynchronously (without taking
ProcArrayLock), so one execution might see what had been the oldest xmin,
and another not. This is OK since RecentGlobalXmin need only be a valid
lower bound. As noted above, we are already assuming that fetch/store
@ -371,7 +371,7 @@ Top-level transactions do not have a parent, so they leave their pg_subtrans
entries set to the default value of zero (InvalidTransactionId).
pg_subtrans is used to check whether the transaction in question is still
running --- the main Xid of a transaction is recorded in the PGPROC struct,
running --- the main Xid of a transaction is recorded in the PGXACT struct,
but since we allow arbitrary nesting of subtransactions, we can't fit all Xids
in shared memory, so we have to store them on disk. Note, however, that for
each transaction we keep a "cache" of Xids that are known to be part of the

View File

@ -21,10 +21,9 @@
* GIDs and aborts the transaction if there already is a global
* transaction in prepared state with the same GID.
*
* A global transaction (gxact) also has a dummy PGPROC that is entered
* into the ProcArray array; this is what keeps the XID considered
* running by TransactionIdIsInProgress. It is also convenient as a
* PGPROC to hook the gxact's locks to.
* A global transaction (gxact) also has dummy PGXACT and PGPROC; this is
* what keeps the XID considered running by TransactionIdIsInProgress.
* It is also convenient as a PGPROC to hook the gxact's locks to.
*
* In order to survive crashes and shutdowns, all prepared
* transactions must be stored in permanent storage. This includes
@ -79,11 +78,6 @@ int max_prepared_xacts = 0;
* This struct describes one global transaction that is in prepared state
* or attempting to become prepared.
*
* The first component of the struct is a dummy PGPROC that is inserted
* into the global ProcArray so that the transaction appears to still be
* running and holding locks. It must be first because we cast pointers
* to PGPROC and pointers to GlobalTransactionData back and forth.
*
* The lifecycle of a global transaction is:
*
* 1. After checking that the requested GID is not in use, set up an
@ -91,7 +85,7 @@ int max_prepared_xacts = 0;
* with locking_xid = my own XID and valid = false.
*
* 2. After successfully completing prepare, set valid = true and enter the
* contained PGPROC into the global ProcArray.
* referenced PGPROC into the global ProcArray.
*
* 3. To begin COMMIT PREPARED or ROLLBACK PREPARED, check that the entry
* is valid and its locking_xid is no longer active, then store my current
@ -1069,12 +1063,12 @@ EndPrepare(GlobalTransaction gxact)
errmsg("could not close two-phase state file: %m")));
/*
* Mark the prepared transaction as valid. As soon as xact.c marks MyProc
* Mark the prepared transaction as valid. As soon as xact.c marks MyPgXact
* as not running our XID (which it will do immediately after this
* function returns), others can commit/rollback the xact.
*
* NB: a side effect of this is to make a dummy ProcArray entry for the
* prepared XID. This must happen before we clear the XID from MyProc,
* prepared XID. This must happen before we clear the XID from MyPgXact,
* else there is a window where the XID is not running according to
* TransactionIdIsInProgress, and onlookers would be entitled to assume
* the xact crashed. Instead we have a window where the same XID appears

View File

@ -35,7 +35,7 @@ VariableCache ShmemVariableCache = NULL;
/*
* Allocate the next XID for a new transaction or subtransaction.
*
* The new XID is also stored into MyProc before returning.
* The new XID is also stored into MyPgXact before returning.
*
* Note: when this is called, we are actually already inside a valid
* transaction, since XIDs are now not allocated until the transaction
@ -174,19 +174,19 @@ GetNewTransactionId(bool isSubXact)
* 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
* XXX by storing xid into MyPgXact 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. So for now, assume atomicity.
*
* Note that readers of PGPROC xid fields should be careful to fetch the
* Note that readers of PGXACT 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.
*
* A solution to the atomic-store problem would be to give each PGPROC its
* own spinlock used only for fetching/storing that PGPROC's xid and
* A solution to the atomic-store problem would be to give each PGXACT its
* own spinlock used only for fetching/storing that PGXACT's xid and
* related fields.
*
* If there's no room to fit a subtransaction XID into PGPROC, set the

View File

@ -279,7 +279,7 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt, BufferAccessStrategy bstrategy)
relation_close(onerel, NoLock);
/*
* Reset my PGPROC flag. Note: we need this here, and not in vacuum_rel,
* Reset my PGXACT flag. Note: we need this here, and not in vacuum_rel,
* because the vacuum flag is cleared by the end-of-xact code.
*/
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);

View File

@ -892,7 +892,7 @@ vacuum_rel(Oid relid, VacuumStmt *vacstmt, bool do_toast, bool for_wraparound)
*
* Note: these flags remain set until CommitTransaction or
* AbortTransaction. We don't want to clear them until we reset
* MyProc->xid/xmin, else OldestXmin might appear to go backwards,
* MyPgXact->xid/xmin, else OldestXmin might appear to go backwards,
* which is probably Not Good.
*/
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);

View File

@ -2327,7 +2327,7 @@ do_autovacuum(void)
tab->at_datname, tab->at_nspname, tab->at_relname);
EmitErrorReport();
/* this resets the PGPROC flags too */
/* this resets the PGXACT flags too */
AbortOutOfAnyTransaction();
FlushErrorState();
MemoryContextResetAndDeleteChildren(PortalContext);
@ -2338,7 +2338,7 @@ do_autovacuum(void)
}
PG_END_TRY();
/* the PGPROC flags are reset at the next end of transaction */
/* the PGXACT flags are reset at the next end of transaction */
/* be tidy */
deleted:

View File

@ -4,18 +4,18 @@
* POSTGRES process array code.
*
*
* This module maintains an unsorted array of the PGPROC structures for all
* This module maintains arrays of the PGPROC and PGXACT structures for all
* active backends. Although there are several uses for this, the principal
* one is as a means of determining the set of currently running transactions.
*
* Because of various subtle race conditions it is critical that a backend
* hold the correct locks while setting or clearing its MyProc->xid field.
* hold the correct locks while setting or clearing its MyPgXact->xid field.
* See notes in src/backend/access/transam/README.
*
* The process array now also includes PGPROC structures representing
* prepared transactions. The xid and subxids fields of these are valid,
* as are the myProcLocks lists. They can be distinguished from regular
* backend PGPROCs at need by checking for pid == 0.
* The process arrays now also include structures representing prepared
* transactions. The xid and subxids fields of these are valid, as are the
* myProcLocks lists. They can be distinguished from regular backend PGPROCs
* at need by checking for pid == 0.
*
* During hot standby, we also keep a list of XIDs representing transactions
* that are known to be running in the master (or more precisely, were running
@ -75,7 +75,7 @@ typedef struct ProcArrayStruct
/*
* Highest subxid that has been removed from KnownAssignedXids array to
* prevent overflow; or InvalidTransactionId if none. We track this for
* similar reasons to tracking overflowing cached subxids in PGPROC
* similar reasons to tracking overflowing cached subxids in PGXACT
* entries. Must hold exclusive ProcArrayLock to change this, and shared
* lock to read it.
*/
@ -440,7 +440,7 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
* This is used after successfully preparing a 2-phase transaction. We are
* not actually reporting the transaction's XID as no longer running --- it
* will still appear as running because the 2PC's gxact is in the ProcArray
* too. We just have to clear out our own PGPROC.
* too. We just have to clear out our own PGXACT.
*/
void
ProcArrayClearTransaction(PGPROC *proc)
@ -752,7 +752,7 @@ ProcArrayApplyXidAssignment(TransactionId topxid,
* there are four possibilities for finding a running transaction:
*
* 1. The given Xid is a main transaction Id. We will find this out cheaply
* by looking at the PGPROC struct for each backend.
* by looking at the PGXACT struct for each backend.
*
* 2. The given Xid is one of the cached subxact Xids in the PGPROC array.
* We can find this out cheaply too.
@ -760,16 +760,16 @@ ProcArrayApplyXidAssignment(TransactionId topxid,
* 3. In Hot Standby mode, we must search the KnownAssignedXids list to see
* if the Xid is running on the master.
*
* 4. Search the SubTrans tree to find the Xid's topmost parent, and then
* see if that is running according to PGPROC or KnownAssignedXids. This is
* the slowest way, but sadly it has to be done always if the others failed,
* 4. Search the SubTrans tree to find the Xid's topmost parent, and then see
* if that is running according to PGXACT or KnownAssignedXids. This is the
* slowest way, but sadly it has to be done always if the others failed,
* unless we see that the cached subxact sets are complete (none have
* overflowed).
*
* ProcArrayLock has to be held while we do 1, 2, 3. If we save the top Xids
* while doing 1 and 3, we can release the ProcArrayLock while we do 4.
* This buys back some concurrency (and we can't retrieve the main Xids from
* PGPROC again anyway; see GetNewTransactionId).
* PGXACT again anyway; see GetNewTransactionId).
*/
bool
TransactionIdIsInProgress(TransactionId xid)
@ -915,7 +915,7 @@ TransactionIdIsInProgress(TransactionId xid)
*/
if (RecoveryInProgress())
{
/* none of the PGPROC entries should have XIDs in hot standby mode */
/* none of the PGXACT entries should have XIDs in hot standby mode */
Assert(nxids == 0);
if (KnownAssignedXidExists(xid))
@ -1283,7 +1283,7 @@ GetSnapshotData(Snapshot snapshot)
/*
* It is sufficient to get shared lock on ProcArrayLock, even if we are
* going to set MyProc->xmin.
* going to set MyPgXact->xmin.
*/
LWLockAcquire(ProcArrayLock, LW_SHARED);
@ -1462,7 +1462,7 @@ GetSnapshotData(Snapshot snapshot)
}
/*
* ProcArrayInstallImportedXmin -- install imported xmin into MyProc->xmin
* ProcArrayInstallImportedXmin -- install imported xmin into MyPgXact->xmin
*
* This is called when installing a snapshot imported from another
* transaction. To ensure that OldestXmin doesn't go backwards, we must
@ -1538,7 +1538,7 @@ ProcArrayInstallImportedXmin(TransactionId xmin, TransactionId sourcexid)
* GetRunningTransactionData -- returns information about running transactions.
*
* Similar to GetSnapshotData but returns more information. We include
* all PGPROCs with an assigned TransactionId, even VACUUM processes.
* all PGXACTs with an assigned TransactionId, even VACUUM processes.
*
* We acquire XidGenLock, but the caller is responsible for releasing it.
* This ensures that no new XIDs enter the proc array until the caller has
@ -1679,7 +1679,7 @@ GetRunningTransactionData(void)
* GetOldestActiveTransactionId()
*
* Similar to GetSnapshotData but returns just oldestActiveXid. We include
* all PGPROCs with an assigned TransactionId, even VACUUM processes.
* all PGXACTs with an assigned TransactionId, even VACUUM processes.
* We look at all databases, though there is no need to include WALSender
* since this has no effect on hot standby conflicts.
*
@ -1744,7 +1744,7 @@ GetOldestActiveTransactionId(void)
* GetTransactionsInCommit -- Get the XIDs of transactions that are committing
*
* Constructs an array of XIDs of transactions that are currently in commit
* critical sections, as shown by having inCommit set in their PGPROC entries.
* critical sections, as shown by having inCommit set in their PGXACT entries.
*
* *xids_p is set to a palloc'd array that should be freed by the caller.
* The return value is the number of valid entries.
@ -2189,7 +2189,7 @@ MinimumActiveBackends(int min)
*
* If someone just decremented numProcs, 'proc' could also point to a
* PGPROC entry that's no longer in the array. It still points to a
* PGPROC struct, though, because freed PGPPROC entries just go to the
* PGPROC struct, though, because freed PGPROC entries just go to the
* free list and are recycled. Its contents are nonsense in that case,
* but that's acceptable for this function.
*/
@ -2514,7 +2514,7 @@ DisplayXidCache(void)
* In Hot Standby mode, we maintain a list of transactions that are (or were)
* running in the master at the current point in WAL. These XIDs must be
* treated as running by standby transactions, even though they are not in
* the standby server's PGPROC array.
* the standby server's PGXACT array.
*
* We record all XIDs that we know have been assigned. That includes all the
* XIDs seen in WAL records, plus all unobserved XIDs that we can deduce have

View File

@ -56,7 +56,7 @@ int DeadlockTimeout = 1000;
int StatementTimeout = 0;
bool log_lock_waits = false;
/* Pointer to this process's PGPROC struct, if any */
/* Pointer to this process's PGPROC and PGXACT structs, if any */
PGPROC *MyProc = NULL;
PGXACT *MyPgXact = NULL;
@ -190,15 +190,11 @@ InitProcGlobal(void)
ProcGlobal->checkpointerLatch = NULL;
/*
* Create and initialize all the PGPROC structures we'll need (except for
* those used for 2PC, which are embedded within a GlobalTransactionData
* struct).
*
* There are four separate consumers of PGPROC structures: (1) normal
* backends, (2) autovacuum workers and the autovacuum launcher, (3)
* auxiliary processes, and (4) prepared transactions. Each PGPROC
* structure is dedicated to exactly one of these purposes, and they do
* not move between groups.
* Create and initialize all the PGPROC structures we'll need. There are
* four separate consumers: (1) normal backends, (2) autovacuum workers
* and the autovacuum launcher, (3) auxiliary processes, and (4) prepared
* transactions. Each PGPROC structure is dedicated to exactly one of
* these purposes, and they do not move between groups.
*/
procs = (PGPROC *) ShmemAlloc(TotalProcs * sizeof(PGPROC));
ProcGlobal->allProcs = procs;
@ -214,7 +210,7 @@ InitProcGlobal(void)
* from the main PGPROC array so that the most heavily accessed data is
* stored contiguously in memory in as few cache lines as possible. This
* provides significant performance benefits, especially on a
* multiprocessor system. Thereis one PGXACT structure for every PGPROC
* multiprocessor system. There is one PGXACT structure for every PGPROC
* structure.
*/
pgxacts = (PGXACT *) ShmemAlloc(TotalProcs * sizeof(PGXACT));

View File

@ -19,7 +19,7 @@
* have regd_count = 1 and are counted in RegisteredSnapshots, but are not
* tracked by any resource owner.
*
* These arrangements let us reset MyProc->xmin when there are no snapshots
* These arrangements let us reset MyPgXact->xmin when there are no snapshots
* referenced by this transaction. (One possible improvement would be to be
* able to advance Xmin when the snapshot with the earliest Xmin is no longer
* referenced. That's a bit harder though, it requires more locking, and
@ -104,7 +104,7 @@ static ActiveSnapshotElt *ActiveSnapshot = NULL;
* How many snapshots is resowner.c tracking for us?
*
* Note: for now, a simple counter is enough. However, if we ever want to be
* smarter about advancing our MyProc->xmin we will need to be more
* smarter about advancing our MyPgXact->xmin we will need to be more
* sophisticated about this, perhaps keeping our own list of snapshots.
*/
static int RegisteredSnapshots = 0;
@ -266,7 +266,7 @@ SetTransactionSnapshot(Snapshot sourcesnap, TransactionId sourcexid)
/* NB: curcid should NOT be copied, it's a local matter */
/*
* Now we have to fix what GetSnapshotData did with MyProc->xmin and
* Now we have to fix what GetSnapshotData did with MyPgXact->xmin and
* TransactionXmin. There is a race condition: to make sure we are not
* causing the global xmin to go backwards, we have to test that the
* source transaction is still running, and that has to be done atomically.
@ -569,7 +569,7 @@ UnregisterSnapshotFromOwner(Snapshot snapshot, ResourceOwner owner)
/*
* SnapshotResetXmin
*
* If there are no more snapshots, we can reset our PGPROC->xmin to InvalidXid.
* If there are no more snapshots, we can reset our PGXACT->xmin to InvalidXid.
* Note we can do this without locking because we assume that storing an Xid
* is atomic.
*/

View File

@ -10,12 +10,12 @@
* the passed-in buffer. The caller must hold not only a pin, but at least
* shared buffer content lock on the buffer containing the tuple.
*
* NOTE: must check TransactionIdIsInProgress (which looks in PGPROC array)
* NOTE: must check TransactionIdIsInProgress (which looks in PGXACT array)
* before TransactionIdDidCommit/TransactionIdDidAbort (which look in
* pg_clog). Otherwise we have a race condition: we might decide that a
* just-committed transaction crashed, because none of the tests succeed.
* xact.c is careful to record commit/abort in pg_clog before it unsets
* MyProc->xid in PGPROC array. That fixes that problem, but it also
* MyPgXact->xid in PGXACT array. That fixes that problem, but it also
* means there is a window where TransactionIdIsInProgress and
* TransactionIdDidCommit will both return true. If we check only
* TransactionIdDidCommit, we could consider a tuple committed when a

View File

@ -38,7 +38,7 @@ struct XidCache
TransactionId xids[PGPROC_MAX_CACHED_SUBXIDS];
};
/* Flags for PGPROC->vacuumFlags */
/* Flags for PGXACT->vacuumFlags */
#define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */
#define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */
#define PROC_IN_ANALYZE 0x04 /* currently running analyze */