diff --git a/src/backend/access/transam/README b/src/backend/access/transam/README index 54d97a5..573c9ad 100644 *** a/src/backend/access/transam/README --- b/src/backend/access/transam/README *************** *** 251,257 **** 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). ProcArrayEndTransaction also holds the lock while advancing the shared latestCompletedXid variable. This allows GetSnapshotData to use --- 251,257 ---- 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 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,286 **** 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 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 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, --- 275,286 ---- 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 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 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,299 **** 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 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, --- 293,299 ---- 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 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,326 **** 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 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 --- 320,326 ---- 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 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,377 **** 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, 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 --- 371,377 ---- 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 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 diff --git a/src/backend/access/transam/index 3d08e92..6db46c0 100644 *** a/src/backend/access/transam/twophase.c --- b/src/backend/access/transam/twophase.c *************** *** 21,30 **** * 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. * * In order to survive crashes and shutdowns, all prepared * transactions must be stored in permanent storage. This includes --- 21,29 ---- * 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 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,89 **** 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 --- 78,83 ---- *************** *** 91,97 **** 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. * * 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 --- 85,91 ---- * with locking_xid = my own XID and valid = false. * * 2. After successfully completing prepare, set valid = true and enter the ! * 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,1080 **** 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 * 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, * 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 --- 1063,1074 ---- errmsg("could not close two-phase state file: %m"))); /* ! * 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 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 diff --git a/src/backend/access/transam/varsindex 8c045fb..892a46a 100644 *** a/src/backend/access/transam/varsup.c --- b/src/backend/access/transam/varsup.c *************** *** 35,41 **** VariableCache ShmemVariableCache = NULL; /* * Allocate the next XID for a new transaction or subtransaction. * ! * The new XID is also stored into MyProc before returning. * * Note: when this is called, we are actually already inside a valid * transaction, since XIDs are now not allocated until the transaction --- 35,41 ---- /* * Allocate the next XID for a new transaction or subtransaction. * ! * 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,192 **** 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 * 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 * 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 * related fields. * * If there's no room to fit a subtransaction XID into PGPROC, set the --- 174,192 ---- * latestCompletedXid is present in the ProcArray, which is essential for * correct OldestXmin tracking; see src/backend/access/transam/README. * ! * 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 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 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 diff --git a/src/backend/commands/analyze.index ff27164..225ea86 100644 *** a/src/backend/commands/analyze.c --- b/src/backend/commands/analyze.c *************** *** 279,285 **** 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, * because the vacuum flag is cleared by the end-of-xact code. */ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); --- 279,285 ---- relation_close(onerel, NoLock); /* ! * 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); diff --git a/src/backend/commands/vacindex 353af50..c43cd8e 100644 *** a/src/backend/commands/vacuum.c --- b/src/backend/commands/vacuum.c *************** *** 892,898 **** 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, * which is probably Not Good. */ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); --- 892,898 ---- * * Note: these flags remain set until CommitTransaction or * AbortTransaction. We don't want to clear them until we reset ! * MyPgXact->xid/xmin, else OldestXmin might appear to go backwards, * which is probably Not Good. */ LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); diff --git a/src/backend/postmaster/index fa9a115..9ff19b7 100644 *** a/src/backend/postmaster/autovacuum.c --- b/src/backend/postmaster/autovacuum.c *************** *** 2327,2333 **** do_autovacuum(void) tab->at_datname, tab->at_nspname, tab->at_relname); EmitErrorReport(); ! /* this resets the PGPROC flags too */ AbortOutOfAnyTransaction(); FlushErrorState(); MemoryContextResetAndDeleteChildren(PortalContext); --- 2327,2333 ---- tab->at_datname, tab->at_nspname, tab->at_relname); EmitErrorReport(); ! /* this resets the PGXACT flags too */ AbortOutOfAnyTransaction(); FlushErrorState(); MemoryContextResetAndDeleteChildren(PortalContext); *************** *** 2338,2344 **** do_autovacuum(void) } PG_END_TRY(); ! /* the PGPROC flags are reset at the next end of transaction */ /* be tidy */ deleted: --- 2338,2344 ---- } PG_END_TRY(); ! /* the PGXACT flags are reset at the next end of transaction */ /* be tidy */ deleted: diff --git a/src/backend/storage/ipc/procaindex 1c9346a..26469c4 100644 *** a/src/backend/storage/ipc/procarray.c --- b/src/backend/storage/ipc/procarray.c *************** *** 4,21 **** * POSTGRES process array code. * * ! * This module maintains an unsorted array of the PGPROC 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. * 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. * * 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 --- 4,21 ---- * POSTGRES process array code. * * ! * 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 MyPgXact->xid field. * See notes in src/backend/access/transam/README. * ! * 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,81 **** 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 * entries. Must hold exclusive ProcArrayLock to change this, and shared * lock to read it. */ --- 75,81 ---- /* * 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 PGXACT * entries. Must hold exclusive ProcArrayLock to change this, and shared * lock to read it. */ *************** *** 440,446 **** 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. */ void ProcArrayClearTransaction(PGPROC *proc) --- 440,446 ---- * 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 PGXACT. */ void ProcArrayClearTransaction(PGPROC *proc) *************** *** 752,758 **** 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. * * 2. The given Xid is one of the cached subxact Xids in the PGPROC array. * We can find this out cheaply too. --- 752,758 ---- * 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 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,775 **** 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, * 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). */ bool TransactionIdIsInProgress(TransactionId xid) --- 760,775 ---- * 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 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 ! * PGXACT again anyway; see GetNewTransactionId). */ bool TransactionIdIsInProgress(TransactionId xid) *************** *** 915,921 **** TransactionIdIsInProgress(TransactionId xid) */ if (RecoveryInProgress()) { ! /* none of the PGPROC entries should have XIDs in hot standby mode */ Assert(nxids == 0); if (KnownAssignedXidExists(xid)) --- 915,921 ---- */ if (RecoveryInProgress()) { ! /* none of the PGXACT entries should have XIDs in hot standby mode */ Assert(nxids == 0); if (KnownAssignedXidExists(xid)) *************** *** 1283,1289 **** GetSnapshotData(Snapshot snapshot) /* * It is sufficient to get shared lock on ProcArrayLock, even if we are ! * going to set MyProc->xmin. */ LWLockAcquire(ProcArrayLock, LW_SHARED); --- 1283,1289 ---- /* * It is sufficient to get shared lock on ProcArrayLock, even if we are ! * going to set MyPgXact->xmin. */ LWLockAcquire(ProcArrayLock, LW_SHARED); *************** *** 1462,1468 **** GetSnapshotData(Snapshot snapshot) } /* ! * ProcArrayInstallImportedXmin -- install imported xmin into MyProc->xmin * * This is called when installing a snapshot imported from another * transaction. To ensure that OldestXmin doesn't go backwards, we must --- 1462,1468 ---- } /* ! * 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,1544 **** 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. * * 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 --- 1538,1544 ---- * GetRunningTransactionData -- returns information about running transactions. * * Similar to GetSnapshotData but returns more information. We include ! * 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,1685 **** GetRunningTransactionData(void) * GetOldestActiveTransactionId() * * Similar to GetSnapshotData but returns just oldestActiveXid. We include ! * all PGPROCs 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. * --- 1679,1685 ---- * GetOldestActiveTransactionId() * * Similar to GetSnapshotData but returns just oldestActiveXid. We include ! * 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,1750 **** 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. * * *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. --- 1744,1750 ---- * 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 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,2195 **** 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 * free list and are recycled. Its contents are nonsense in that case, * but that's acceptable for this function. */ --- 2189,2195 ---- * * 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 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,2520 **** 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. * * 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 --- 2514,2520 ---- * 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 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 diff --git a/src/backend/storage/lmgr/procindex 031e91d..458cd27 100644 *** a/src/backend/storage/lmgr/proc.c --- b/src/backend/storage/lmgr/proc.c *************** *** 56,62 **** int DeadlockTimeout = 1000; int StatementTimeout = 0; bool log_lock_waits = false; ! /* Pointer to this process's PGPROC struct, if any */ PGPROC *MyProc = NULL; PGXACT *MyPgXact = NULL; --- 56,62 ---- int StatementTimeout = 0; bool log_lock_waits = false; ! /* Pointer to this process's PGPROC and PGXACT structs, if any */ PGPROC *MyProc = NULL; PGXACT *MyPgXact = NULL; *************** *** 190,204 **** 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. */ procs = (PGPROC *) ShmemAlloc(TotalProcs * sizeof(PGPROC)); ProcGlobal->allProcs = procs; --- 190,200 ---- ProcGlobal->checkpointerLatch = NULL; /* ! * 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,220 **** 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 * structure. */ pgxacts = (PGXACT *) ShmemAlloc(TotalProcs * sizeof(PGXACT)); --- 210,216 ---- * 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. There is one PGXACT structure for every PGPROC * structure. */ pgxacts = (PGXACT *) ShmemAlloc(TotalProcs * sizeof(PGXACT)); diff --git a/src/backend/utils/time/snindex 5aebbd1..574099d 100644 *** a/src/backend/utils/time/snapmgr.c --- b/src/backend/utils/time/snapmgr.c *************** *** 19,25 **** * 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 * 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 --- 19,25 ---- * have regd_count = 1 and are counted in RegisteredSnapshots, but are not * tracked by any resource owner. * ! * 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,110 **** 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 * sophisticated about this, perhaps keeping our own list of snapshots. */ static int RegisteredSnapshots = 0; --- 104,110 ---- * 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 MyPgXact->xmin we will need to be more * sophisticated about this, perhaps keeping our own list of snapshots. */ static int RegisteredSnapshots = 0; *************** *** 266,272 **** 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 * 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. --- 266,272 ---- /* NB: curcid should NOT be copied, it's a local matter */ /* ! * 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,575 **** UnregisterSnapshotFromOwner(Snapshot snapshot, ResourceOwner owner) /* * SnapshotResetXmin * ! * If there are no more snapshots, we can reset our PGPROC->xmin to InvalidXid. * Note we can do this without locking because we assume that storing an Xid * is atomic. */ --- 569,575 ---- /* * SnapshotResetXmin * ! * 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. */ diff --git a/src/backend/utils/time/tquindex 727e0bf..01f7398 100644 *** a/src/backend/utils/time/tqual.c --- b/src/backend/utils/time/tqual.c *************** *** 10,21 **** * 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) * 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 * 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 --- 10,21 ---- * 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 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 ! * 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 diff --git a/src/include/storage/procindex 7552e18..618a02f 100644 *** a/src/include/storage/proc.h --- b/src/include/storage/proc.h *************** *** 38,44 **** struct XidCache TransactionId xids[PGPROC_MAX_CACHED_SUBXIDS]; }; ! /* Flags for PGPROC->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 */ --- 38,44 ---- TransactionId xids[PGPROC_MAX_CACHED_SUBXIDS]; }; ! /* 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 */