PostgreSQL Source Code  git master
procarray.c File Reference
#include "postgres.h"
#include <signal.h>
#include "access/clog.h"
#include "access/subtrans.h"
#include "access/transam.h"
#include "access/twophase.h"
#include "access/xact.h"
#include "access/xlogutils.h"
#include "catalog/catalog.h"
#include "catalog/pg_authid.h"
#include "commands/dbcommands.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "port/pg_lfind.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
Include dependency graph for procarray.c:

Go to the source code of this file.

Data Structures

struct  ProcArrayStruct
 
struct  GlobalVisState
 
struct  ComputeXidHorizonsResult
 

Macros

#define UINT32_ACCESS_ONCE(var)   ((uint32)(*((volatile uint32 *)&(var))))
 
#define xc_by_recent_xmin_inc()   ((void) 0)
 
#define xc_by_known_xact_inc()   ((void) 0)
 
#define xc_by_my_xact_inc()   ((void) 0)
 
#define xc_by_latest_xid_inc()   ((void) 0)
 
#define xc_by_main_xid_inc()   ((void) 0)
 
#define xc_by_child_xid_inc()   ((void) 0)
 
#define xc_by_known_assigned_inc()   ((void) 0)
 
#define xc_no_overflow_inc()   ((void) 0)
 
#define xc_slow_answer_inc()   ((void) 0)
 
#define PROCARRAY_MAXPROCS   (MaxBackends + max_prepared_xacts)
 
#define TOTAL_MAX_CACHED_SUBXIDS    ((PGPROC_MAX_CACHED_SUBXIDS + 1) * PROCARRAY_MAXPROCS)
 
#define MAXAUTOVACPIDS   10 /* max autovacs to SIGTERM per iteration */
 
#define KAX_COMPRESS_FREQUENCY   128 /* in transactions */
 
#define KAX_COMPRESS_IDLE_INTERVAL   1000 /* in ms */
 

Typedefs

typedef struct ProcArrayStruct ProcArrayStruct
 
typedef struct ComputeXidHorizonsResult ComputeXidHorizonsResult
 
typedef enum GlobalVisHorizonKind GlobalVisHorizonKind
 
typedef enum KAXCompressReason KAXCompressReason
 

Enumerations

enum  GlobalVisHorizonKind { VISHORIZON_SHARED , VISHORIZON_CATALOG , VISHORIZON_DATA , VISHORIZON_TEMP }
 
enum  KAXCompressReason { KAX_NO_SPACE , KAX_PRUNE , KAX_TRANSACTION_END , KAX_STARTUP_PROCESS_IDLE }
 

Functions

static void KnownAssignedXidsCompress (KAXCompressReason reason, bool haveLock)
 
static void KnownAssignedXidsAdd (TransactionId from_xid, TransactionId to_xid, bool exclusive_lock)
 
static bool KnownAssignedXidsSearch (TransactionId xid, bool remove)
 
static bool KnownAssignedXidExists (TransactionId xid)
 
static void KnownAssignedXidsRemove (TransactionId xid)
 
static void KnownAssignedXidsRemoveTree (TransactionId xid, int nsubxids, TransactionId *subxids)
 
static void KnownAssignedXidsRemovePreceding (TransactionId removeXid)
 
static int KnownAssignedXidsGet (TransactionId *xarray, TransactionId xmax)
 
static int KnownAssignedXidsGetAndSetXmin (TransactionId *xarray, TransactionId *xmin, TransactionId xmax)
 
static TransactionId KnownAssignedXidsGetOldestXmin (void)
 
static void KnownAssignedXidsDisplay (int trace_level)
 
static void KnownAssignedXidsReset (void)
 
static void ProcArrayEndTransactionInternal (PGPROC *proc, TransactionId latestXid)
 
static void ProcArrayGroupClearXid (PGPROC *proc, TransactionId latestXid)
 
static void MaintainLatestCompletedXid (TransactionId latestXid)
 
static void MaintainLatestCompletedXidRecovery (TransactionId latestXid)
 
static FullTransactionId FullXidRelativeTo (FullTransactionId rel, TransactionId xid)
 
static void GlobalVisUpdateApply (ComputeXidHorizonsResult *horizons)
 
Size ProcArrayShmemSize (void)
 
void CreateSharedProcArray (void)
 
void ProcArrayAdd (PGPROC *proc)
 
void ProcArrayRemove (PGPROC *proc, TransactionId latestXid)
 
void ProcArrayEndTransaction (PGPROC *proc, TransactionId latestXid)
 
void ProcArrayClearTransaction (PGPROC *proc)
 
void ProcArrayInitRecovery (TransactionId initializedUptoXID)
 
void ProcArrayApplyRecoveryInfo (RunningTransactions running)
 
void ProcArrayApplyXidAssignment (TransactionId topxid, int nsubxids, TransactionId *subxids)
 
bool TransactionIdIsInProgress (TransactionId xid)
 
bool TransactionIdIsActive (TransactionId xid)
 
static void ComputeXidHorizons (ComputeXidHorizonsResult *h)
 
static GlobalVisHorizonKind GlobalVisHorizonKindForRel (Relation rel)
 
TransactionId GetOldestNonRemovableTransactionId (Relation rel)
 
TransactionId GetOldestTransactionIdConsideredRunning (void)
 
void GetReplicationHorizons (TransactionId *xmin, TransactionId *catalog_xmin)
 
int GetMaxSnapshotXidCount (void)
 
int GetMaxSnapshotSubxidCount (void)
 
static bool GetSnapshotDataReuse (Snapshot snapshot)
 
Snapshot GetSnapshotData (Snapshot snapshot)
 
bool ProcArrayInstallImportedXmin (TransactionId xmin, VirtualTransactionId *sourcevxid)
 
bool ProcArrayInstallRestoredXmin (TransactionId xmin, PGPROC *proc)
 
RunningTransactions GetRunningTransactionData (void)
 
TransactionId GetOldestActiveTransactionId (void)
 
TransactionId GetOldestSafeDecodingTransactionId (bool catalogOnly)
 
VirtualTransactionIdGetVirtualXIDsDelayingChkpt (int *nvxids, int type)
 
bool HaveVirtualXIDsDelayingChkpt (VirtualTransactionId *vxids, int nvxids, int type)
 
PGPROCBackendPidGetProc (int pid)
 
PGPROCBackendPidGetProcWithLock (int pid)
 
int BackendXidGetPid (TransactionId xid)
 
bool IsBackendPid (int pid)
 
VirtualTransactionIdGetCurrentVirtualXIDs (TransactionId limitXmin, bool excludeXmin0, bool allDbs, int excludeVacuum, int *nvxids)
 
VirtualTransactionIdGetConflictingVirtualXIDs (TransactionId limitXmin, Oid dbOid)
 
pid_t CancelVirtualTransaction (VirtualTransactionId vxid, ProcSignalReason sigmode)
 
pid_t SignalVirtualTransaction (VirtualTransactionId vxid, ProcSignalReason sigmode, bool conflictPending)
 
bool MinimumActiveBackends (int min)
 
int CountDBBackends (Oid databaseid)
 
int CountDBConnections (Oid databaseid)
 
void CancelDBBackends (Oid databaseid, ProcSignalReason sigmode, bool conflictPending)
 
int CountUserBackends (Oid roleid)
 
bool CountOtherDBBackends (Oid databaseId, int *nbackends, int *nprepared)
 
void TerminateOtherDBBackends (Oid databaseId)
 
void ProcArraySetReplicationSlotXmin (TransactionId xmin, TransactionId catalog_xmin, bool already_locked)
 
void ProcArrayGetReplicationSlotXmin (TransactionId *xmin, TransactionId *catalog_xmin)
 
void XidCacheRemoveRunningXids (TransactionId xid, int nxids, const TransactionId *xids, TransactionId latestXid)
 
GlobalVisStateGlobalVisTestFor (Relation rel)
 
static bool GlobalVisTestShouldUpdate (GlobalVisState *state)
 
static void GlobalVisUpdate (void)
 
bool GlobalVisTestIsRemovableFullXid (GlobalVisState *state, FullTransactionId fxid)
 
bool GlobalVisTestIsRemovableXid (GlobalVisState *state, TransactionId xid)
 
FullTransactionId GlobalVisTestNonRemovableFullHorizon (GlobalVisState *state)
 
TransactionId GlobalVisTestNonRemovableHorizon (GlobalVisState *state)
 
bool GlobalVisCheckRemovableFullXid (Relation rel, FullTransactionId fxid)
 
bool GlobalVisCheckRemovableXid (Relation rel, TransactionId xid)
 
void RecordKnownAssignedTransactionIds (TransactionId xid)
 
void ExpireTreeKnownAssignedTransactionIds (TransactionId xid, int nsubxids, TransactionId *subxids, TransactionId max_xid)
 
void ExpireAllKnownAssignedTransactionIds (void)
 
void ExpireOldKnownAssignedTransactionIds (TransactionId xid)
 
void KnownAssignedTransactionIdsIdleMaintenance (void)
 

Variables

static ProcArrayStructprocArray
 
static PGPROCallProcs
 
static TransactionId cachedXidIsNotInProgress = InvalidTransactionId
 
static TransactionIdKnownAssignedXids
 
static boolKnownAssignedXidsValid
 
static TransactionId latestObservedXid = InvalidTransactionId
 
static TransactionId standbySnapshotPendingXmin
 
static GlobalVisState GlobalVisSharedRels
 
static GlobalVisState GlobalVisCatalogRels
 
static GlobalVisState GlobalVisDataRels
 
static GlobalVisState GlobalVisTempRels
 
static TransactionId ComputeXidHorizonsResultLastXmin
 

Macro Definition Documentation

◆ KAX_COMPRESS_FREQUENCY

#define KAX_COMPRESS_FREQUENCY   128 /* in transactions */

◆ KAX_COMPRESS_IDLE_INTERVAL

#define KAX_COMPRESS_IDLE_INTERVAL   1000 /* in ms */

◆ MAXAUTOVACPIDS

#define MAXAUTOVACPIDS   10 /* max autovacs to SIGTERM per iteration */

◆ PROCARRAY_MAXPROCS

#define PROCARRAY_MAXPROCS   (MaxBackends + max_prepared_xacts)

◆ TOTAL_MAX_CACHED_SUBXIDS

#define TOTAL_MAX_CACHED_SUBXIDS    ((PGPROC_MAX_CACHED_SUBXIDS + 1) * PROCARRAY_MAXPROCS)

◆ UINT32_ACCESS_ONCE

#define UINT32_ACCESS_ONCE (   var)    ((uint32)(*((volatile uint32 *)&(var))))

Definition at line 69 of file procarray.c.

◆ xc_by_child_xid_inc

#define xc_by_child_xid_inc ( )    ((void) 0)

Definition at line 341 of file procarray.c.

◆ xc_by_known_assigned_inc

#define xc_by_known_assigned_inc ( )    ((void) 0)

Definition at line 342 of file procarray.c.

◆ xc_by_known_xact_inc

#define xc_by_known_xact_inc ( )    ((void) 0)

Definition at line 337 of file procarray.c.

◆ xc_by_latest_xid_inc

#define xc_by_latest_xid_inc ( )    ((void) 0)

Definition at line 339 of file procarray.c.

◆ xc_by_main_xid_inc

#define xc_by_main_xid_inc ( )    ((void) 0)

Definition at line 340 of file procarray.c.

◆ xc_by_my_xact_inc

#define xc_by_my_xact_inc ( )    ((void) 0)

Definition at line 338 of file procarray.c.

◆ xc_by_recent_xmin_inc

#define xc_by_recent_xmin_inc ( )    ((void) 0)

Definition at line 336 of file procarray.c.

◆ xc_no_overflow_inc

#define xc_no_overflow_inc ( )    ((void) 0)

Definition at line 343 of file procarray.c.

◆ xc_slow_answer_inc

#define xc_slow_answer_inc ( )    ((void) 0)

Definition at line 344 of file procarray.c.

Typedef Documentation

◆ ComputeXidHorizonsResult

◆ GlobalVisHorizonKind

◆ KAXCompressReason

◆ ProcArrayStruct

Enumeration Type Documentation

◆ GlobalVisHorizonKind

Enumerator
VISHORIZON_SHARED 
VISHORIZON_CATALOG 
VISHORIZON_DATA 
VISHORIZON_TEMP 

Definition at line 250 of file procarray.c.

251 {
GlobalVisHorizonKind
Definition: procarray.c:251
@ VISHORIZON_SHARED
Definition: procarray.c:252
@ VISHORIZON_DATA
Definition: procarray.c:254
@ VISHORIZON_CATALOG
Definition: procarray.c:253
@ VISHORIZON_TEMP
Definition: procarray.c:255

◆ KAXCompressReason

Enumerator
KAX_NO_SPACE 
KAX_PRUNE 
KAX_TRANSACTION_END 
KAX_STARTUP_PROCESS_IDLE 

Definition at line 261 of file procarray.c.

262 {
263  KAX_NO_SPACE, /* need to free up space at array end */
264  KAX_PRUNE, /* we just pruned old entries */
265  KAX_TRANSACTION_END, /* we just committed/removed some XIDs */
266  KAX_STARTUP_PROCESS_IDLE /* startup process is about to sleep */
KAXCompressReason
Definition: procarray.c:262
@ KAX_PRUNE
Definition: procarray.c:264
@ KAX_NO_SPACE
Definition: procarray.c:263
@ KAX_TRANSACTION_END
Definition: procarray.c:265
@ KAX_STARTUP_PROCESS_IDLE
Definition: procarray.c:266

Function Documentation

◆ BackendPidGetProc()

PGPROC* BackendPidGetProc ( int  pid)

Definition at line 3103 of file procarray.c.

3104 {
3105  PGPROC *result;
3106 
3107  if (pid == 0) /* never match dummy PGPROCs */
3108  return NULL;
3109 
3110  LWLockAcquire(ProcArrayLock, LW_SHARED);
3111 
3112  result = BackendPidGetProcWithLock(pid);
3113 
3114  LWLockRelease(ProcArrayLock);
3115 
3116  return result;
3117 }
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1195
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
@ LW_SHARED
Definition: lwlock.h:117
PGPROC * BackendPidGetProcWithLock(int pid)
Definition: procarray.c:3126
Definition: proc.h:162

References BackendPidGetProcWithLock(), LW_SHARED, LWLockAcquire(), and LWLockRelease().

Referenced by IsBackendPid(), pg_log_backend_memory_contexts(), pg_signal_backend(), pg_stat_get_activity(), pg_stat_get_backend_wait_event(), pg_stat_get_backend_wait_event_type(), TerminateOtherDBBackends(), and test_shm_mq_main().

◆ BackendPidGetProcWithLock()

PGPROC* BackendPidGetProcWithLock ( int  pid)

Definition at line 3126 of file procarray.c.

3127 {
3128  PGPROC *result = NULL;
3129  ProcArrayStruct *arrayP = procArray;
3130  int index;
3131 
3132  if (pid == 0) /* never match dummy PGPROCs */
3133  return NULL;
3134 
3135  for (index = 0; index < arrayP->numProcs; index++)
3136  {
3137  PGPROC *proc = &allProcs[arrayP->pgprocnos[index]];
3138 
3139  if (proc->pid == pid)
3140  {
3141  result = proc;
3142  break;
3143  }
3144  }
3145 
3146  return result;
3147 }
static PGPROC * allProcs
Definition: procarray.c:272
static ProcArrayStruct * procArray
Definition: procarray.c:270
int pid
Definition: proc.h:186
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:100
Definition: type.h:95

References allProcs, ProcArrayStruct::numProcs, ProcArrayStruct::pgprocnos, PGPROC::pid, and procArray.

Referenced by BackendPidGetProc(), and GetBlockerStatusData().

◆ BackendXidGetPid()

int BackendXidGetPid ( TransactionId  xid)

Definition at line 3163 of file procarray.c.

3164 {
3165  int result = 0;
3166  ProcArrayStruct *arrayP = procArray;
3167  TransactionId *other_xids = ProcGlobal->xids;
3168  int index;
3169 
3170  if (xid == InvalidTransactionId) /* never match invalid xid */
3171  return 0;
3172 
3173  LWLockAcquire(ProcArrayLock, LW_SHARED);
3174 
3175  for (index = 0; index < arrayP->numProcs; index++)
3176  {
3177  if (other_xids[index] == xid)
3178  {
3179  int pgprocno = arrayP->pgprocnos[index];
3180  PGPROC *proc = &allProcs[pgprocno];
3181 
3182  result = proc->pid;
3183  break;
3184  }
3185  }
3186 
3187  LWLockRelease(ProcArrayLock);
3188 
3189  return result;
3190 }
uint32 TransactionId
Definition: c.h:641
PROC_HDR * ProcGlobal
Definition: proc.c:78
TransactionId * xids
Definition: proc.h:365
#define InvalidTransactionId
Definition: transam.h:31

References allProcs, InvalidTransactionId, LW_SHARED, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::numProcs, ProcArrayStruct::pgprocnos, PGPROC::pid, procArray, ProcGlobal, and PROC_HDR::xids.

Referenced by pgrowlocks().

◆ CancelDBBackends()

void CancelDBBackends ( Oid  databaseid,
ProcSignalReason  sigmode,
bool  conflictPending 
)

Definition at line 3567 of file procarray.c.

3568 {
3569  ProcArrayStruct *arrayP = procArray;
3570  int index;
3571 
3572  /* tell all backends to die */
3573  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3574 
3575  for (index = 0; index < arrayP->numProcs; index++)
3576  {
3577  int pgprocno = arrayP->pgprocnos[index];
3578  PGPROC *proc = &allProcs[pgprocno];
3579 
3580  if (databaseid == InvalidOid || proc->databaseId == databaseid)
3581  {
3582  VirtualTransactionId procvxid;
3583  pid_t pid;
3584 
3585  GET_VXID_FROM_PGPROC(procvxid, *proc);
3586 
3587  proc->recoveryConflictPending = conflictPending;
3588  pid = proc->pid;
3589  if (pid != 0)
3590  {
3591  /*
3592  * Kill the pid if it's still here. If not, that's what we
3593  * wanted so ignore any errors.
3594  */
3595  (void) SendProcSignal(pid, sigmode, procvxid.backendId);
3596  }
3597  }
3598  }
3599 
3600  LWLockRelease(ProcArrayLock);
3601 }
#define GET_VXID_FROM_PGPROC(vxid, proc)
Definition: lock.h:77
@ LW_EXCLUSIVE
Definition: lwlock.h:116
#define InvalidOid
Definition: postgres_ext.h:36
int SendProcSignal(pid_t pid, ProcSignalReason reason, BackendId backendId)
Definition: procsignal.c:262
bool recoveryConflictPending
Definition: proc.h:211
Oid databaseId
Definition: proc.h:198
BackendId backendId
Definition: lock.h:61

References allProcs, VirtualTransactionId::backendId, PGPROC::databaseId, GET_VXID_FROM_PGPROC, InvalidOid, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::numProcs, ProcArrayStruct::pgprocnos, PGPROC::pid, procArray, PGPROC::recoveryConflictPending, and SendProcSignal().

Referenced by ResolveRecoveryConflictWithDatabase(), and SendRecoveryConflictWithBufferPin().

◆ CancelVirtualTransaction()

pid_t CancelVirtualTransaction ( VirtualTransactionId  vxid,
ProcSignalReason  sigmode 
)

Definition at line 3398 of file procarray.c.

3399 {
3400  return SignalVirtualTransaction(vxid, sigmode, true);
3401 }
pid_t SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode, bool conflictPending)
Definition: procarray.c:3404

References SignalVirtualTransaction().

Referenced by ResolveRecoveryConflictWithVirtualXIDs().

◆ ComputeXidHorizons()

static void ComputeXidHorizons ( ComputeXidHorizonsResult h)
static

Definition at line 1716 of file procarray.c.

1717 {
1718  ProcArrayStruct *arrayP = procArray;
1719  TransactionId kaxmin;
1720  bool in_recovery = RecoveryInProgress();
1721  TransactionId *other_xids = ProcGlobal->xids;
1722 
1723  /* inferred after ProcArrayLock is released */
1725 
1726  LWLockAcquire(ProcArrayLock, LW_SHARED);
1727 
1729 
1730  /*
1731  * We initialize the MIN() calculation with latestCompletedXid + 1. This
1732  * is a lower bound for the XIDs that might appear in the ProcArray later,
1733  * and so protects us against overestimating the result due to future
1734  * additions.
1735  */
1736  {
1737  TransactionId initial;
1738 
1740  Assert(TransactionIdIsValid(initial));
1741  TransactionIdAdvance(initial);
1742 
1743  h->oldest_considered_running = initial;
1744  h->shared_oldest_nonremovable = initial;
1745  h->data_oldest_nonremovable = initial;
1746 
1747  /*
1748  * Only modifications made by this backend affect the horizon for
1749  * temporary relations. Instead of a check in each iteration of the
1750  * loop over all PGPROCs it is cheaper to just initialize to the
1751  * current top-level xid any.
1752  *
1753  * Without an assigned xid we could use a horizon as aggressive as
1754  * GetNewTransactionId(), but we can get away with the much cheaper
1755  * latestCompletedXid + 1: If this backend has no xid there, by
1756  * definition, can't be any newer changes in the temp table than
1757  * latestCompletedXid.
1758  */
1761  else
1762  h->temp_oldest_nonremovable = initial;
1763  }
1764 
1765  /*
1766  * Fetch slot horizons while ProcArrayLock is held - the
1767  * LWLockAcquire/LWLockRelease are a barrier, ensuring this happens inside
1768  * the lock.
1769  */
1772 
1773  for (int index = 0; index < arrayP->numProcs; index++)
1774  {
1775  int pgprocno = arrayP->pgprocnos[index];
1776  PGPROC *proc = &allProcs[pgprocno];
1777  int8 statusFlags = ProcGlobal->statusFlags[index];
1778  TransactionId xid;
1779  TransactionId xmin;
1780 
1781  /* Fetch xid just once - see GetNewTransactionId */
1782  xid = UINT32_ACCESS_ONCE(other_xids[index]);
1783  xmin = UINT32_ACCESS_ONCE(proc->xmin);
1784 
1785  /*
1786  * Consider both the transaction's Xmin, and its Xid.
1787  *
1788  * We must check both because a transaction might have an Xmin but not
1789  * (yet) an Xid; conversely, if it has an Xid, that could determine
1790  * some not-yet-set Xmin.
1791  */
1792  xmin = TransactionIdOlder(xmin, xid);
1793 
1794  /* if neither is set, this proc doesn't influence the horizon */
1795  if (!TransactionIdIsValid(xmin))
1796  continue;
1797 
1798  /*
1799  * Don't ignore any procs when determining which transactions might be
1800  * considered running. While slots should ensure logical decoding
1801  * backends are protected even without this check, it can't hurt to
1802  * include them here as well..
1803  */
1806 
1807  /*
1808  * Skip over backends either vacuuming (which is ok with rows being
1809  * removed, as long as pg_subtrans is not truncated) or doing logical
1810  * decoding (which manages xmin separately, check below).
1811  */
1812  if (statusFlags & (PROC_IN_VACUUM | PROC_IN_LOGICAL_DECODING))
1813  continue;
1814 
1815  /* shared tables need to take backends in all databases into account */
1818 
1819  /*
1820  * Normally sessions in other databases are ignored for anything but
1821  * the shared horizon.
1822  *
1823  * However, include them when MyDatabaseId is not (yet) set. A
1824  * backend in the process of starting up must not compute a "too
1825  * aggressive" horizon, otherwise we could end up using it to prune
1826  * still-needed data away. If the current backend never connects to a
1827  * database this is harmless, because data_oldest_nonremovable will
1828  * never be utilized.
1829  *
1830  * Also, sessions marked with PROC_AFFECTS_ALL_HORIZONS should always
1831  * be included. (This flag is used for hot standby feedback, which
1832  * can't be tied to a specific database.)
1833  *
1834  * Also, while in recovery we cannot compute an accurate per-database
1835  * horizon, as all xids are managed via the KnownAssignedXids
1836  * machinery.
1837  */
1838  if (proc->databaseId == MyDatabaseId ||
1839  MyDatabaseId == InvalidOid ||
1840  (statusFlags & PROC_AFFECTS_ALL_HORIZONS) ||
1841  in_recovery)
1842  {
1845  }
1846  }
1847 
1848  /*
1849  * If in recovery fetch oldest xid in KnownAssignedXids, will be applied
1850  * after lock is released.
1851  */
1852  if (in_recovery)
1853  kaxmin = KnownAssignedXidsGetOldestXmin();
1854 
1855  /*
1856  * No other information from shared state is needed, release the lock
1857  * immediately. The rest of the computations can be done without a lock.
1858  */
1859  LWLockRelease(ProcArrayLock);
1860 
1861  if (in_recovery)
1862  {
1869  /* temp relations cannot be accessed in recovery */
1870  }
1871 
1876 
1877  /*
1878  * Check whether there are replication slots requiring an older xmin.
1879  */
1884 
1885  /*
1886  * The only difference between catalog / data horizons is that the slot's
1887  * catalog xmin is applied to the catalog one (so catalogs can be accessed
1888  * for logical decoding). Initialize with data horizon, and then back up
1889  * further if necessary. Have to back up the shared horizon as well, since
1890  * that also can contain catalogs.
1891  */
1895  h->slot_catalog_xmin);
1899  h->slot_catalog_xmin);
1900 
1901  /*
1902  * It's possible that slots backed up the horizons further than
1903  * oldest_considered_running. Fix.
1904  */
1914 
1915  /*
1916  * shared horizons have to be at least as old as the oldest visible in
1917  * current db
1918  */
1923 
1924  /*
1925  * Horizons need to ensure that pg_subtrans access is still possible for
1926  * the relevant backends.
1927  */
1938  h->slot_xmin));
1941  h->slot_catalog_xmin));
1942 
1943  /* update approximate horizons with the computed horizons */
1945 }
signed char int8
Definition: c.h:481
Oid MyDatabaseId
Definition: globals.c:89
Assert(fmt[strlen(fmt) - 1] !='\n')
#define PROC_IN_LOGICAL_DECODING
Definition: proc.h:60
#define PROC_AFFECTS_ALL_HORIZONS
Definition: proc.h:61
#define PROC_IN_VACUUM
Definition: proc.h:57
#define UINT32_ACCESS_ONCE(var)
Definition: procarray.c:69
static void GlobalVisUpdateApply(ComputeXidHorizonsResult *horizons)
Definition: procarray.c:4070
static TransactionId KnownAssignedXidsGetOldestXmin(void)
Definition: procarray.c:5093
PGPROC * MyProc
Definition: proc.c:66
TransactionId slot_catalog_xmin
Definition: procarray.c:193
TransactionId data_oldest_nonremovable
Definition: procarray.c:238
TransactionId temp_oldest_nonremovable
Definition: procarray.c:244
TransactionId shared_oldest_nonremovable
Definition: procarray.c:215
TransactionId oldest_considered_running
Definition: procarray.c:206
TransactionId slot_xmin
Definition: procarray.c:192
FullTransactionId latest_completed
Definition: procarray.c:186
TransactionId catalog_oldest_nonremovable
Definition: procarray.c:232
TransactionId shared_oldest_nonremovable_raw
Definition: procarray.c:226
TransactionId xmin
Definition: proc.h:178
TransactionId xid
Definition: proc.h:173
uint8 * statusFlags
Definition: proc.h:377
TransactionId replication_slot_xmin
Definition: procarray.c:95
TransactionId replication_slot_catalog_xmin
Definition: procarray.c:97
FullTransactionId latestCompletedXid
Definition: transam.h:238
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:299
#define XidFromFullTransactionId(x)
Definition: transam.h:48
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define TransactionIdAdvance(dest)
Definition: transam.h:91
static TransactionId TransactionIdOlder(TransactionId a, TransactionId b)
Definition: transam.h:334
VariableCache ShmemVariableCache
Definition: varsup.c:34
bool RecoveryInProgress(void)
Definition: xlog.c:5948

References allProcs, Assert(), ComputeXidHorizonsResult::catalog_oldest_nonremovable, ComputeXidHorizonsResult::data_oldest_nonremovable, PGPROC::databaseId, GlobalVisUpdateApply(), InvalidOid, InvalidTransactionId, KnownAssignedXidsGetOldestXmin(), ComputeXidHorizonsResult::latest_completed, VariableCacheData::latestCompletedXid, LW_SHARED, LWLockAcquire(), LWLockRelease(), MyDatabaseId, MyProc, ProcArrayStruct::numProcs, ComputeXidHorizonsResult::oldest_considered_running, ProcArrayStruct::pgprocnos, PROC_AFFECTS_ALL_HORIZONS, PROC_IN_LOGICAL_DECODING, PROC_IN_VACUUM, procArray, ProcGlobal, RecoveryInProgress(), ProcArrayStruct::replication_slot_catalog_xmin, ProcArrayStruct::replication_slot_xmin, ComputeXidHorizonsResult::shared_oldest_nonremovable, ComputeXidHorizonsResult::shared_oldest_nonremovable_raw, ShmemVariableCache, ComputeXidHorizonsResult::slot_catalog_xmin, ComputeXidHorizonsResult::slot_xmin, PROC_HDR::statusFlags, ComputeXidHorizonsResult::temp_oldest_nonremovable, TransactionIdAdvance, TransactionIdIsValid, TransactionIdOlder(), TransactionIdPrecedesOrEquals(), UINT32_ACCESS_ONCE, PGPROC::xid, XidFromFullTransactionId, PROC_HDR::xids, and PGPROC::xmin.

Referenced by GetOldestNonRemovableTransactionId(), GetOldestTransactionIdConsideredRunning(), GetReplicationHorizons(), and GlobalVisUpdate().

◆ CountDBBackends()

int CountDBBackends ( Oid  databaseid)

Definition at line 3506 of file procarray.c.

3507 {
3508  ProcArrayStruct *arrayP = procArray;
3509  int count = 0;
3510  int index;
3511 
3512  LWLockAcquire(ProcArrayLock, LW_SHARED);
3513 
3514  for (index = 0; index < arrayP->numProcs; index++)
3515  {
3516  int pgprocno = arrayP->pgprocnos[index];
3517  PGPROC *proc = &allProcs[pgprocno];
3518 
3519  if (proc->pid == 0)
3520  continue; /* do not count prepared xacts */
3521  if (!OidIsValid(databaseid) ||
3522  proc->databaseId == databaseid)
3523  count++;
3524  }
3525 
3526  LWLockRelease(ProcArrayLock);
3527 
3528  return count;
3529 }
#define OidIsValid(objectId)
Definition: c.h:764

References allProcs, PGPROC::databaseId, LW_SHARED, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::numProcs, OidIsValid, ProcArrayStruct::pgprocnos, PGPROC::pid, and procArray.

Referenced by ResolveRecoveryConflictWithDatabase().

◆ CountDBConnections()

int CountDBConnections ( Oid  databaseid)

Definition at line 3536 of file procarray.c.

3537 {
3538  ProcArrayStruct *arrayP = procArray;
3539  int count = 0;
3540  int index;
3541 
3542  LWLockAcquire(ProcArrayLock, LW_SHARED);
3543 
3544  for (index = 0; index < arrayP->numProcs; index++)
3545  {
3546  int pgprocno = arrayP->pgprocnos[index];
3547  PGPROC *proc = &allProcs[pgprocno];
3548 
3549  if (proc->pid == 0)
3550  continue; /* do not count prepared xacts */
3551  if (proc->isBackgroundWorker)
3552  continue; /* do not count background workers */
3553  if (!OidIsValid(databaseid) ||
3554  proc->databaseId == databaseid)
3555  count++;
3556  }
3557 
3558  LWLockRelease(ProcArrayLock);
3559 
3560  return count;
3561 }
bool isBackgroundWorker
Definition: proc.h:204

References allProcs, PGPROC::databaseId, PGPROC::isBackgroundWorker, LW_SHARED, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::numProcs, OidIsValid, ProcArrayStruct::pgprocnos, PGPROC::pid, and procArray.

Referenced by CheckMyDatabase().

◆ CountOtherDBBackends()

bool CountOtherDBBackends ( Oid  databaseId,
int *  nbackends,
int *  nprepared 
)

Definition at line 3657 of file procarray.c.

3658 {
3659  ProcArrayStruct *arrayP = procArray;
3660 
3661 #define MAXAUTOVACPIDS 10 /* max autovacs to SIGTERM per iteration */
3662  int autovac_pids[MAXAUTOVACPIDS];
3663  int tries;
3664 
3665  /* 50 tries with 100ms sleep between tries makes 5 sec total wait */
3666  for (tries = 0; tries < 50; tries++)
3667  {
3668  int nautovacs = 0;
3669  bool found = false;
3670  int index;
3671 
3673 
3674  *nbackends = *nprepared = 0;
3675 
3676  LWLockAcquire(ProcArrayLock, LW_SHARED);
3677 
3678  for (index = 0; index < arrayP->numProcs; index++)
3679  {
3680  int pgprocno = arrayP->pgprocnos[index];
3681  PGPROC *proc = &allProcs[pgprocno];
3682  uint8 statusFlags = ProcGlobal->statusFlags[index];
3683 
3684  if (proc->databaseId != databaseId)
3685  continue;
3686  if (proc == MyProc)
3687  continue;
3688 
3689  found = true;
3690 
3691  if (proc->pid == 0)
3692  (*nprepared)++;
3693  else
3694  {
3695  (*nbackends)++;
3696  if ((statusFlags & PROC_IS_AUTOVACUUM) &&
3697  nautovacs < MAXAUTOVACPIDS)
3698  autovac_pids[nautovacs++] = proc->pid;
3699  }
3700  }
3701 
3702  LWLockRelease(ProcArrayLock);
3703 
3704  if (!found)
3705  return false; /* no conflicting backends, so done */
3706 
3707  /*
3708  * Send SIGTERM to any conflicting autovacuums before sleeping. We
3709  * postpone this step until after the loop because we don't want to
3710  * hold ProcArrayLock while issuing kill(). We have no idea what might
3711  * block kill() inside the kernel...
3712  */
3713  for (index = 0; index < nautovacs; index++)
3714  (void) kill(autovac_pids[index], SIGTERM); /* ignore any error */
3715 
3716  /* sleep, then try again */
3717  pg_usleep(100 * 1000L); /* 100ms */
3718  }
3719 
3720  return true; /* timed out, still conflicts */
3721 }
unsigned char uint8
Definition: c.h:493
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121
#define PROC_IS_AUTOVACUUM
Definition: proc.h:56
#define MAXAUTOVACPIDS
void pg_usleep(long microsec)
Definition: signal.c:53
#define kill(pid, sig)
Definition: win32_port.h:485

References allProcs, CHECK_FOR_INTERRUPTS, PGPROC::databaseId, kill, LW_SHARED, LWLockAcquire(), LWLockRelease(), MAXAUTOVACPIDS, MyProc, ProcArrayStruct::numProcs, pg_usleep(), ProcArrayStruct::pgprocnos, PGPROC::pid, PROC_IS_AUTOVACUUM, procArray, ProcGlobal, and PROC_HDR::statusFlags.

Referenced by createdb(), dropdb(), movedb(), and RenameDatabase().

◆ CountUserBackends()

int CountUserBackends ( Oid  roleid)

Definition at line 3607 of file procarray.c.

3608 {
3609  ProcArrayStruct *arrayP = procArray;
3610  int count = 0;
3611  int index;
3612 
3613  LWLockAcquire(ProcArrayLock, LW_SHARED);
3614 
3615  for (index = 0; index < arrayP->numProcs; index++)
3616  {
3617  int pgprocno = arrayP->pgprocnos[index];
3618  PGPROC *proc = &allProcs[pgprocno];
3619 
3620  if (proc->pid == 0)
3621  continue; /* do not count prepared xacts */
3622  if (proc->isBackgroundWorker)
3623  continue; /* do not count background workers */
3624  if (proc->roleId == roleid)
3625  count++;
3626  }
3627 
3628  LWLockRelease(ProcArrayLock);
3629 
3630  return count;
3631 }
Oid roleId
Definition: proc.h:199

References allProcs, PGPROC::isBackgroundWorker, LW_SHARED, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::numProcs, ProcArrayStruct::pgprocnos, PGPROC::pid, procArray, and PGPROC::roleId.

Referenced by InitializeSessionUserId().

◆ CreateSharedProcArray()

void CreateSharedProcArray ( void  )

Definition at line 419 of file procarray.c.

420 {
421  bool found;
422 
423  /* Create or attach to the ProcArray shared structure */
425  ShmemInitStruct("Proc Array",
426  add_size(offsetof(ProcArrayStruct, pgprocnos),
427  mul_size(sizeof(int),
429  &found);
430 
431  if (!found)
432  {
433  /*
434  * We're the first - initialize.
435  */
436  procArray->numProcs = 0;
446  }
447 
449 
450  /* Create or attach to the KnownAssignedXids arrays too, if needed */
451  if (EnableHotStandby)
452  {
454  ShmemInitStruct("KnownAssignedXids",
455  mul_size(sizeof(TransactionId),
457  &found);
458  KnownAssignedXidsValid = (bool *)
459  ShmemInitStruct("KnownAssignedXidsValid",
460  mul_size(sizeof(bool), TOTAL_MAX_CACHED_SUBXIDS),
461  &found);
462  }
463 }
#define TOTAL_MAX_CACHED_SUBXIDS
#define PROCARRAY_MAXPROCS
static TransactionId * KnownAssignedXids
Definition: procarray.c:282
static bool * KnownAssignedXidsValid
Definition: procarray.c:283
Size add_size(Size s1, Size s2)
Definition: shmem.c:502
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:396
Size mul_size(Size s1, Size s2)
Definition: shmem.c:519
PGPROC * allProcs
Definition: proc.h:362
int maxKnownAssignedXids
Definition: procarray.c:80
int numKnownAssignedXids
Definition: procarray.c:81
TransactionId lastOverflowedXid
Definition: procarray.c:92
int tailKnownAssignedXids
Definition: procarray.c:82
int headKnownAssignedXids
Definition: procarray.c:83
uint64 xactCompletionCount
Definition: transam.h:248
bool EnableHotStandby
Definition: xlog.c:124

References add_size(), allProcs, PROC_HDR::allProcs, EnableHotStandby, ProcArrayStruct::headKnownAssignedXids, InvalidTransactionId, KnownAssignedXids, KnownAssignedXidsValid, ProcArrayStruct::lastOverflowedXid, ProcArrayStruct::maxKnownAssignedXids, ProcArrayStruct::maxProcs, mul_size(), ProcArrayStruct::numKnownAssignedXids, ProcArrayStruct::numProcs, procArray, PROCARRAY_MAXPROCS, ProcGlobal, ProcArrayStruct::replication_slot_catalog_xmin, ProcArrayStruct::replication_slot_xmin, ShmemInitStruct(), ShmemVariableCache, ProcArrayStruct::tailKnownAssignedXids, TOTAL_MAX_CACHED_SUBXIDS, and VariableCacheData::xactCompletionCount.

Referenced by CreateSharedMemoryAndSemaphores().

◆ ExpireAllKnownAssignedTransactionIds()

void ExpireAllKnownAssignedTransactionIds ( void  )

Definition at line 4432 of file procarray.c.

4433 {
4434  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4436 
4437  /*
4438  * Reset lastOverflowedXid. Currently, lastOverflowedXid has no use after
4439  * the call of this function. But do this for unification with what
4440  * ExpireOldKnownAssignedTransactionIds() do.
4441  */
4443  LWLockRelease(ProcArrayLock);
4444 }
static void KnownAssignedXidsRemovePreceding(TransactionId removeXid)
Definition: procarray.c:4945

References InvalidTransactionId, KnownAssignedXidsRemovePreceding(), ProcArrayStruct::lastOverflowedXid, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), and procArray.

Referenced by ShutdownRecoveryTransactionEnvironment().

◆ ExpireOldKnownAssignedTransactionIds()

void ExpireOldKnownAssignedTransactionIds ( TransactionId  xid)

Definition at line 4452 of file procarray.c.

4453 {
4454  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4455 
4456  /*
4457  * Reset lastOverflowedXid if we know all transactions that have been
4458  * possibly running are being gone. Not doing so could cause an incorrect
4459  * lastOverflowedXid value, which makes extra snapshots be marked as
4460  * suboverflowed.
4461  */
4465  LWLockRelease(ProcArrayLock);
4466 }
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:280

References InvalidTransactionId, KnownAssignedXidsRemovePreceding(), ProcArrayStruct::lastOverflowedXid, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), procArray, and TransactionIdPrecedes().

Referenced by ProcArrayApplyRecoveryInfo().

◆ ExpireTreeKnownAssignedTransactionIds()

void ExpireTreeKnownAssignedTransactionIds ( TransactionId  xid,
int  nsubxids,
TransactionId subxids,
TransactionId  max_xid 
)

Definition at line 4406 of file procarray.c.

4408 {
4410 
4411  /*
4412  * Uses same locking as transaction commit
4413  */
4414  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4415 
4416  KnownAssignedXidsRemoveTree(xid, nsubxids, subxids);
4417 
4418  /* As in ProcArrayEndTransaction, advance latestCompletedXid */
4420 
4421  /* ... and xactCompletionCount */
4423 
4424  LWLockRelease(ProcArrayLock);
4425 }
static void KnownAssignedXidsRemoveTree(TransactionId xid, int nsubxids, TransactionId *subxids)
Definition: procarray.c:4923
static void MaintainLatestCompletedXidRecovery(TransactionId latestXid)
Definition: procarray.c:988
HotStandbyState standbyState
Definition: xlogutils.c:56
@ STANDBY_INITIALIZED
Definition: xlogutils.h:50

References Assert(), KnownAssignedXidsRemoveTree(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MaintainLatestCompletedXidRecovery(), ShmemVariableCache, STANDBY_INITIALIZED, standbyState, and VariableCacheData::xactCompletionCount.

Referenced by xact_redo_abort(), and xact_redo_commit().

◆ FullXidRelativeTo()

static FullTransactionId FullXidRelativeTo ( FullTransactionId  rel,
TransactionId  xid 
)
inlinestatic

Definition at line 4255 of file procarray.c.

4256 {
4257  TransactionId rel_xid = XidFromFullTransactionId(rel);
4258 
4260  Assert(TransactionIdIsValid(rel_xid));
4261 
4262  /* not guaranteed to find issues, but likely to catch mistakes */
4264 
4266  + (int32) (xid - rel_xid));
4267 }
signed int int32
Definition: c.h:483
#define U64FromFullTransactionId(x)
Definition: transam.h:49
static FullTransactionId FullTransactionIdFromU64(uint64 value)
Definition: transam.h:81
#define AssertTransactionIdInAllowableRange(xid)
Definition: transam.h:301

References Assert(), AssertTransactionIdInAllowableRange, FullTransactionIdFromU64(), TransactionIdIsValid, U64FromFullTransactionId, and XidFromFullTransactionId.

Referenced by GetSnapshotData(), GlobalVisTestIsRemovableXid(), GlobalVisUpdateApply(), MaintainLatestCompletedXid(), and MaintainLatestCompletedXidRecovery().

◆ GetConflictingVirtualXIDs()

VirtualTransactionId* GetConflictingVirtualXIDs ( TransactionId  limitXmin,
Oid  dbOid 
)

Definition at line 3324 of file procarray.c.

3325 {
3326  static VirtualTransactionId *vxids;
3327  ProcArrayStruct *arrayP = procArray;
3328  int count = 0;
3329  int index;
3330 
3331  /*
3332  * If first time through, get workspace to remember main XIDs in. We
3333  * malloc it permanently to avoid repeated palloc/pfree overhead. Allow
3334  * result space, remembering room for a terminator.
3335  */
3336  if (vxids == NULL)
3337  {
3338  vxids = (VirtualTransactionId *)
3339  malloc(sizeof(VirtualTransactionId) * (arrayP->maxProcs + 1));
3340  if (vxids == NULL)
3341  ereport(ERROR,
3342  (errcode(ERRCODE_OUT_OF_MEMORY),
3343  errmsg("out of memory")));
3344  }
3345 
3346  LWLockAcquire(ProcArrayLock, LW_SHARED);
3347 
3348  for (index = 0; index < arrayP->numProcs; index++)
3349  {
3350  int pgprocno = arrayP->pgprocnos[index];
3351  PGPROC *proc = &allProcs[pgprocno];
3352 
3353  /* Exclude prepared transactions */
3354  if (proc->pid == 0)
3355  continue;
3356 
3357  if (!OidIsValid(dbOid) ||
3358  proc->databaseId == dbOid)
3359  {
3360  /* Fetch xmin just once - can't change on us, but good coding */
3361  TransactionId pxmin = UINT32_ACCESS_ONCE(proc->xmin);
3362 
3363  /*
3364  * We ignore an invalid pxmin because this means that backend has
3365  * no snapshot currently. We hold a Share lock to avoid contention
3366  * with users taking snapshots. That is not a problem because the
3367  * current xmin is always at least one higher than the latest
3368  * removed xid, so any new snapshot would never conflict with the
3369  * test here.
3370  */
3371  if (!TransactionIdIsValid(limitXmin) ||
3372  (TransactionIdIsValid(pxmin) && !TransactionIdFollows(pxmin, limitXmin)))
3373  {
3374  VirtualTransactionId vxid;
3375 
3376  GET_VXID_FROM_PGPROC(vxid, *proc);
3377  if (VirtualTransactionIdIsValid(vxid))
3378  vxids[count++] = vxid;
3379  }
3380  }
3381  }
3382 
3383  LWLockRelease(ProcArrayLock);
3384 
3385  /* add the terminator */
3386  vxids[count].backendId = InvalidBackendId;
3388 
3389  return vxids;
3390 }
#define InvalidBackendId
Definition: backendid.h:23
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#define malloc(a)
Definition: header.h:50
#define VirtualTransactionIdIsValid(vxid)
Definition: lock.h:67
#define InvalidLocalTransactionId
Definition: lock.h:65
LocalTransactionId localTransactionId
Definition: lock.h:62
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:314

References allProcs, VirtualTransactionId::backendId, PGPROC::databaseId, ereport, errcode(), errmsg(), ERROR, GET_VXID_FROM_PGPROC, InvalidBackendId, InvalidLocalTransactionId, VirtualTransactionId::localTransactionId, LW_SHARED, LWLockAcquire(), LWLockRelease(), malloc, ProcArrayStruct::maxProcs, ProcArrayStruct::numProcs, OidIsValid, ProcArrayStruct::pgprocnos, PGPROC::pid, procArray, TransactionIdFollows(), TransactionIdIsValid, UINT32_ACCESS_ONCE, VirtualTransactionIdIsValid, and PGPROC::xmin.

Referenced by ResolveRecoveryConflictWithSnapshot(), and ResolveRecoveryConflictWithTablespace().

◆ GetCurrentVirtualXIDs()

VirtualTransactionId* GetCurrentVirtualXIDs ( TransactionId  limitXmin,
bool  excludeXmin0,
bool  allDbs,
int  excludeVacuum,
int *  nvxids 
)

Definition at line 3231 of file procarray.c.

3234 {
3235  VirtualTransactionId *vxids;
3236  ProcArrayStruct *arrayP = procArray;
3237  int count = 0;
3238  int index;
3239 
3240  /* allocate what's certainly enough result space */
3241  vxids = (VirtualTransactionId *)
3242  palloc(sizeof(VirtualTransactionId) * arrayP->maxProcs);
3243 
3244  LWLockAcquire(ProcArrayLock, LW_SHARED);
3245 
3246  for (index = 0; index < arrayP->numProcs; index++)
3247  {
3248  int pgprocno = arrayP->pgprocnos[index];
3249  PGPROC *proc = &allProcs[pgprocno];
3250  uint8 statusFlags = ProcGlobal->statusFlags[index];
3251 
3252  if (proc == MyProc)
3253  continue;
3254 
3255  if (excludeVacuum & statusFlags)
3256  continue;
3257 
3258  if (allDbs || proc->databaseId == MyDatabaseId)
3259  {
3260  /* Fetch xmin just once - might change on us */
3261  TransactionId pxmin = UINT32_ACCESS_ONCE(proc->xmin);
3262 
3263  if (excludeXmin0 && !TransactionIdIsValid(pxmin))
3264  continue;
3265 
3266  /*
3267  * InvalidTransactionId precedes all other XIDs, so a proc that
3268  * hasn't set xmin yet will not be rejected by this test.
3269  */
3270  if (!TransactionIdIsValid(limitXmin) ||
3271  TransactionIdPrecedesOrEquals(pxmin, limitXmin))
3272  {
3273  VirtualTransactionId vxid;
3274 
3275  GET_VXID_FROM_PGPROC(vxid, *proc);
3276  if (VirtualTransactionIdIsValid(vxid))
3277  vxids[count++] = vxid;
3278  }
3279  }
3280  }
3281 
3282  LWLockRelease(ProcArrayLock);
3283 
3284  *nvxids = count;
3285  return vxids;
3286 }
void * palloc(Size size)
Definition: mcxt.c:1226

References allProcs, PGPROC::databaseId, GET_VXID_FROM_PGPROC, LW_SHARED, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::maxProcs, MyDatabaseId, MyProc, ProcArrayStruct::numProcs, palloc(), ProcArrayStruct::pgprocnos, procArray, ProcGlobal, PROC_HDR::statusFlags, TransactionIdIsValid, TransactionIdPrecedesOrEquals(), UINT32_ACCESS_ONCE, VirtualTransactionIdIsValid, and PGPROC::xmin.

Referenced by WaitForOlderSnapshots().

◆ GetMaxSnapshotSubxidCount()

int GetMaxSnapshotSubxidCount ( void  )

Definition at line 2061 of file procarray.c.

2062 {
2063  return TOTAL_MAX_CACHED_SUBXIDS;
2064 }

References TOTAL_MAX_CACHED_SUBXIDS.

Referenced by ExportSnapshot(), GetSnapshotData(), ImportSnapshot(), and SetTransactionSnapshot().

◆ GetMaxSnapshotXidCount()

int GetMaxSnapshotXidCount ( void  )

Definition at line 2050 of file procarray.c.

2051 {
2052  return procArray->maxProcs;
2053 }

References ProcArrayStruct::maxProcs, and procArray.

Referenced by GetSnapshotData(), ImportSnapshot(), SetTransactionSnapshot(), and SnapBuildInitialSnapshot().

◆ GetOldestActiveTransactionId()

TransactionId GetOldestActiveTransactionId ( void  )

Definition at line 2845 of file procarray.c.

2846 {
2847  ProcArrayStruct *arrayP = procArray;
2848  TransactionId *other_xids = ProcGlobal->xids;
2849  TransactionId oldestRunningXid;
2850  int index;
2851 
2853 
2854  /*
2855  * Read nextXid, as the upper bound of what's still active.
2856  *
2857  * Reading a TransactionId is atomic, but we must grab the lock to make
2858  * sure that all XIDs < nextXid are already present in the proc array (or
2859  * have already completed), when we spin over it.
2860  */
2861  LWLockAcquire(XidGenLock, LW_SHARED);
2863  LWLockRelease(XidGenLock);
2864 
2865  /*
2866  * Spin over procArray collecting all xids and subxids.
2867  */
2868  LWLockAcquire(ProcArrayLock, LW_SHARED);
2869  for (index = 0; index < arrayP->numProcs; index++)
2870  {
2871  TransactionId xid;
2872 
2873  /* Fetch xid just once - see GetNewTransactionId */
2874  xid = UINT32_ACCESS_ONCE(other_xids[index]);
2875 
2876  if (!TransactionIdIsNormal(xid))
2877  continue;
2878 
2879  if (TransactionIdPrecedes(xid, oldestRunningXid))
2880  oldestRunningXid = xid;
2881 
2882  /*
2883  * Top-level XID of a transaction is always less than any of its
2884  * subxids, so we don't need to check if any of the subxids are
2885  * smaller than oldestRunningXid
2886  */
2887  }
2888  LWLockRelease(ProcArrayLock);
2889 
2890  return oldestRunningXid;
2891 }
FullTransactionId nextXid
Definition: transam.h:220
#define TransactionIdIsNormal(xid)
Definition: transam.h:42

References Assert(), LW_SHARED, LWLockAcquire(), LWLockRelease(), VariableCacheData::nextXid, ProcArrayStruct::numProcs, procArray, ProcGlobal, RecoveryInProgress(), ShmemVariableCache, TransactionIdIsNormal, TransactionIdPrecedes(), UINT32_ACCESS_ONCE, XidFromFullTransactionId, and PROC_HDR::xids.

Referenced by CreateCheckPoint().

◆ GetOldestNonRemovableTransactionId()

TransactionId GetOldestNonRemovableTransactionId ( Relation  rel)

Definition at line 1986 of file procarray.c.

1987 {
1988  ComputeXidHorizonsResult horizons;
1989 
1990  ComputeXidHorizons(&horizons);
1991 
1992  switch (GlobalVisHorizonKindForRel(rel))
1993  {
1994  case VISHORIZON_SHARED:
1995  return horizons.shared_oldest_nonremovable;
1996  case VISHORIZON_CATALOG:
1997  return horizons.catalog_oldest_nonremovable;
1998  case VISHORIZON_DATA:
1999  return horizons.data_oldest_nonremovable;
2000  case VISHORIZON_TEMP:
2001  return horizons.temp_oldest_nonremovable;
2002  }
2003 
2004  /* just to prevent compiler warnings */
2005  return InvalidTransactionId;
2006 }
static void ComputeXidHorizons(ComputeXidHorizonsResult *h)
Definition: procarray.c:1716
static GlobalVisHorizonKind GlobalVisHorizonKindForRel(Relation rel)
Definition: procarray.c:1952

References ComputeXidHorizonsResult::catalog_oldest_nonremovable, ComputeXidHorizons(), ComputeXidHorizonsResult::data_oldest_nonremovable, GlobalVisHorizonKindForRel(), InvalidTransactionId, ComputeXidHorizonsResult::shared_oldest_nonremovable, ComputeXidHorizonsResult::temp_oldest_nonremovable, VISHORIZON_CATALOG, VISHORIZON_DATA, VISHORIZON_SHARED, and VISHORIZON_TEMP.

Referenced by _bt_pendingfsm_finalize(), acquire_sample_rows(), collect_corrupt_items(), heapam_index_build_range_scan(), statapprox_heap(), vac_update_datfrozenxid(), and vacuum_get_cutoffs().

◆ GetOldestSafeDecodingTransactionId()

TransactionId GetOldestSafeDecodingTransactionId ( bool  catalogOnly)

Definition at line 2910 of file procarray.c.

2911 {
2912  ProcArrayStruct *arrayP = procArray;
2913  TransactionId oldestSafeXid;
2914  int index;
2915  bool recovery_in_progress = RecoveryInProgress();
2916 
2917  Assert(LWLockHeldByMe(ProcArrayLock));
2918 
2919  /*
2920  * Acquire XidGenLock, so no transactions can acquire an xid while we're
2921  * running. If no transaction with xid were running concurrently a new xid
2922  * could influence the RecentXmin et al.
2923  *
2924  * We initialize the computation to nextXid since that's guaranteed to be
2925  * a safe, albeit pessimal, value.
2926  */
2927  LWLockAcquire(XidGenLock, LW_SHARED);
2929 
2930  /*
2931  * If there's already a slot pegging the xmin horizon, we can start with
2932  * that value, it's guaranteed to be safe since it's computed by this
2933  * routine initially and has been enforced since. We can always use the
2934  * slot's general xmin horizon, but the catalog horizon is only usable
2935  * when only catalog data is going to be looked at.
2936  */
2939  oldestSafeXid))
2940  oldestSafeXid = procArray->replication_slot_xmin;
2941 
2942  if (catalogOnly &&
2945  oldestSafeXid))
2946  oldestSafeXid = procArray->replication_slot_catalog_xmin;
2947 
2948  /*
2949  * If we're not in recovery, we walk over the procarray and collect the
2950  * lowest xid. Since we're called with ProcArrayLock held and have
2951  * acquired XidGenLock, no entries can vanish concurrently, since
2952  * ProcGlobal->xids[i] is only set with XidGenLock held and only cleared
2953  * with ProcArrayLock held.
2954  *
2955  * In recovery we can't lower the safe value besides what we've computed
2956  * above, so we'll have to wait a bit longer there. We unfortunately can
2957  * *not* use KnownAssignedXidsGetOldestXmin() since the KnownAssignedXids
2958  * machinery can miss values and return an older value than is safe.
2959  */
2960  if (!recovery_in_progress)
2961  {
2962  TransactionId *other_xids = ProcGlobal->xids;
2963 
2964  /*
2965  * Spin over procArray collecting min(ProcGlobal->xids[i])
2966  */
2967  for (index = 0; index < arrayP->numProcs; index++)
2968  {
2969  TransactionId xid;
2970 
2971  /* Fetch xid just once - see GetNewTransactionId */
2972  xid = UINT32_ACCESS_ONCE(other_xids[index]);
2973 
2974  if (!TransactionIdIsNormal(xid))
2975  continue;
2976 
2977  if (TransactionIdPrecedes(xid, oldestSafeXid))
2978  oldestSafeXid = xid;
2979  }
2980  }
2981 
2982  LWLockRelease(XidGenLock);
2983 
2984  return oldestSafeXid;
2985 }
bool LWLockHeldByMe(LWLock *lock)
Definition: lwlock.c:1920

References Assert(), LW_SHARED, LWLockAcquire(), LWLockHeldByMe(), LWLockRelease(), VariableCacheData::nextXid, ProcArrayStruct::numProcs, procArray, ProcGlobal, RecoveryInProgress(), ProcArrayStruct::replication_slot_catalog_xmin, ProcArrayStruct::replication_slot_xmin, ShmemVariableCache, TransactionIdIsNormal, TransactionIdIsValid, TransactionIdPrecedes(), UINT32_ACCESS_ONCE, XidFromFullTransactionId, and PROC_HDR::xids.

Referenced by CreateInitDecodingContext(), and SnapBuildInitialSnapshot().

◆ GetOldestTransactionIdConsideredRunning()

TransactionId GetOldestTransactionIdConsideredRunning ( void  )

Definition at line 2015 of file procarray.c.

2016 {
2017  ComputeXidHorizonsResult horizons;
2018 
2019  ComputeXidHorizons(&horizons);
2020 
2021  return horizons.oldest_considered_running;
2022 }

References ComputeXidHorizons(), and ComputeXidHorizonsResult::oldest_considered_running.

Referenced by CreateCheckPoint(), and CreateRestartPoint().

◆ GetReplicationHorizons()

void GetReplicationHorizons ( TransactionId xmin,
TransactionId catalog_xmin 
)

Definition at line 2028 of file procarray.c.

2029 {
2030  ComputeXidHorizonsResult horizons;
2031 
2032  ComputeXidHorizons(&horizons);
2033 
2034  /*
2035  * Don't want to use shared_oldest_nonremovable here, as that contains the
2036  * effect of replication slot's catalog_xmin. We want to send a separate
2037  * feedback for the catalog horizon, so the primary can remove data table
2038  * contents more aggressively.
2039  */
2040  *xmin = horizons.shared_oldest_nonremovable_raw;
2041  *catalog_xmin = horizons.slot_catalog_xmin;
2042 }

References ComputeXidHorizons(), ComputeXidHorizonsResult::shared_oldest_nonremovable_raw, and ComputeXidHorizonsResult::slot_catalog_xmin.

Referenced by XLogWalRcvSendHSFeedback().

◆ GetRunningTransactionData()

RunningTransactions GetRunningTransactionData ( void  )

Definition at line 2670 of file procarray.c.

2671 {
2672  /* result workspace */
2673  static RunningTransactionsData CurrentRunningXactsData;
2674 
2675  ProcArrayStruct *arrayP = procArray;
2676  TransactionId *other_xids = ProcGlobal->xids;
2677  RunningTransactions CurrentRunningXacts = &CurrentRunningXactsData;
2678  TransactionId latestCompletedXid;
2679  TransactionId oldestRunningXid;
2680  TransactionId *xids;
2681  int index;
2682  int count;
2683  int subcount;
2684  bool suboverflowed;
2685 
2687 
2688  /*
2689  * Allocating space for maxProcs xids is usually overkill; numProcs would
2690  * be sufficient. But it seems better to do the malloc while not holding
2691  * the lock, so we can't look at numProcs. Likewise, we allocate much
2692  * more subxip storage than is probably needed.
2693  *
2694  * Should only be allocated in bgwriter, since only ever executed during
2695  * checkpoints.
2696  */
2697  if (CurrentRunningXacts->xids == NULL)
2698  {
2699  /*
2700  * First call
2701  */
2702  CurrentRunningXacts->xids = (TransactionId *)
2704  if (CurrentRunningXacts->xids == NULL)
2705  ereport(ERROR,
2706  (errcode(ERRCODE_OUT_OF_MEMORY),
2707  errmsg("out of memory")));
2708  }
2709 
2710  xids = CurrentRunningXacts->xids;
2711 
2712  count = subcount = 0;
2713  suboverflowed = false;
2714 
2715  /*
2716  * Ensure that no xids enter or leave the procarray while we obtain
2717  * snapshot.
2718  */
2719  LWLockAcquire(ProcArrayLock, LW_SHARED);
2720  LWLockAcquire(XidGenLock, LW_SHARED);
2721 
2722  latestCompletedXid =
2724  oldestRunningXid =
2726 
2727  /*
2728  * Spin over procArray collecting all xids
2729  */
2730  for (index = 0; index < arrayP->numProcs; index++)
2731  {
2732  TransactionId xid;
2733 
2734  /* Fetch xid just once - see GetNewTransactionId */
2735  xid = UINT32_ACCESS_ONCE(other_xids[index]);
2736 
2737  /*
2738  * We don't need to store transactions that don't have a TransactionId
2739  * yet because they will not show as running on a standby server.
2740  */
2741  if (!TransactionIdIsValid(xid))
2742  continue;
2743 
2744  /*
2745  * Be careful not to exclude any xids before calculating the values of
2746  * oldestRunningXid and suboverflowed, since these are used to clean
2747  * up transaction information held on standbys.
2748  */
2749  if (TransactionIdPrecedes(xid, oldestRunningXid))
2750  oldestRunningXid = xid;
2751 
2753  suboverflowed = true;
2754 
2755  /*
2756  * If we wished to exclude xids this would be the right place for it.
2757  * Procs with the PROC_IN_VACUUM flag set don't usually assign xids,
2758  * but they do during truncation at the end when they get the lock and
2759  * truncate, so it is not much of a problem to include them if they
2760  * are seen and it is cleaner to include them.
2761  */
2762 
2763  xids[count++] = xid;
2764  }
2765 
2766  /*
2767  * Spin over procArray collecting all subxids, but only if there hasn't
2768  * been a suboverflow.
2769  */
2770  if (!suboverflowed)
2771  {
2772  XidCacheStatus *other_subxidstates = ProcGlobal->subxidStates;
2773 
2774  for (index = 0; index < arrayP->numProcs; index++)
2775  {
2776  int pgprocno = arrayP->pgprocnos[index];
2777  PGPROC *proc = &allProcs[pgprocno];
2778  int nsubxids;
2779 
2780  /*
2781  * Save subtransaction XIDs. Other backends can't add or remove
2782  * entries while we're holding XidGenLock.
2783  */
2784  nsubxids = other_subxidstates[index].count;
2785  if (nsubxids > 0)
2786  {
2787  /* barrier not really required, as XidGenLock is held, but ... */
2788  pg_read_barrier(); /* pairs with GetNewTransactionId */
2789 
2790  memcpy(&xids[count], proc->subxids.xids,
2791  nsubxids * sizeof(TransactionId));
2792  count += nsubxids;
2793  subcount += nsubxids;
2794 
2795  /*
2796  * Top-level XID of a transaction is always less than any of
2797  * its subxids, so we don't need to check if any of the
2798  * subxids are smaller than oldestRunningXid
2799  */
2800  }
2801  }
2802  }
2803 
2804  /*
2805  * It's important *not* to include the limits set by slots here because
2806  * snapbuild.c uses oldestRunningXid to manage its xmin horizon. If those
2807  * were to be included here the initial value could never increase because
2808  * of a circular dependency where slots only increase their limits when
2809  * running xacts increases oldestRunningXid and running xacts only
2810  * increases if slots do.
2811  */
2812 
2813  CurrentRunningXacts->xcnt = count - subcount;
2814  CurrentRunningXacts->subxcnt = subcount;
2815  CurrentRunningXacts->subxid_overflow = suboverflowed;
2817  CurrentRunningXacts->oldestRunningXid = oldestRunningXid;
2818  CurrentRunningXacts->latestCompletedXid = latestCompletedXid;
2819 
2820  Assert(TransactionIdIsValid(CurrentRunningXacts->nextXid));
2821  Assert(TransactionIdIsValid(CurrentRunningXacts->oldestRunningXid));
2822  Assert(TransactionIdIsNormal(CurrentRunningXacts->latestCompletedXid));
2823 
2824  /* We don't release the locks here, the caller is responsible for that */
2825 
2826  return CurrentRunningXacts;
2827 }
#define pg_read_barrier()
Definition: atomics.h:153
struct XidCache subxids
Definition: proc.h:256
XidCacheStatus * subxidStates
Definition: proc.h:371
TransactionId oldestRunningXid
Definition: standby.h:84
TransactionId nextXid
Definition: standby.h:83
TransactionId latestCompletedXid
Definition: standby.h:85
TransactionId * xids
Definition: standby.h:87
bool overflowed
Definition: proc.h:45
uint8 count
Definition: proc.h:43
TransactionId xids[PGPROC_MAX_CACHED_SUBXIDS]
Definition: proc.h:50

References allProcs, Assert(), XidCacheStatus::count, ereport, errcode(), errmsg(), ERROR, VariableCacheData::latestCompletedXid, RunningTransactionsData::latestCompletedXid, LW_SHARED, LWLockAcquire(), malloc, VariableCacheData::nextXid, RunningTransactionsData::nextXid, ProcArrayStruct::numProcs, RunningTransactionsData::oldestRunningXid, XidCacheStatus::overflowed, pg_read_barrier, ProcArrayStruct::pgprocnos, procArray, ProcGlobal, RecoveryInProgress(), ShmemVariableCache, RunningTransactionsData::subxcnt, RunningTransactionsData::subxid_overflow, PGPROC::subxids, PROC_HDR::subxidStates, TOTAL_MAX_CACHED_SUBXIDS, TransactionIdIsNormal, TransactionIdIsValid, TransactionIdPrecedes(), UINT32_ACCESS_ONCE, RunningTransactionsData::xcnt, XidFromFullTransactionId, XidCache::xids, PROC_HDR::xids, and RunningTransactionsData::xids.

Referenced by LogStandbySnapshot().

◆ GetSnapshotData()

Snapshot GetSnapshotData ( Snapshot  snapshot)

Definition at line 2159 of file procarray.c.

2160 {
2161  ProcArrayStruct *arrayP = procArray;
2162  TransactionId *other_xids = ProcGlobal->xids;
2163  TransactionId xmin;
2164  TransactionId xmax;
2165  int count = 0;
2166  int subcount = 0;
2167  bool suboverflowed = false;
2168  FullTransactionId latest_completed;
2169  TransactionId oldestxid;
2170  int mypgxactoff;
2171  TransactionId myxid;
2172  uint64 curXactCompletionCount;
2173 
2174  TransactionId replication_slot_xmin = InvalidTransactionId;
2175  TransactionId replication_slot_catalog_xmin = InvalidTransactionId;
2176 
2177  Assert(snapshot != NULL);
2178 
2179  /*
2180  * Allocating space for maxProcs xids is usually overkill; numProcs would
2181  * be sufficient. But it seems better to do the malloc while not holding
2182  * the lock, so we can't look at numProcs. Likewise, we allocate much
2183  * more subxip storage than is probably needed.
2184  *
2185  * This does open a possibility for avoiding repeated malloc/free: since
2186  * maxProcs does not change at runtime, we can simply reuse the previous
2187  * xip arrays if any. (This relies on the fact that all callers pass
2188  * static SnapshotData structs.)
2189  */
2190  if (snapshot->xip == NULL)
2191  {
2192  /*
2193  * First call for this snapshot. Snapshot is same size whether or not
2194  * we are in recovery, see later comments.
2195  */
2196  snapshot->xip = (TransactionId *)
2198  if (snapshot->xip == NULL)
2199  ereport(ERROR,
2200  (errcode(ERRCODE_OUT_OF_MEMORY),
2201  errmsg("out of memory")));
2202  Assert(snapshot->subxip == NULL);
2203  snapshot->subxip = (TransactionId *)
2205  if (snapshot->subxip == NULL)
2206  ereport(ERROR,
2207  (errcode(ERRCODE_OUT_OF_MEMORY),
2208  errmsg("out of memory")));
2209  }
2210 
2211  /*
2212  * It is sufficient to get shared lock on ProcArrayLock, even if we are
2213  * going to set MyProc->xmin.
2214  */
2215  LWLockAcquire(ProcArrayLock, LW_SHARED);
2216 
2217  if (GetSnapshotDataReuse(snapshot))
2218  {
2219  LWLockRelease(ProcArrayLock);
2220  return snapshot;
2221  }
2222 
2223  latest_completed = ShmemVariableCache->latestCompletedXid;
2224  mypgxactoff = MyProc->pgxactoff;
2225  myxid = other_xids[mypgxactoff];
2226  Assert(myxid == MyProc->xid);
2227 
2228  oldestxid = ShmemVariableCache->oldestXid;
2229  curXactCompletionCount = ShmemVariableCache->xactCompletionCount;
2230 
2231  /* xmax is always latestCompletedXid + 1 */
2232  xmax = XidFromFullTransactionId(latest_completed);
2233  TransactionIdAdvance(xmax);
2235 
2236  /* initialize xmin calculation with xmax */
2237  xmin = xmax;
2238 
2239  /* take own xid into account, saves a check inside the loop */
2240  if (TransactionIdIsNormal(myxid) && NormalTransactionIdPrecedes(myxid, xmin))
2241  xmin = myxid;
2242 
2244 
2245  if (!snapshot->takenDuringRecovery)
2246  {
2247  int numProcs = arrayP->numProcs;
2248  TransactionId *xip = snapshot->xip;
2249  int *pgprocnos = arrayP->pgprocnos;
2250  XidCacheStatus *subxidStates = ProcGlobal->subxidStates;
2251  uint8 *allStatusFlags = ProcGlobal->statusFlags;
2252 
2253  /*
2254  * First collect set of pgxactoff/xids that need to be included in the
2255  * snapshot.
2256  */
2257  for (int pgxactoff = 0; pgxactoff < numProcs; pgxactoff++)
2258  {
2259  /* Fetch xid just once - see GetNewTransactionId */
2260  TransactionId xid = UINT32_ACCESS_ONCE(other_xids[pgxactoff]);
2261  uint8 statusFlags;
2262 
2263  Assert(allProcs[arrayP->pgprocnos[pgxactoff]].pgxactoff == pgxactoff);
2264 
2265  /*
2266  * If the transaction has no XID assigned, we can skip it; it
2267  * won't have sub-XIDs either.
2268  */
2269  if (likely(xid == InvalidTransactionId))
2270  continue;
2271 
2272  /*
2273  * We don't include our own XIDs (if any) in the snapshot. It
2274  * needs to be included in the xmin computation, but we did so
2275  * outside the loop.
2276  */
2277  if (pgxactoff == mypgxactoff)
2278  continue;
2279 
2280  /*
2281  * The only way we are able to get here with a non-normal xid is
2282  * during bootstrap - with this backend using
2283  * BootstrapTransactionId. But the above test should filter that
2284  * out.
2285  */
2287 
2288  /*
2289  * If the XID is >= xmax, we can skip it; such transactions will
2290  * be treated as running anyway (and any sub-XIDs will also be >=
2291  * xmax).
2292  */
2293  if (!NormalTransactionIdPrecedes(xid, xmax))
2294  continue;
2295 
2296  /*
2297  * Skip over backends doing logical decoding which manages xmin
2298  * separately (check below) and ones running LAZY VACUUM.
2299  */
2300  statusFlags = allStatusFlags[pgxactoff];
2301  if (statusFlags & (PROC_IN_LOGICAL_DECODING | PROC_IN_VACUUM))
2302  continue;
2303 
2304  if (NormalTransactionIdPrecedes(xid, xmin))
2305  xmin = xid;
2306 
2307  /* Add XID to snapshot. */
2308  xip[count++] = xid;
2309 
2310  /*
2311  * Save subtransaction XIDs if possible (if we've already
2312  * overflowed, there's no point). Note that the subxact XIDs must
2313  * be later than their parent, so no need to check them against
2314  * xmin. We could filter against xmax, but it seems better not to
2315  * do that much work while holding the ProcArrayLock.
2316  *
2317  * The other backend can add more subxids concurrently, but cannot
2318  * remove any. Hence it's important to fetch nxids just once.
2319  * Should be safe to use memcpy, though. (We needn't worry about
2320  * missing any xids added concurrently, because they must postdate
2321  * xmax.)
2322  *
2323  * Again, our own XIDs are not included in the snapshot.
2324  */
2325  if (!suboverflowed)
2326  {
2327 
2328  if (subxidStates[pgxactoff].overflowed)
2329  suboverflowed = true;
2330  else
2331  {
2332  int nsubxids = subxidStates[pgxactoff].count;
2333 
2334  if (nsubxids > 0)
2335  {
2336  int pgprocno = pgprocnos[pgxactoff];
2337  PGPROC *proc = &allProcs[pgprocno];
2338 
2339  pg_read_barrier(); /* pairs with GetNewTransactionId */
2340 
2341  memcpy(snapshot->subxip + subcount,
2342  proc->subxids.xids,
2343  nsubxids * sizeof(TransactionId));
2344  subcount += nsubxids;
2345  }
2346  }
2347  }
2348  }
2349  }
2350  else
2351  {
2352  /*
2353  * We're in hot standby, so get XIDs from KnownAssignedXids.
2354  *
2355  * We store all xids directly into subxip[]. Here's why:
2356  *
2357  * In recovery we don't know which xids are top-level and which are
2358  * subxacts, a design choice that greatly simplifies xid processing.
2359  *
2360  * It seems like we would want to try to put xids into xip[] only, but
2361  * that is fairly small. We would either need to make that bigger or
2362  * to increase the rate at which we WAL-log xid assignment; neither is
2363  * an appealing choice.
2364  *
2365  * We could try to store xids into xip[] first and then into subxip[]
2366  * if there are too many xids. That only works if the snapshot doesn't
2367  * overflow because we do not search subxip[] in that case. A simpler
2368  * way is to just store all xids in the subxip array because this is
2369  * by far the bigger array. We just leave the xip array empty.
2370  *
2371  * Either way we need to change the way XidInMVCCSnapshot() works
2372  * depending upon when the snapshot was taken, or change normal
2373  * snapshot processing so it matches.
2374  *
2375  * Note: It is possible for recovery to end before we finish taking
2376  * the snapshot, and for newly assigned transaction ids to be added to
2377  * the ProcArray. xmax cannot change while we hold ProcArrayLock, so
2378  * those newly added transaction ids would be filtered away, so we
2379  * need not be concerned about them.
2380  */
2381  subcount = KnownAssignedXidsGetAndSetXmin(snapshot->subxip, &xmin,
2382  xmax);
2383 
2385  suboverflowed = true;
2386  }
2387 
2388 
2389  /*
2390  * Fetch into local variable while ProcArrayLock is held - the
2391  * LWLockRelease below is a barrier, ensuring this happens inside the
2392  * lock.
2393  */
2394  replication_slot_xmin = procArray->replication_slot_xmin;
2395  replication_slot_catalog_xmin = procArray->replication_slot_catalog_xmin;
2396 
2398  MyProc->xmin = TransactionXmin = xmin;
2399 
2400  LWLockRelease(ProcArrayLock);
2401 
2402  /* maintain state for GlobalVis* */
2403  {
2404  TransactionId def_vis_xid;
2405  TransactionId def_vis_xid_data;
2406  FullTransactionId def_vis_fxid;
2407  FullTransactionId def_vis_fxid_data;
2408  FullTransactionId oldestfxid;
2409 
2410  /*
2411  * Converting oldestXid is only safe when xid horizon cannot advance,
2412  * i.e. holding locks. While we don't hold the lock anymore, all the
2413  * necessary data has been gathered with lock held.
2414  */
2415  oldestfxid = FullXidRelativeTo(latest_completed, oldestxid);
2416 
2417  /* Check whether there's a replication slot requiring an older xmin. */
2418  def_vis_xid_data =
2419  TransactionIdOlder(xmin, replication_slot_xmin);
2420 
2421  /*
2422  * Rows in non-shared, non-catalog tables possibly could be vacuumed
2423  * if older than this xid.
2424  */
2425  def_vis_xid = def_vis_xid_data;
2426 
2427  /*
2428  * Check whether there's a replication slot requiring an older catalog
2429  * xmin.
2430  */
2431  def_vis_xid =
2432  TransactionIdOlder(replication_slot_catalog_xmin, def_vis_xid);
2433 
2434  def_vis_fxid = FullXidRelativeTo(latest_completed, def_vis_xid);
2435  def_vis_fxid_data = FullXidRelativeTo(latest_completed, def_vis_xid_data);
2436 
2437  /*
2438  * Check if we can increase upper bound. As a previous
2439  * GlobalVisUpdate() might have computed more aggressive values, don't
2440  * overwrite them if so.
2441  */
2443  FullTransactionIdNewer(def_vis_fxid,
2446  FullTransactionIdNewer(def_vis_fxid,
2449  FullTransactionIdNewer(def_vis_fxid_data,
2451  /* See temp_oldest_nonremovable computation in ComputeXidHorizons() */
2452  if (TransactionIdIsNormal(myxid))
2454  FullXidRelativeTo(latest_completed, myxid);
2455  else
2456  {
2457  GlobalVisTempRels.definitely_needed = latest_completed;
2459  }
2460 
2461  /*
2462  * Check if we know that we can initialize or increase the lower
2463  * bound. Currently the only cheap way to do so is to use
2464  * ShmemVariableCache->oldestXid as input.
2465  *
2466  * We should definitely be able to do better. We could e.g. put a
2467  * global lower bound value into ShmemVariableCache.
2468  */
2471  oldestfxid);
2474  oldestfxid);
2477  oldestfxid);
2478  /* accurate value known */
2480  }
2481 
2482  RecentXmin = xmin;
2484 
2485  snapshot->xmin = xmin;
2486  snapshot->xmax = xmax;
2487  snapshot->xcnt = count;
2488  snapshot->subxcnt = subcount;
2489  snapshot->suboverflowed = suboverflowed;
2490  snapshot->snapXactCompletionCount = curXactCompletionCount;
2491 
2492  snapshot->curcid = GetCurrentCommandId(false);
2493 
2494  /*
2495  * This is a new snapshot, so set both refcounts are zero, and mark it as
2496  * not copied in persistent memory.
2497  */
2498  snapshot->active_count = 0;
2499  snapshot->regd_count = 0;
2500  snapshot->copied = false;
2501  snapshot->lsn = InvalidXLogRecPtr;
2502  snapshot->whenTaken = 0;
2503 
2504  return snapshot;
2505 }
#define likely(x)
Definition: c.h:299
static GlobalVisState GlobalVisDataRels
Definition: procarray.c:300
static GlobalVisState GlobalVisSharedRels
Definition: procarray.c:298
static GlobalVisState GlobalVisCatalogRels
Definition: procarray.c:299
static FullTransactionId FullXidRelativeTo(FullTransactionId rel, TransactionId xid)
Definition: procarray.c:4255
static int KnownAssignedXidsGetAndSetXmin(TransactionId *xarray, TransactionId *xmin, TransactionId xmax)
Definition: procarray.c:5037
int GetMaxSnapshotSubxidCount(void)
Definition: procarray.c:2061
static GlobalVisState GlobalVisTempRels
Definition: procarray.c:301
int GetMaxSnapshotXidCount(void)
Definition: procarray.c:2050
static bool GetSnapshotDataReuse(Snapshot snapshot)
Definition: procarray.c:2076
TransactionId RecentXmin
Definition: snapmgr.c:105
TransactionId TransactionXmin
Definition: snapmgr.c:104
FullTransactionId definitely_needed
Definition: procarray.c:171
FullTransactionId maybe_needed
Definition: procarray.c:174
int pgxactoff
Definition: proc.h:188
TransactionId xmin
Definition: snapshot.h:157
int32 subxcnt
Definition: snapshot.h:181
bool copied
Definition: snapshot.h:185
uint32 regd_count
Definition: snapshot.h:205
uint32 active_count
Definition: snapshot.h:204
CommandId curcid
Definition: snapshot.h:187
TimestampTz whenTaken
Definition: snapshot.h:208
uint32 xcnt
Definition: snapshot.h:169
TransactionId * subxip
Definition: snapshot.h:180
uint64 snapXactCompletionCount
Definition: snapshot.h:216
TransactionId xmax
Definition: snapshot.h:158
XLogRecPtr lsn
Definition: snapshot.h:209
TransactionId * xip
Definition: snapshot.h:168
bool suboverflowed
Definition: snapshot.h:182
bool takenDuringRecovery
Definition: snapshot.h:184
TransactionId oldestXid
Definition: transam.h:222
static FullTransactionId FullTransactionIdNewer(FullTransactionId a, FullTransactionId b)
Definition: transam.h:360
#define NormalTransactionIdPrecedes(id1, id2)
Definition: transam.h:147
static void FullTransactionIdAdvance(FullTransactionId *dest)
Definition: transam.h:128
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:818
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28

References SnapshotData::active_count, allProcs, Assert(), SnapshotData::copied, XidCacheStatus::count, SnapshotData::curcid, GlobalVisState::definitely_needed, ereport, errcode(), errmsg(), ERROR, FullTransactionIdAdvance(), FullTransactionIdNewer(), FullXidRelativeTo(), GetCurrentCommandId(), GetMaxSnapshotSubxidCount(), GetMaxSnapshotXidCount(), GetSnapshotDataReuse(), GlobalVisCatalogRels, GlobalVisDataRels, GlobalVisSharedRels, GlobalVisTempRels, InvalidTransactionId, InvalidXLogRecPtr, KnownAssignedXidsGetAndSetXmin(), ProcArrayStruct::lastOverflowedXid, VariableCacheData::latestCompletedXid, likely, SnapshotData::lsn, LW_SHARED, LWLockAcquire(), LWLockRelease(), malloc, GlobalVisState::maybe_needed, MyProc, NormalTransactionIdPrecedes, ProcArrayStruct::numProcs, VariableCacheData::oldestXid, pg_read_barrier, ProcArrayStruct::pgprocnos, PGPROC::pgxactoff, PROC_IN_LOGICAL_DECODING, PROC_IN_VACUUM, procArray, ProcGlobal, RecentXmin, RecoveryInProgress(), SnapshotData::regd_count, ProcArrayStruct::replication_slot_catalog_xmin, ProcArrayStruct::replication_slot_xmin, ShmemVariableCache, SnapshotData::snapXactCompletionCount, PROC_HDR::statusFlags, SnapshotData::suboverflowed, SnapshotData::subxcnt, PGPROC::subxids, PROC_HDR::subxidStates, SnapshotData::subxip, SnapshotData::takenDuringRecovery, TransactionIdAdvance, TransactionIdIsNormal, TransactionIdIsValid, TransactionIdOlder(), TransactionIdPrecedesOrEquals(), TransactionXmin, UINT32_ACCESS_ONCE, SnapshotData::whenTaken, VariableCacheData::xactCompletionCount, SnapshotData::xcnt, PGPROC::xid, XidFromFullTransactionId, XidCache::xids, PROC_HDR::xids, SnapshotData::xip, SnapshotData::xmax, PGPROC::xmin, and SnapshotData::xmin.

Referenced by GetLatestSnapshot(), GetNonHistoricCatalogSnapshot(), GetSerializableTransactionSnapshotInt(), GetTransactionSnapshot(), and SetTransactionSnapshot().

◆ GetSnapshotDataReuse()

static bool GetSnapshotDataReuse ( Snapshot  snapshot)
static

Definition at line 2076 of file procarray.c.

2077 {
2078  uint64 curXactCompletionCount;
2079 
2080  Assert(LWLockHeldByMe(ProcArrayLock));
2081 
2082  if (unlikely(snapshot->snapXactCompletionCount == 0))
2083  return false;
2084 
2085  curXactCompletionCount = ShmemVariableCache->xactCompletionCount;
2086  if (curXactCompletionCount != snapshot->snapXactCompletionCount)
2087  return false;
2088 
2089  /*
2090  * If the current xactCompletionCount is still the same as it was at the
2091  * time the snapshot was built, we can be sure that rebuilding the
2092  * contents of the snapshot the hard way would result in the same snapshot
2093  * contents:
2094  *
2095  * As explained in transam/README, the set of xids considered running by
2096  * GetSnapshotData() cannot change while ProcArrayLock is held. Snapshot
2097  * contents only depend on transactions with xids and xactCompletionCount
2098  * is incremented whenever a transaction with an xid finishes (while
2099  * holding ProcArrayLock) exclusively). Thus the xactCompletionCount check
2100  * ensures we would detect if the snapshot would have changed.
2101  *
2102  * As the snapshot contents are the same as it was before, it is safe to
2103  * re-enter the snapshot's xmin into the PGPROC array. None of the rows
2104  * visible under the snapshot could already have been removed (that'd
2105  * require the set of running transactions to change) and it fulfills the
2106  * requirement that concurrent GetSnapshotData() calls yield the same
2107  * xmin.
2108  */
2110  MyProc->xmin = TransactionXmin = snapshot->xmin;
2111 
2112  RecentXmin = snapshot->xmin;
2114 
2115  snapshot->curcid = GetCurrentCommandId(false);
2116  snapshot->active_count = 0;
2117  snapshot->regd_count = 0;
2118  snapshot->copied = false;
2119  snapshot->lsn = InvalidXLogRecPtr;
2120  snapshot->whenTaken = 0;
2121 
2122  return true;
2123 }
#define unlikely(x)
Definition: c.h:300

References SnapshotData::active_count, Assert(), SnapshotData::copied, SnapshotData::curcid, GetCurrentCommandId(), InvalidXLogRecPtr, SnapshotData::lsn, LWLockHeldByMe(), MyProc, RecentXmin, SnapshotData::regd_count, ShmemVariableCache, SnapshotData::snapXactCompletionCount, TransactionIdIsValid, TransactionIdPrecedesOrEquals(), TransactionXmin, unlikely, SnapshotData::whenTaken, VariableCacheData::xactCompletionCount, PGPROC::xmin, and SnapshotData::xmin.

Referenced by GetSnapshotData().

◆ GetVirtualXIDsDelayingChkpt()

VirtualTransactionId* GetVirtualXIDsDelayingChkpt ( int *  nvxids,
int  type 
)

Definition at line 3008 of file procarray.c.

3009 {
3010  VirtualTransactionId *vxids;
3011  ProcArrayStruct *arrayP = procArray;
3012  int count = 0;
3013  int index;
3014 
3015  Assert(type != 0);
3016 
3017  /* allocate what's certainly enough result space */
3018  vxids = (VirtualTransactionId *)
3019  palloc(sizeof(VirtualTransactionId) * arrayP->maxProcs);
3020 
3021  LWLockAcquire(ProcArrayLock, LW_SHARED);
3022 
3023  for (index = 0; index < arrayP->numProcs; index++)
3024  {
3025  int pgprocno = arrayP->pgprocnos[index];
3026  PGPROC *proc = &allProcs[pgprocno];
3027 
3028  if ((proc->delayChkptFlags & type) != 0)
3029  {
3030  VirtualTransactionId vxid;
3031 
3032  GET_VXID_FROM_PGPROC(vxid, *proc);
3033  if (VirtualTransactionIdIsValid(vxid))
3034  vxids[count++] = vxid;
3035  }
3036  }
3037 
3038  LWLockRelease(ProcArrayLock);
3039 
3040  *nvxids = count;
3041  return vxids;
3042 }
int delayChkptFlags
Definition: proc.h:231
const char * type

References allProcs, Assert(), PGPROC::delayChkptFlags, GET_VXID_FROM_PGPROC, LW_SHARED, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::maxProcs, ProcArrayStruct::numProcs, palloc(), ProcArrayStruct::pgprocnos, procArray, type, and VirtualTransactionIdIsValid.

Referenced by CreateCheckPoint().

◆ GlobalVisCheckRemovableFullXid()

bool GlobalVisCheckRemovableFullXid ( Relation  rel,
FullTransactionId  fxid 
)

Definition at line 4220 of file procarray.c.

4221 {
4223 
4224  state = GlobalVisTestFor(rel);
4225 
4226  return GlobalVisTestIsRemovableFullXid(state, fxid);
4227 }
bool GlobalVisTestIsRemovableFullXid(GlobalVisState *state, FullTransactionId fxid)
Definition: procarray.c:4126
GlobalVisState * GlobalVisTestFor(Relation rel)
Definition: procarray.c:4011
Definition: regguts.h:323

References GlobalVisTestFor(), and GlobalVisTestIsRemovableFullXid().

Referenced by _bt_pendingfsm_finalize(), BTPageIsRecyclable(), and gistPageRecyclable().

◆ GlobalVisCheckRemovableXid()

bool GlobalVisCheckRemovableXid ( Relation  rel,
TransactionId  xid 
)

Definition at line 4234 of file procarray.c.

4235 {
4237 
4238  state = GlobalVisTestFor(rel);
4239 
4240  return GlobalVisTestIsRemovableXid(state, xid);
4241 }
bool GlobalVisTestIsRemovableXid(GlobalVisState *state, TransactionId xid)
Definition: procarray.c:4168

References GlobalVisTestFor(), and GlobalVisTestIsRemovableXid().

Referenced by GinPageIsRecyclable().

◆ GlobalVisHorizonKindForRel()

static GlobalVisHorizonKind GlobalVisHorizonKindForRel ( Relation  rel)
inlinestatic

Definition at line 1952 of file procarray.c.

1953 {
1954  /*
1955  * Other relkinds currently don't contain xids, nor always the necessary
1956  * logical decoding markers.
1957  */
1958  Assert(!rel ||
1959  rel->rd_rel->relkind == RELKIND_RELATION ||
1960  rel->rd_rel->relkind == RELKIND_MATVIEW ||
1961  rel->rd_rel->relkind == RELKIND_TOASTVALUE);
1962 
1963  if (rel == NULL || rel->rd_rel->relisshared || RecoveryInProgress())
1964  return VISHORIZON_SHARED;
1965  else if (IsCatalogRelation(rel) ||
1967  return VISHORIZON_CATALOG;
1968  else if (!RELATION_IS_LOCAL(rel))
1969  return VISHORIZON_DATA;
1970  else
1971  return VISHORIZON_TEMP;
1972 }
bool IsCatalogRelation(Relation relation)
Definition: catalog.c:105
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:649
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:685
Form_pg_class rd_rel
Definition: rel.h:111

References Assert(), IsCatalogRelation(), RelationData::rd_rel, RecoveryInProgress(), RELATION_IS_LOCAL, RelationIsAccessibleInLogicalDecoding, VISHORIZON_CATALOG, VISHORIZON_DATA, VISHORIZON_SHARED, and VISHORIZON_TEMP.

Referenced by GetOldestNonRemovableTransactionId(), and GlobalVisTestFor().

◆ GlobalVisTestFor()

GlobalVisState* GlobalVisTestFor ( Relation  rel)

Definition at line 4011 of file procarray.c.

4012 {
4013  GlobalVisState *state = NULL;
4014 
4015  /* XXX: we should assert that a snapshot is pushed or registered */
4016  Assert(RecentXmin);
4017 
4018  switch (GlobalVisHorizonKindForRel(rel))
4019  {
4020  case VISHORIZON_SHARED:
4022  break;
4023  case VISHORIZON_CATALOG:
4025  break;
4026  case VISHORIZON_DATA:
4028  break;
4029  case VISHORIZON_TEMP:
4031  break;
4032  }
4033 
4034  Assert(FullTransactionIdIsValid(state->definitely_needed) &&
4035  FullTransactionIdIsValid(state->maybe_needed));
4036 
4037  return state;
4038 }
#define FullTransactionIdIsValid(x)
Definition: transam.h:55

References Assert(), FullTransactionIdIsValid, GlobalVisCatalogRels, GlobalVisDataRels, GlobalVisHorizonKindForRel(), GlobalVisSharedRels, GlobalVisTempRels, RecentXmin, VISHORIZON_CATALOG, VISHORIZON_DATA, VISHORIZON_SHARED, and VISHORIZON_TEMP.

Referenced by get_actual_variable_endpoint(), GlobalVisCheckRemovableFullXid(), GlobalVisCheckRemovableXid(), heap_hot_search_buffer(), heap_index_delete_tuples(), heap_page_prune_opt(), heap_vacuum_rel(), and vacuumRedirectAndPlaceholder().

◆ GlobalVisTestIsRemovableFullXid()

bool GlobalVisTestIsRemovableFullXid ( GlobalVisState state,
FullTransactionId  fxid 
)

Definition at line 4126 of file procarray.c.

4128 {
4129  /*
4130  * If fxid is older than maybe_needed bound, it definitely is visible to
4131  * everyone.
4132  */
4133  if (FullTransactionIdPrecedes(fxid, state->maybe_needed))
4134  return true;
4135 
4136  /*
4137  * If fxid is >= definitely_needed bound, it is very likely to still be
4138  * considered running.
4139  */
4140  if (FullTransactionIdFollowsOrEquals(fxid, state->definitely_needed))
4141  return false;
4142 
4143  /*
4144  * fxid is between maybe_needed and definitely_needed, i.e. there might or
4145  * might not exist a snapshot considering fxid running. If it makes sense,
4146  * update boundaries and recheck.
4147  */
4149  {
4150  GlobalVisUpdate();
4151 
4152  Assert(FullTransactionIdPrecedes(fxid, state->definitely_needed));
4153 
4154  return FullTransactionIdPrecedes(fxid, state->maybe_needed);
4155  }
4156  else
4157  return false;
4158 }
static bool GlobalVisTestShouldUpdate(GlobalVisState *state)
Definition: procarray.c:4051
static void GlobalVisUpdate(void)
Definition: procarray.c:4109
#define FullTransactionIdFollowsOrEquals(a, b)
Definition: transam.h:54
#define FullTransactionIdPrecedes(a, b)
Definition: transam.h:51

References Assert(), FullTransactionIdFollowsOrEquals, FullTransactionIdPrecedes, GlobalVisTestShouldUpdate(), and GlobalVisUpdate().

Referenced by GlobalVisCheckRemovableFullXid(), and GlobalVisTestIsRemovableXid().

◆ GlobalVisTestIsRemovableXid()

bool GlobalVisTestIsRemovableXid ( GlobalVisState state,
TransactionId  xid 
)

Definition at line 4168 of file procarray.c.

4169 {
4170  FullTransactionId fxid;
4171 
4172  /*
4173  * Convert 32 bit argument to FullTransactionId. We can do so safely
4174  * because we know the xid has to, at the very least, be between
4175  * [oldestXid, nextXid), i.e. within 2 billion of xid. To avoid taking a
4176  * lock to determine either, we can just compare with
4177  * state->definitely_needed, which was based on those value at the time
4178  * the current snapshot was built.
4179  */
4180  fxid = FullXidRelativeTo(state->definitely_needed, xid);
4181 
4182  return GlobalVisTestIsRemovableFullXid(state, fxid);
4183 }

References FullXidRelativeTo(), and GlobalVisTestIsRemovableFullXid().

Referenced by GlobalVisCheckRemovableXid(), heap_page_prune_opt(), heap_prune_satisfies_vacuum(), HeapTupleIsSurelyDead(), HeapTupleSatisfiesNonVacuumable(), and vacuumRedirectAndPlaceholder().

◆ GlobalVisTestNonRemovableFullHorizon()

FullTransactionId GlobalVisTestNonRemovableFullHorizon ( GlobalVisState state)

Definition at line 4195 of file procarray.c.

4196 {
4197  /* acquire accurate horizon if not already done */
4199  GlobalVisUpdate();
4200 
4201  return state->maybe_needed;
4202 }

References GlobalVisTestShouldUpdate(), and GlobalVisUpdate().

Referenced by GlobalVisTestNonRemovableHorizon().

◆ GlobalVisTestNonRemovableHorizon()

TransactionId GlobalVisTestNonRemovableHorizon ( GlobalVisState state)

Definition at line 4206 of file procarray.c.

4207 {
4208  FullTransactionId cutoff;
4209 
4211 
4212  return XidFromFullTransactionId(cutoff);
4213 }
FullTransactionId GlobalVisTestNonRemovableFullHorizon(GlobalVisState *state)
Definition: procarray.c:4195

References GlobalVisTestNonRemovableFullHorizon(), and XidFromFullTransactionId.

◆ GlobalVisTestShouldUpdate()

static bool GlobalVisTestShouldUpdate ( GlobalVisState state)
static

Definition at line 4051 of file procarray.c.

4052 {
4053  /* hasn't been updated yet */
4055  return true;
4056 
4057  /*
4058  * If the maybe_needed/definitely_needed boundaries are the same, it's
4059  * unlikely to be beneficial to refresh boundaries.
4060  */
4061  if (FullTransactionIdFollowsOrEquals(state->maybe_needed,
4062  state->definitely_needed))
4063  return false;
4064 
4065  /* does the last snapshot built have a different xmin? */
4067 }
static TransactionId ComputeXidHorizonsResultLastXmin
Definition: procarray.c:308

References ComputeXidHorizonsResultLastXmin, FullTransactionIdFollowsOrEquals, RecentXmin, and TransactionIdIsValid.

Referenced by GlobalVisTestIsRemovableFullXid(), and GlobalVisTestNonRemovableFullHorizon().

◆ GlobalVisUpdate()

static void GlobalVisUpdate ( void  )
static

Definition at line 4109 of file procarray.c.

4110 {
4111  ComputeXidHorizonsResult horizons;
4112 
4113  /* updates the horizons as a side-effect */
4114  ComputeXidHorizons(&horizons);
4115 }

References ComputeXidHorizons().

Referenced by GlobalVisTestIsRemovableFullXid(), and GlobalVisTestNonRemovableFullHorizon().

◆ GlobalVisUpdateApply()

static void GlobalVisUpdateApply ( ComputeXidHorizonsResult horizons)
static

Definition at line 4070 of file procarray.c.

4071 {
4074  horizons->shared_oldest_nonremovable);
4077  horizons->catalog_oldest_nonremovable);
4080  horizons->data_oldest_nonremovable);
4083  horizons->temp_oldest_nonremovable);
4084 
4085  /*
4086  * In longer running transactions it's possible that transactions we
4087  * previously needed to treat as running aren't around anymore. So update
4088  * definitely_needed to not be earlier than maybe_needed.
4089  */
4100 
4102 }

References ComputeXidHorizonsResult::catalog_oldest_nonremovable, ComputeXidHorizonsResultLastXmin, ComputeXidHorizonsResult::data_oldest_nonremovable, GlobalVisState::definitely_needed, FullTransactionIdNewer(), FullXidRelativeTo(), GlobalVisCatalogRels, GlobalVisDataRels, GlobalVisSharedRels, GlobalVisTempRels, ComputeXidHorizonsResult::latest_completed, GlobalVisState::maybe_needed, RecentXmin, ComputeXidHorizonsResult::shared_oldest_nonremovable, and ComputeXidHorizonsResult::temp_oldest_nonremovable.

Referenced by ComputeXidHorizons().

◆ HaveVirtualXIDsDelayingChkpt()

bool HaveVirtualXIDsDelayingChkpt ( VirtualTransactionId vxids,
int  nvxids,
int  type 
)

Definition at line 3054 of file procarray.c.

3055 {
3056  bool result = false;
3057  ProcArrayStruct *arrayP = procArray;
3058  int index;
3059 
3060  Assert(type != 0);
3061 
3062  LWLockAcquire(ProcArrayLock, LW_SHARED);
3063 
3064  for (index = 0; index < arrayP->numProcs; index++)
3065  {
3066  int pgprocno = arrayP->pgprocnos[index];
3067  PGPROC *proc = &allProcs[pgprocno];
3068  VirtualTransactionId vxid;
3069 
3070  GET_VXID_FROM_PGPROC(vxid, *proc);
3071 
3072  if ((proc->delayChkptFlags & type) != 0 &&
3074  {
3075  int i;
3076 
3077  for (i = 0; i < nvxids; i++)
3078  {
3079  if (VirtualTransactionIdEquals(vxid, vxids[i]))
3080  {
3081  result = true;
3082  break;
3083  }
3084  }
3085  if (result)
3086  break;
3087  }
3088  }
3089 
3090  LWLockRelease(ProcArrayLock);
3091 
3092  return result;
3093 }
int i
Definition: isn.c:73
#define VirtualTransactionIdEquals(vxid1, vxid2)
Definition: lock.h:71

References allProcs, Assert(), PGPROC::delayChkptFlags, GET_VXID_FROM_PGPROC, i, LW_SHARED, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::numProcs, ProcArrayStruct::pgprocnos, procArray, type, VirtualTransactionIdEquals, and VirtualTransactionIdIsValid.

Referenced by CreateCheckPoint().

◆ IsBackendPid()

bool IsBackendPid ( int  pid)

Definition at line 3198 of file procarray.c.

3199 {
3200  return (BackendPidGetProc(pid) != NULL);
3201 }
PGPROC * BackendPidGetProc(int pid)
Definition: procarray.c:3103

References BackendPidGetProc().

Referenced by pg_stat_get_subscription().

◆ KnownAssignedTransactionIdsIdleMaintenance()

void KnownAssignedTransactionIdsIdleMaintenance ( void  )

Definition at line 4474 of file procarray.c.

4475 {
4477 }
static void KnownAssignedXidsCompress(KAXCompressReason reason, bool haveLock)
Definition: procarray.c:4575

References KAX_STARTUP_PROCESS_IDLE, and KnownAssignedXidsCompress().

Referenced by WaitForWALToBecomeAvailable().

◆ KnownAssignedXidExists()

static bool KnownAssignedXidExists ( TransactionId  xid)
static

Definition at line 4884 of file procarray.c.

4885 {
4887 
4888  return KnownAssignedXidsSearch(xid, false);
4889 }
static bool KnownAssignedXidsSearch(TransactionId xid, bool remove)
Definition: procarray.c:4796

References Assert(), KnownAssignedXidsSearch(), and TransactionIdIsValid.

Referenced by TransactionIdIsInProgress().

◆ KnownAssignedXidsAdd()

static void KnownAssignedXidsAdd ( TransactionId  from_xid,
TransactionId  to_xid,
bool  exclusive_lock 
)
static

Definition at line 4692 of file procarray.c.

4694 {
4695  ProcArrayStruct *pArray = procArray;
4696  TransactionId next_xid;
4697  int head,
4698  tail;
4699  int nxids;
4700  int i;
4701 
4702  Assert(TransactionIdPrecedesOrEquals(from_xid, to_xid));
4703 
4704  /*
4705  * Calculate how many array slots we'll need. Normally this is cheap; in
4706  * the unusual case where the XIDs cross the wrap point, we do it the hard
4707  * way.
4708  */
4709  if (to_xid >= from_xid)
4710  nxids = to_xid - from_xid + 1;
4711  else
4712  {
4713  nxids = 1;
4714  next_xid = from_xid;
4715  while (TransactionIdPrecedes(next_xid, to_xid))
4716  {
4717  nxids++;
4718  TransactionIdAdvance(next_xid);
4719  }
4720  }
4721 
4722  /*
4723  * Since only the startup process modifies the head/tail pointers, we
4724  * don't need a lock to read them here.
4725  */
4726  head = pArray->headKnownAssignedXids;
4727  tail = pArray->tailKnownAssignedXids;
4728 
4729  Assert(head >= 0 && head <= pArray->maxKnownAssignedXids);
4730  Assert(tail >= 0 && tail < pArray->maxKnownAssignedXids);
4731 
4732  /*
4733  * Verify that insertions occur in TransactionId sequence. Note that even
4734  * if the last existing element is marked invalid, it must still have a
4735  * correctly sequenced XID value.
4736  */
4737  if (head > tail &&
4738  TransactionIdFollowsOrEquals(KnownAssignedXids[head - 1], from_xid))
4739  {
4741  elog(ERROR, "out-of-order XID insertion in KnownAssignedXids");
4742  }
4743 
4744  /*
4745  * If our xids won't fit in the remaining space, compress out free space
4746  */
4747  if (head + nxids > pArray->maxKnownAssignedXids)
4748  {
4749  KnownAssignedXidsCompress(KAX_NO_SPACE, exclusive_lock);
4750 
4751  head = pArray->headKnownAssignedXids;
4752  /* note: we no longer care about the tail pointer */
4753 
4754  /*
4755  * If it still won't fit then we're out of memory
4756  */
4757  if (head + nxids > pArray->maxKnownAssignedXids)
4758  elog(ERROR, "too many KnownAssignedXids");
4759  }
4760 
4761  /* Now we can insert the xids into the space starting at head */
4762  next_xid = from_xid;
4763  for (i = 0; i < nxids; i++)
4764  {
4765  KnownAssignedXids[head] = next_xid;
4766  KnownAssignedXidsValid[head] = true;
4767  TransactionIdAdvance(next_xid);
4768  head++;
4769  }
4770 
4771  /* Adjust count of number of valid entries */
4772  pArray->numKnownAssignedXids += nxids;
4773 
4774  /*
4775  * Now update the head pointer. We use a write barrier to ensure that
4776  * other processors see the above array updates before they see the head
4777  * pointer change. The barrier isn't required if we're holding
4778  * ProcArrayLock exclusively.
4779  */
4780  if (!exclusive_lock)
4781  pg_write_barrier();
4782 
4783  pArray->headKnownAssignedXids = head;
4784 }
#define pg_write_barrier()
Definition: atomics.h:154
#define LOG
Definition: elog.h:31
static void KnownAssignedXidsDisplay(int trace_level)
Definition: procarray.c:5128
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:329

References Assert(), elog(), ERROR, ProcArrayStruct::headKnownAssignedXids, i, KAX_NO_SPACE, KnownAssignedXids, KnownAssignedXidsCompress(), KnownAssignedXidsDisplay(), KnownAssignedXidsValid, LOG, ProcArrayStruct::maxKnownAssignedXids, ProcArrayStruct::numKnownAssignedXids, pg_write_barrier, procArray, ProcArrayStruct::tailKnownAssignedXids, TransactionIdAdvance, TransactionIdFollowsOrEquals(), TransactionIdPrecedes(), and TransactionIdPrecedesOrEquals().

Referenced by ProcArrayApplyRecoveryInfo(), and RecordKnownAssignedTransactionIds().

◆ KnownAssignedXidsCompress()

static void KnownAssignedXidsCompress ( KAXCompressReason  reason,
bool  haveLock 
)
static

Definition at line 4575 of file procarray.c.

4576 {
4577  ProcArrayStruct *pArray = procArray;
4578  int head,
4579  tail,
4580  nelements;
4581  int compress_index;
4582  int i;
4583 
4584  /* Counters for compression heuristics */
4585  static unsigned int transactionEndsCounter;
4586  static TimestampTz lastCompressTs;
4587 
4588  /* Tuning constants */
4589 #define KAX_COMPRESS_FREQUENCY 128 /* in transactions */
4590 #define KAX_COMPRESS_IDLE_INTERVAL 1000 /* in ms */
4591 
4592  /*
4593  * Since only the startup process modifies the head/tail pointers, we
4594  * don't need a lock to read them here.
4595  */
4596  head = pArray->headKnownAssignedXids;
4597  tail = pArray->tailKnownAssignedXids;
4598  nelements = head - tail;
4599 
4600  /*
4601  * If we can choose whether to compress, use a heuristic to avoid
4602  * compressing too often or not often enough. "Compress" here simply
4603  * means moving the values to the beginning of the array, so it is not as
4604  * complex or costly as typical data compression algorithms.
4605  */
4606  if (nelements == pArray->numKnownAssignedXids)
4607  {
4608  /*
4609  * When there are no gaps between head and tail, don't bother to
4610  * compress, except in the KAX_NO_SPACE case where we must compress to
4611  * create some space after the head.
4612  */
4613  if (reason != KAX_NO_SPACE)
4614  return;
4615  }
4616  else if (reason == KAX_TRANSACTION_END)
4617  {
4618  /*
4619  * Consider compressing only once every so many commits. Frequency
4620  * determined by benchmarks.
4621  */
4622  if ((transactionEndsCounter++) % KAX_COMPRESS_FREQUENCY != 0)
4623  return;
4624 
4625  /*
4626  * Furthermore, compress only if the used part of the array is less
4627  * than 50% full (see comments above).
4628  */
4629  if (nelements < 2 * pArray->numKnownAssignedXids)
4630  return;
4631  }
4632  else if (reason == KAX_STARTUP_PROCESS_IDLE)
4633  {
4634  /*
4635  * We're about to go idle for lack of new WAL, so we might as well
4636  * compress. But not too often, to avoid ProcArray lock contention
4637  * with readers.
4638  */
4639  if (lastCompressTs != 0)
4640  {
4641  TimestampTz compress_after;
4642 
4643  compress_after = TimestampTzPlusMilliseconds(lastCompressTs,
4645  if (GetCurrentTimestamp() < compress_after)
4646  return;
4647  }
4648  }
4649 
4650  /* Need to compress, so get the lock if we don't have it. */
4651  if (!haveLock)
4652  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4653 
4654  /*
4655  * We compress the array by reading the valid values from tail to head,
4656  * re-aligning data to 0th element.
4657  */
4658  compress_index = 0;
4659  for (i = tail; i < head; i++)
4660  {
4662  {
4663  KnownAssignedXids[compress_index] = KnownAssignedXids[i];
4664  KnownAssignedXidsValid[compress_index] = true;
4665  compress_index++;
4666  }
4667  }
4668  Assert(compress_index == pArray->numKnownAssignedXids);
4669 
4670  pArray->tailKnownAssignedXids = 0;
4671  pArray->headKnownAssignedXids = compress_index;
4672 
4673  if (!haveLock)
4674  LWLockRelease(ProcArrayLock);
4675 
4676  /* Update timestamp for maintenance. No need to hold lock for this. */
4677  lastCompressTs = GetCurrentTimestamp();
4678 }
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1583
int64 TimestampTz
Definition: timestamp.h:39
#define KAX_COMPRESS_FREQUENCY
#define KAX_COMPRESS_IDLE_INTERVAL
#define TimestampTzPlusMilliseconds(tz, ms)
Definition: timestamp.h:85

References Assert(), GetCurrentTimestamp(), ProcArrayStruct::headKnownAssignedXids, i, KAX_COMPRESS_FREQUENCY, KAX_COMPRESS_IDLE_INTERVAL, KAX_NO_SPACE, KAX_STARTUP_PROCESS_IDLE, KAX_TRANSACTION_END, KnownAssignedXids, KnownAssignedXidsValid, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::numKnownAssignedXids, procArray, ProcArrayStruct::tailKnownAssignedXids, and TimestampTzPlusMilliseconds.

Referenced by KnownAssignedTransactionIdsIdleMaintenance(), KnownAssignedXidsAdd(), KnownAssignedXidsRemovePreceding(), and KnownAssignedXidsRemoveTree().

◆ KnownAssignedXidsDisplay()

static void KnownAssignedXidsDisplay ( int  trace_level)
static

Definition at line 5128 of file procarray.c.

5129 {
5130  ProcArrayStruct *pArray = procArray;
5132  int head,
5133  tail,
5134  i;
5135  int nxids = 0;
5136 
5137  tail = pArray->tailKnownAssignedXids;
5138  head = pArray->headKnownAssignedXids;
5139 
5140  initStringInfo(&buf);
5141 
5142  for (i = tail; i < head; i++)
5143  {
5145  {
5146  nxids++;
5147  appendStringInfo(&buf, "[%d]=%u ", i, KnownAssignedXids[i]);
5148  }
5149  }
5150 
5151  elog(trace_level, "%d KnownAssignedXids (num=%d tail=%d head=%d) %s",
5152  nxids,
5153  pArray->numKnownAssignedXids,
5154  pArray->tailKnownAssignedXids,
5155  pArray->headKnownAssignedXids,
5156  buf.data);
5157 
5158  pfree(buf.data);
5159 }
void pfree(void *pointer)
Definition: mcxt.c:1456
static char * buf
Definition: pg_test_fsync.c:67
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59

References appendStringInfo(), buf, elog(), ProcArrayStruct::headKnownAssignedXids, i, initStringInfo(), KnownAssignedXids, KnownAssignedXidsValid, ProcArrayStruct::numKnownAssignedXids, pfree(), procArray, and ProcArrayStruct::tailKnownAssignedXids.

Referenced by KnownAssignedXidsAdd(), and ProcArrayApplyRecoveryInfo().

◆ KnownAssignedXidsGet()

static int KnownAssignedXidsGet ( TransactionId xarray,
TransactionId  xmax 
)
static

Definition at line 5023 of file procarray.c.

5024 {
5026 
5027  return KnownAssignedXidsGetAndSetXmin(xarray, &xtmp, xmax);
5028 }

References InvalidTransactionId, and KnownAssignedXidsGetAndSetXmin().

Referenced by TransactionIdIsInProgress().

◆ KnownAssignedXidsGetAndSetXmin()

static int KnownAssignedXidsGetAndSetXmin ( TransactionId xarray,
TransactionId xmin,
TransactionId  xmax 
)
static

Definition at line 5037 of file procarray.c.

5039 {
5040  int count = 0;
5041  int head,
5042  tail;
5043  int i;
5044 
5045  /*
5046  * Fetch head just once, since it may change while we loop. We can stop
5047  * once we reach the initially seen head, since we are certain that an xid
5048  * cannot enter and then leave the array while we hold ProcArrayLock. We
5049  * might miss newly-added xids, but they should be >= xmax so irrelevant
5050  * anyway.
5051  */
5054 
5055  pg_read_barrier(); /* pairs with KnownAssignedXidsAdd */
5056 
5057  for (i = tail; i < head; i++)
5058  {
5059  /* Skip any gaps in the array */
5061  {
5062  TransactionId knownXid = KnownAssignedXids[i];
5063 
5064  /*
5065  * Update xmin if required. Only the first XID need be checked,
5066  * since the array is sorted.
5067  */
5068  if (count == 0 &&
5069  TransactionIdPrecedes(knownXid, *xmin))
5070  *xmin = knownXid;
5071 
5072  /*
5073  * Filter out anything >= xmax, again relying on sorted property
5074  * of array.
5075  */
5076  if (TransactionIdIsValid(xmax) &&
5077  TransactionIdFollowsOrEquals(knownXid, xmax))
5078  break;
5079 
5080  /* Add knownXid into output array */
5081  xarray[count++] = knownXid;
5082  }
5083  }
5084 
5085  return count;
5086 }

References ProcArrayStruct::headKnownAssignedXids, i, KnownAssignedXids, KnownAssignedXidsValid, pg_read_barrier, procArray, ProcArrayStruct::tailKnownAssignedXids, TransactionIdFollowsOrEquals(), TransactionIdIsValid, and TransactionIdPrecedes().

Referenced by GetSnapshotData(), and KnownAssignedXidsGet().

◆ KnownAssignedXidsGetOldestXmin()

static TransactionId KnownAssignedXidsGetOldestXmin ( void  )
static

Definition at line 5093 of file procarray.c.

5094 {
5095  int head,
5096  tail;
5097  int i;
5098 
5099  /*
5100  * Fetch head just once, since it may change while we loop.
5101  */
5104 
5105  pg_read_barrier(); /* pairs with KnownAssignedXidsAdd */
5106 
5107  for (i = tail; i < head; i++)
5108  {
5109  /* Skip any gaps in the array */
5111  return KnownAssignedXids[i];
5112  }
5113 
5114  return InvalidTransactionId;
5115 }

References ProcArrayStruct::headKnownAssignedXids, i, InvalidTransactionId, KnownAssignedXids, KnownAssignedXidsValid, pg_read_barrier, procArray, and ProcArrayStruct::tailKnownAssignedXids.

Referenced by ComputeXidHorizons().

◆ KnownAssignedXidsRemove()

static void KnownAssignedXidsRemove ( TransactionId  xid)
static

Definition at line 4897 of file procarray.c.

4898 {
4900 
4901  elog(trace_recovery(DEBUG4), "remove KnownAssignedXid %u", xid);
4902 
4903  /*
4904  * Note: we cannot consider it an error to remove an XID that's not
4905  * present. We intentionally remove subxact IDs while processing
4906  * XLOG_XACT_ASSIGNMENT, to avoid array overflow. Then those XIDs will be
4907  * removed again when the top-level xact commits or aborts.
4908  *
4909  * It might be possible to track such XIDs to distinguish this case from
4910  * actual errors, but it would be complicated and probably not worth it.
4911  * So, just ignore the search result.
4912  */
4913  (void) KnownAssignedXidsSearch(xid, true);
4914 }
int trace_recovery(int trace_level)
Definition: elog.c:3752
#define DEBUG4
Definition: elog.h:27

References Assert(), DEBUG4, elog(), KnownAssignedXidsSearch(), trace_recovery(), and TransactionIdIsValid.

Referenced by KnownAssignedXidsRemoveTree().

◆ KnownAssignedXidsRemovePreceding()

static void KnownAssignedXidsRemovePreceding ( TransactionId  removeXid)
static

Definition at line 4945 of file procarray.c.

4946 {
4947  ProcArrayStruct *pArray = procArray;
4948  int count = 0;
4949  int head,
4950  tail,
4951  i;
4952 
4953  if (!TransactionIdIsValid(removeXid))
4954  {
4955  elog(trace_recovery(DEBUG4), "removing all KnownAssignedXids");
4956  pArray->numKnownAssignedXids = 0;
4957  pArray->headKnownAssignedXids = pArray->tailKnownAssignedXids = 0;
4958  return;
4959  }
4960 
4961  elog(trace_recovery(DEBUG4), "prune KnownAssignedXids to %u", removeXid);
4962 
4963  /*
4964  * Mark entries invalid starting at the tail. Since array is sorted, we
4965  * can stop as soon as we reach an entry >= removeXid.
4966  */
4967  tail = pArray->tailKnownAssignedXids;
4968  head = pArray->headKnownAssignedXids;
4969 
4970  for (i = tail; i < head; i++)
4971  {
4973  {
4974  TransactionId knownXid = KnownAssignedXids[i];
4975 
4976  if (TransactionIdFollowsOrEquals(knownXid, removeXid))
4977  break;
4978 
4979  if (!StandbyTransactionIdIsPrepared(knownXid))
4980  {
4981  KnownAssignedXidsValid[i] = false;
4982  count++;
4983  }
4984  }
4985  }
4986 
4987  pArray->numKnownAssignedXids -= count;
4988  Assert(pArray->numKnownAssignedXids >= 0);
4989 
4990  /*
4991  * Advance the tail pointer if we've marked the tail item invalid.
4992  */
4993  for (i = tail; i < head; i++)
4994  {
4996  break;
4997  }
4998  if (i >= head)
4999  {
5000  /* Array is empty, so we can reset both pointers */
5001  pArray->headKnownAssignedXids = 0;
5002  pArray->tailKnownAssignedXids = 0;
5003  }
5004  else
5005  {
5006  pArray->tailKnownAssignedXids = i;
5007  }
5008 
5009  /* Opportunistically compress the array */
5011 }
bool StandbyTransactionIdIsPrepared(TransactionId xid)
Definition: twophase.c:1453

References Assert(), DEBUG4, elog(), ProcArrayStruct::headKnownAssignedXids, i, KAX_PRUNE, KnownAssignedXids, KnownAssignedXidsCompress(), KnownAssignedXidsValid, ProcArrayStruct::numKnownAssignedXids, procArray, StandbyTransactionIdIsPrepared(), ProcArrayStruct::tailKnownAssignedXids, trace_recovery(), TransactionIdFollowsOrEquals(), and TransactionIdIsValid.

Referenced by ExpireAllKnownAssignedTransactionIds(), and ExpireOldKnownAssignedTransactionIds().

◆ KnownAssignedXidsRemoveTree()

static void KnownAssignedXidsRemoveTree ( TransactionId  xid,
int  nsubxids,
TransactionId subxids 
)
static

Definition at line 4923 of file procarray.c.

4925 {
4926  int i;
4927 
4928  if (TransactionIdIsValid(xid))
4930 
4931  for (i = 0; i < nsubxids; i++)
4932  KnownAssignedXidsRemove(subxids[i]);
4933 
4934  /* Opportunistically compress the array */
4936 }
static void KnownAssignedXidsRemove(TransactionId xid)
Definition: procarray.c:4897

References i, KAX_TRANSACTION_END, KnownAssignedXidsCompress(), KnownAssignedXidsRemove(), and TransactionIdIsValid.

Referenced by ExpireTreeKnownAssignedTransactionIds(), and ProcArrayApplyXidAssignment().

◆ KnownAssignedXidsReset()

static void KnownAssignedXidsReset ( void  )
static

Definition at line 5166 of file procarray.c.

5167 {
5168  ProcArrayStruct *pArray = procArray;
5169 
5170  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
5171 
5172  pArray->numKnownAssignedXids = 0;
5173  pArray->tailKnownAssignedXids = 0;
5174  pArray->headKnownAssignedXids = 0;
5175 
5176  LWLockRelease(ProcArrayLock);
5177 }

References ProcArrayStruct::headKnownAssignedXids, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::numKnownAssignedXids, procArray, and ProcArrayStruct::tailKnownAssignedXids.

Referenced by ProcArrayApplyRecoveryInfo().

◆ KnownAssignedXidsSearch()

static bool KnownAssignedXidsSearch ( TransactionId  xid,
bool  remove 
)
static

Definition at line 4796 of file procarray.c.

4797 {
4798  ProcArrayStruct *pArray = procArray;
4799  int first,
4800  last;
4801  int head;
4802  int tail;
4803  int result_index = -1;
4804 
4805  tail = pArray->tailKnownAssignedXids;
4806  head = pArray->headKnownAssignedXids;
4807 
4808  /*
4809  * Only the startup process removes entries, so we don't need the read
4810  * barrier in that case.
4811  */
4812  if (!remove)
4813  pg_read_barrier(); /* pairs with KnownAssignedXidsAdd */
4814 
4815  /*
4816  * Standard binary search. Note we can ignore the KnownAssignedXidsValid
4817  * array here, since even invalid entries will contain sorted XIDs.
4818  */
4819  first = tail;
4820  last = head - 1;
4821  while (first <= last)
4822  {
4823  int mid_index;
4824  TransactionId mid_xid;
4825 
4826  mid_index = (first + last) / 2;
4827  mid_xid = KnownAssignedXids[mid_index];
4828 
4829  if (xid == mid_xid)
4830  {
4831  result_index = mid_index;
4832  break;
4833  }
4834  else if (TransactionIdPrecedes(xid, mid_xid))
4835  last = mid_index - 1;
4836  else
4837  first = mid_index + 1;
4838  }
4839 
4840  if (result_index < 0)
4841  return false; /* not in array */
4842 
4843  if (!KnownAssignedXidsValid[result_index])
4844  return false; /* in array, but invalid */
4845 
4846  if (remove)
4847  {
4848  KnownAssignedXidsValid[result_index] = false;
4849 
4850  pArray->numKnownAssignedXids--;
4851  Assert(pArray->numKnownAssignedXids >= 0);
4852 
4853  /*
4854  * If we're removing the tail element then advance tail pointer over
4855  * any invalid elements. This will speed future searches.
4856  */
4857  if (result_index == tail)
4858  {
4859  tail++;
4860  while (tail < head && !KnownAssignedXidsValid[tail])
4861  tail++;
4862  if (tail >= head)
4863  {
4864  /* Array is empty, so we can reset both pointers */
4865  pArray->headKnownAssignedXids = 0;
4866  pArray->tailKnownAssignedXids = 0;
4867  }
4868  else
4869  {
4870  pArray->tailKnownAssignedXids = tail;
4871  }
4872  }
4873  }
4874 
4875  return true;
4876 }

References Assert(), ProcArrayStruct::headKnownAssignedXids, KnownAssignedXids, KnownAssignedXidsValid, ProcArrayStruct::numKnownAssignedXids, pg_read_barrier, procArray, ProcArrayStruct::tailKnownAssignedXids, and TransactionIdPrecedes().

Referenced by KnownAssignedXidExists(), and KnownAssignedXidsRemove().

◆ MaintainLatestCompletedXid()

◆ MaintainLatestCompletedXidRecovery()

static void MaintainLatestCompletedXidRecovery ( TransactionId  latestXid)
static

Definition at line 988 of file procarray.c.

989 {
991  FullTransactionId rel;
992 
994  Assert(LWLockHeldByMe(ProcArrayLock));
995 
996  /*
997  * Need a FullTransactionId to compare latestXid with. Can't rely on
998  * latestCompletedXid to be initialized in recovery. But in recovery it's
999  * safe to access nextXid without a lock for the startup process.
1000  */
1001  rel = ShmemVariableCache->nextXid;
1003 
1004  if (!FullTransactionIdIsValid(cur_latest) ||
1005  TransactionIdPrecedes(XidFromFullTransactionId(cur_latest), latestXid))
1006  {
1008  FullXidRelativeTo(rel, latestXid);
1009  }
1010 
1012 }
bool IsUnderPostmaster
Definition: globals.c:113
#define AmStartupProcess()
Definition: miscadmin.h:452

References AmStartupProcess, Assert(), FullTransactionIdIsNormal, FullTransactionIdIsValid, FullXidRelativeTo(), IsUnderPostmaster, VariableCacheData::latestCompletedXid, LWLockHeldByMe(), VariableCacheData::nextXid, ShmemVariableCache, TransactionIdPrecedes(), and XidFromFullTransactionId.

Referenced by ExpireTreeKnownAssignedTransactionIds(), and ProcArrayApplyRecoveryInfo().

◆ MinimumActiveBackends()

bool MinimumActiveBackends ( int  min)

Definition at line 3453 of file procarray.c.

3454 {
3455  ProcArrayStruct *arrayP = procArray;
3456  int count = 0;
3457  int index;
3458 
3459  /* Quick short-circuit if no minimum is specified */
3460  if (min == 0)
3461  return true;
3462 
3463  /*
3464  * Note: for speed, we don't acquire ProcArrayLock. This is a little bit
3465  * bogus, but since we are only testing fields for zero or nonzero, it
3466  * should be OK. The result is only used for heuristic purposes anyway...
3467  */
3468  for (index = 0; index < arrayP->numProcs; index++)
3469  {
3470  int pgprocno = arrayP->pgprocnos[index];
3471  PGPROC *proc = &allProcs[pgprocno];
3472 
3473  /*
3474  * Since we're not holding a lock, need to be prepared to deal with
3475  * garbage, as someone could have incremented numProcs but not yet
3476  * filled the structure.
3477  *
3478  * If someone just decremented numProcs, 'proc' could also point to a
3479  * PGPROC entry that's no longer in the array. It still points to a
3480  * PGPROC struct, though, because freed PGPROC entries just go to the
3481  * free list and are recycled. Its contents are nonsense in that case,
3482  * but that's acceptable for this function.
3483  */
3484  if (pgprocno == -1)
3485  continue; /* do not count deleted entries */
3486  if (proc == MyProc)
3487  continue; /* do not count myself */
3488  if (proc->xid == InvalidTransactionId)
3489  continue; /* do not count if no XID assigned */
3490  if (proc->pid == 0)
3491  continue; /* do not count prepared xacts */
3492  if (proc->waitLock != NULL)
3493  continue; /* do not count if blocked on a lock */
3494  count++;
3495  if (count >= min)
3496  break;
3497  }
3498 
3499  return count >= min;
3500 }
LOCK * waitLock
Definition: proc.h:223

References allProcs, InvalidTransactionId, MyProc, ProcArrayStruct::numProcs, ProcArrayStruct::pgprocnos, PGPROC::pid, procArray, PGPROC::waitLock, and PGPROC::xid.

Referenced by XLogFlush().

◆ ProcArrayAdd()

void ProcArrayAdd ( PGPROC proc)

Definition at line 469 of file procarray.c.

470 {
471  ProcArrayStruct *arrayP = procArray;
472  int index;
473  int movecount;
474 
475  /* See ProcGlobal comment explaining why both locks are held */
476  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
477  LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
478 
479  if (arrayP->numProcs >= arrayP->maxProcs)
480  {
481  /*
482  * Oops, no room. (This really shouldn't happen, since there is a
483  * fixed supply of PGPROC structs too, and so we should have failed
484  * earlier.)
485  */
486  ereport(FATAL,
487  (errcode(ERRCODE_TOO_MANY_CONNECTIONS),
488  errmsg("sorry, too many clients already")));
489  }
490 
491  /*
492  * Keep the procs array sorted by (PGPROC *) so that we can utilize
493  * locality of references much better. This is useful while traversing the
494  * ProcArray because there is an increased likelihood of finding the next
495  * PGPROC structure in the cache.
496  *
497  * Since the occurrence of adding/removing a proc is much lower than the
498  * access to the ProcArray itself, the overhead should be marginal
499  */
500  for (index = 0; index < arrayP->numProcs; index++)
501  {
502  int procno PG_USED_FOR_ASSERTS_ONLY = arrayP->pgprocnos[index];
503 
504  Assert(procno >= 0 && procno < (arrayP->maxProcs + NUM_AUXILIARY_PROCS));
505  Assert(allProcs[procno].pgxactoff == index);
506 
507  /* If we have found our right position in the array, break */
508  if (arrayP->pgprocnos[index] > proc->pgprocno)
509  break;
510  }
511 
512  movecount = arrayP->numProcs - index;
513  memmove(&arrayP->pgprocnos[index + 1],
514  &arrayP->pgprocnos[index],
515  movecount * sizeof(*arrayP->pgprocnos));
516  memmove(&ProcGlobal->xids[index + 1],
517  &ProcGlobal->xids[index],
518  movecount * sizeof(*ProcGlobal->xids));
519  memmove(&ProcGlobal->subxidStates[index + 1],
521  movecount * sizeof(*ProcGlobal->subxidStates));
522  memmove(&ProcGlobal->statusFlags[index + 1],
524  movecount * sizeof(*ProcGlobal->statusFlags));
525 
526  arrayP->pgprocnos[index] = proc->pgprocno;
527  proc->pgxactoff = index;
528  ProcGlobal->xids[index] = proc->xid;
531 
532  arrayP->numProcs++;
533 
534  /* adjust pgxactoff for all following PGPROCs */
535  index++;
536  for (; index < arrayP->numProcs; index++)
537  {
538  int procno = arrayP->pgprocnos[index];
539 
540  Assert(procno >= 0 && procno < (arrayP->maxProcs + NUM_AUXILIARY_PROCS));
541  Assert(allProcs[procno].pgxactoff == index - 1);
542 
543  allProcs[procno].pgxactoff = index;
544  }
545 
546  /*
547  * Release in reversed acquisition order, to reduce frequency of having to
548  * wait for XidGenLock while holding ProcArrayLock.
549  */
550  LWLockRelease(XidGenLock);
551  LWLockRelease(ProcArrayLock);
552 }
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:171
#define FATAL
Definition: elog.h:41
#define NUM_AUXILIARY_PROCS
Definition: proc.h:418
uint8 statusFlags
Definition: proc.h:233
XidCacheStatus subxidStatus
Definition: proc.h:254
int pgprocno
Definition: proc.h:191

References allProcs, Assert(), ereport, errcode(), errmsg(), FATAL, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::maxProcs, NUM_AUXILIARY_PROCS, ProcArrayStruct::numProcs, PG_USED_FOR_ASSERTS_ONLY, PGPROC::pgprocno, ProcArrayStruct::pgprocnos, PGPROC::pgxactoff, procArray, ProcGlobal, PGPROC::statusFlags, PROC_HDR::statusFlags, PROC_HDR::subxidStates, PGPROC::subxidStatus, PGPROC::xid, and PROC_HDR::xids.

Referenced by InitProcessPhase2(), and MarkAsPrepared().

◆ ProcArrayApplyRecoveryInfo()

void ProcArrayApplyRecoveryInfo ( RunningTransactions  running)

Definition at line 1053 of file procarray.c.

1054 {
1055  TransactionId *xids;
1056  int nxids;
1057  int i;
1058 
1060  Assert(TransactionIdIsValid(running->nextXid));
1063 
1064  /*
1065  * Remove stale transactions, if any.
1066  */
1068 
1069  /*
1070  * Remove stale locks, if any.
1071  */
1073 
1074  /*
1075  * If our snapshot is already valid, nothing else to do...
1076  */
1078  return;
1079 
1080  /*
1081  * If our initial RunningTransactionsData had an overflowed snapshot then
1082  * we knew we were missing some subxids from our snapshot. If we continue
1083  * to see overflowed snapshots then we might never be able to start up, so
1084  * we make another test to see if our snapshot is now valid. We know that
1085  * the missing subxids are equal to or earlier than nextXid. After we
1086  * initialise we continue to apply changes during recovery, so once the
1087  * oldestRunningXid is later than the nextXid from the initial snapshot we
1088  * know that we no longer have missing information and can mark the
1089  * snapshot as valid.
1090  */
1092  {
1093  /*
1094  * If the snapshot isn't overflowed or if its empty we can reset our
1095  * pending state and use this snapshot instead.
1096  */
1097  if (!running->subxid_overflow || running->xcnt == 0)
1098  {
1099  /*
1100  * If we have already collected known assigned xids, we need to
1101  * throw them away before we apply the recovery snapshot.
1102  */
1105  }
1106  else
1107  {
1109  running->oldestRunningXid))
1110  {
1113  "recovery snapshots are now enabled");
1114  }
1115  else
1117  "recovery snapshot waiting for non-overflowed snapshot or "
1118  "until oldest active xid on standby is at least %u (now %u)",
1120  running->oldestRunningXid);
1121  return;
1122  }
1123  }
1124 
1126 
1127  /*
1128  * NB: this can be reached at least twice, so make sure new code can deal
1129  * with that.
1130  */
1131 
1132  /*
1133  * Nobody else is running yet, but take locks anyhow
1134  */
1135  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
1136 
1137  /*
1138  * KnownAssignedXids is sorted so we cannot just add the xids, we have to
1139  * sort them first.
1140  *
1141  * Some of the new xids are top-level xids and some are subtransactions.
1142  * We don't call SubTransSetParent because it doesn't matter yet. If we
1143  * aren't overflowed then all xids will fit in snapshot and so we don't
1144  * need subtrans. If we later overflow, an xid assignment record will add
1145  * xids to subtrans. If RunningTransactionsData is overflowed then we
1146  * don't have enough information to correctly update subtrans anyway.
1147  */
1148 
1149  /*
1150  * Allocate a temporary array to avoid modifying the array passed as
1151  * argument.
1152  */
1153  xids = palloc(sizeof(TransactionId) * (running->xcnt + running->subxcnt));
1154 
1155  /*
1156  * Add to the temp array any xids which have not already completed.
1157  */
1158  nxids = 0;
1159  for (i = 0; i < running->xcnt + running->subxcnt; i++)
1160  {
1161  TransactionId xid = running->xids[i];
1162 
1163  /*
1164  * The running-xacts snapshot can contain xids that were still visible
1165  * in the procarray when the snapshot was taken, but were already
1166  * WAL-logged as completed. They're not running anymore, so ignore
1167  * them.
1168  */
1170  continue;
1171 
1172  xids[nxids++] = xid;
1173  }
1174 
1175  if (nxids > 0)
1176  {
1177  if (procArray->numKnownAssignedXids != 0)
1178  {
1179  LWLockRelease(ProcArrayLock);
1180  elog(ERROR, "KnownAssignedXids is not empty");
1181  }
1182 
1183  /*
1184  * Sort the array so that we can add them safely into
1185  * KnownAssignedXids.
1186  *
1187  * We have to sort them logically, because in KnownAssignedXidsAdd we
1188  * call TransactionIdFollowsOrEquals and so on. But we know these XIDs
1189  * come from RUNNING_XACTS, which means there are only normal XIDs
1190  * from the same epoch, so this is safe.
1191  */
1192  qsort(xids, nxids, sizeof(TransactionId), xidLogicalComparator);
1193 
1194  /*
1195  * Add the sorted snapshot into KnownAssignedXids. The running-xacts
1196  * snapshot may include duplicated xids because of prepared
1197  * transactions, so ignore them.
1198  */
1199  for (i = 0; i < nxids; i++)
1200  {
1201  if (i > 0 && TransactionIdEquals(xids[i - 1], xids[i]))
1202  {
1203  elog(DEBUG1,
1204  "found duplicated transaction %u for KnownAssignedXids insertion",
1205  xids[i]);
1206  continue;
1207  }
1208  KnownAssignedXidsAdd(xids[i], xids[i], true);
1209  }
1210 
1212  }
1213 
1214  pfree(xids);
1215 
1216  /*
1217  * latestObservedXid is at least set to the point where SUBTRANS was
1218  * started up to (cf. ProcArrayInitRecovery()) or to the biggest xid
1219  * RecordKnownAssignedTransactionIds() was called for. Initialize
1220  * subtrans from thereon, up to nextXid - 1.
1221  *
1222  * We need to duplicate parts of RecordKnownAssignedTransactionId() here,
1223  * because we've just added xids to the known assigned xids machinery that
1224  * haven't gone through RecordKnownAssignedTransactionId().
1225  */
1229  {
1232  }
1233  TransactionIdRetreat(latestObservedXid); /* = running->nextXid - 1 */
1234 
1235  /* ----------
1236  * Now we've got the running xids we need to set the global values that
1237  * are used to track snapshots as they evolve further.
1238  *
1239  * - latestCompletedXid which will be the xmax for snapshots
1240  * - lastOverflowedXid which shows whether snapshots overflow
1241  * - nextXid
1242  *
1243  * If the snapshot overflowed, then we still initialise with what we know,
1244  * but the recovery snapshot isn't fully valid yet because we know there
1245  * are some subxids missing. We don't know the specific subxids that are
1246  * missing, so conservatively assume the last one is latestObservedXid.
1247  * ----------
1248  */
1249  if (running->subxid_overflow)
1250  {
1252 
1255  }
1256  else
1257  {
1259 
1261  }
1262 
1263  /*
1264  * If a transaction wrote a commit record in the gap between taking and
1265  * logging the snapshot then latestCompletedXid may already be higher than
1266  * the value from the snapshot, so check before we use the incoming value.
1267  * It also might not yet be set at all.
1268  */
1270 
1271  /*
1272  * NB: No need to increment ShmemVariableCache->xactCompletionCount here,
1273  * nobody can see it yet.
1274  */
1275 
1276  LWLockRelease(ProcArrayLock);
1277 
1278  /* ShmemVariableCache->nextXid must be beyond any observed xid. */
1280 
1282 
1285  elog(trace_recovery(DEBUG1), "recovery snapshots are now enabled");
1286  else
1288  "recovery snapshot waiting for non-overflowed snapshot or "
1289  "until oldest active xid on standby is at least %u (now %u)",
1291  running->oldestRunningXid);
1292 }
#define DEBUG3
Definition: elog.h:28
#define DEBUG1
Definition: elog.h:30
#define qsort(a, b, c, d)
Definition: port.h:445
static TransactionId standbySnapshotPendingXmin
Definition: procarray.c:291
static TransactionId latestObservedXid
Definition: procarray.c:284
static void KnownAssignedXidsReset(void)
Definition: procarray.c:5166
static void KnownAssignedXidsAdd(TransactionId from_xid, TransactionId to_xid, bool exclusive_lock)
Definition: procarray.c:4692
void ExpireOldKnownAssignedTransactionIds(TransactionId xid)
Definition: procarray.c:4452
void StandbyReleaseOldLocks(TransactionId oldxid)
Definition: standby.c:1128
void ExtendSUBTRANS(TransactionId newestXact)
Definition: subtrans.c:308
bool TransactionIdDidCommit(TransactionId transactionId)
Definition: transam.c:126
bool TransactionIdDidAbort(TransactionId transactionId)
Definition: transam.c:188
#define TransactionIdRetreat(dest)
Definition: transam.h:141
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
void AdvanceNextFullTransactionIdPastXid(TransactionId xid)
Definition: varsup.c:277
int xidLogicalComparator(const void *arg1, const void *arg2)
Definition: xid.c:159
@ STANDBY_SNAPSHOT_READY
Definition: xlogutils.h:52
@ STANDBY_SNAPSHOT_PENDING
Definition: xlogutils.h:51

References AdvanceNextFullTransactionIdPastXid(), Assert(), DEBUG1, DEBUG3, elog(), ERROR, ExpireOldKnownAssignedTransactionIds(), ExtendSUBTRANS(), FullTransactionIdIsValid, i, InvalidTransactionId, KnownAssignedXidsAdd(), KnownAssignedXidsDisplay(), KnownAssignedXidsReset(), ProcArrayStruct::lastOverflowedXid, RunningTransactionsData::latestCompletedXid, latestObservedXid, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MaintainLatestCompletedXidRecovery(), VariableCacheData::nextXid, RunningTransactionsData::nextXid, ProcArrayStruct::numKnownAssignedXids, RunningTransactionsData::oldestRunningXid, palloc(), pfree(), procArray, qsort, ShmemVariableCache, STANDBY_INITIALIZED, STANDBY_SNAPSHOT_PENDING, STANDBY_SNAPSHOT_READY, StandbyReleaseOldLocks(), standbySnapshotPendingXmin, standbyState, RunningTransactionsData::subxcnt, RunningTransactionsData::subxid_overflow, trace_recovery(), TransactionIdAdvance, TransactionIdDidAbort(), TransactionIdDidCommit(), TransactionIdEquals, TransactionIdIsNormal, TransactionIdIsValid, TransactionIdPrecedes(), TransactionIdRetreat, RunningTransactionsData::xcnt, xidLogicalComparator(), and RunningTransactionsData::xids.

Referenced by standby_redo(), StartupXLOG(), and xlog_redo().

◆ ProcArrayApplyXidAssignment()

void ProcArrayApplyXidAssignment ( TransactionId  topxid,
int  nsubxids,
TransactionId subxids 
)

Definition at line 1299 of file procarray.c.

1301 {
1302  TransactionId max_xid;
1303  int i;
1304 
1306 
1307  max_xid = TransactionIdLatest(topxid, nsubxids, subxids);
1308 
1309  /*
1310  * Mark all the subtransactions as observed.
1311  *
1312  * NOTE: This will fail if the subxid contains too many previously
1313  * unobserved xids to fit into known-assigned-xids. That shouldn't happen
1314  * as the code stands, because xid-assignment records should never contain
1315  * more than PGPROC_MAX_CACHED_SUBXIDS entries.
1316  */
1318 
1319  /*
1320  * Notice that we update pg_subtrans with the top-level xid, rather than
1321  * the parent xid. This is a difference between normal processing and
1322  * recovery, yet is still correct in all cases. The reason is that
1323  * subtransaction commit is not marked in clog until commit processing, so
1324  * all aborted subtransactions have already been clearly marked in clog.
1325  * As a result we are able to refer directly to the top-level
1326  * transaction's state rather than skipping through all the intermediate
1327  * states in the subtransaction tree. This should be the first time we
1328  * have attempted to SubTransSetParent().
1329  */
1330  for (i = 0; i < nsubxids; i++)
1331  SubTransSetParent(subxids[i], topxid);
1332 
1333  /* KnownAssignedXids isn't maintained yet, so we're done for now */
1335  return;
1336 
1337  /*
1338  * Uses same locking as transaction commit
1339  */
1340  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
1341 
1342  /*
1343  * Remove subxids from known-assigned-xacts.
1344  */
1346 
1347  /*
1348  * Advance lastOverflowedXid to be at least the last of these subxids.
1349  */
1351  procArray->lastOverflowedXid = max_xid;
1352 
1353  LWLockRelease(ProcArrayLock);
1354 }
void RecordKnownAssignedTransactionIds(TransactionId xid)
Definition: procarray.c:4337
void SubTransSetParent(TransactionId xid, TransactionId parent)
Definition: subtrans.c:74
TransactionId TransactionIdLatest(TransactionId mainxid, int nxids, const TransactionId *xids)
Definition: transam.c:345

References Assert(), i, InvalidTransactionId, KnownAssignedXidsRemoveTree(), ProcArrayStruct::lastOverflowedXid, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), procArray, RecordKnownAssignedTransactionIds(), STANDBY_INITIALIZED, standbyState, SubTransSetParent(), TransactionIdLatest(), and TransactionIdPrecedes().

Referenced by xact_redo().

◆ ProcArrayClearTransaction()

void ProcArrayClearTransaction ( PGPROC proc)

Definition at line 906 of file procarray.c.

907 {
908  int pgxactoff;
909 
910  /*
911  * Currently we need to lock ProcArrayLock exclusively here, as we
912  * increment xactCompletionCount below. We also need it at least in shared
913  * mode for pgproc->pgxactoff to stay the same below.
914  *
915  * We could however, as this action does not actually change anyone's view
916  * of the set of running XIDs (our entry is duplicate with the gxact that
917  * has already been inserted into the ProcArray), lower the lock level to
918  * shared if we were to make xactCompletionCount an atomic variable. But
919  * that doesn't seem worth it currently, as a 2PC commit is heavyweight
920  * enough for this not to be the bottleneck. If it ever becomes a
921  * bottleneck it may also be worth considering to combine this with the
922  * subsequent ProcArrayRemove()
923  */
924  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
925 
926  pgxactoff = proc->pgxactoff;
927 
928  ProcGlobal->xids[pgxactoff] = InvalidTransactionId;
929  proc->xid = InvalidTransactionId;
930 
932  proc->xmin = InvalidTransactionId;
933  proc->recoveryConflictPending = false;
934 
936  Assert(!proc->delayChkptFlags);
937 
938  /*
939  * Need to increment completion count even though transaction hasn't
940  * really committed yet. The reason for that is that GetSnapshotData()
941  * omits the xid of the current transaction, thus without the increment we
942  * otherwise could end up reusing the snapshot later. Which would be bad,
943  * because it might not count the prepared transaction as running.
944  */
946 
947  /* Clear the subtransaction-XID cache too */
948  Assert(ProcGlobal->subxidStates[pgxactoff].count == proc->subxidStatus.count &&
950  if (proc->subxidStatus.count > 0 || proc->subxidStatus.overflowed)
951  {
952  ProcGlobal->subxidStates[pgxactoff].count = 0;
953  ProcGlobal->subxidStates[pgxactoff].overflowed = false;
954  proc->subxidStatus.count = 0;
955  proc->subxidStatus.overflowed = false;
956  }
957 
958  LWLockRelease(ProcArrayLock);
959 }
#define PROC_VACUUM_STATE_MASK
Definition: proc.h:64
LocalTransactionId lxid
Definition: proc.h:183

References Assert(), XidCacheStatus::count, PGPROC::delayChkptFlags, InvalidLocalTransactionId, InvalidTransactionId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), PGPROC::lxid, XidCacheStatus::overflowed, PGPROC::pgxactoff, PROC_VACUUM_STATE_MASK, ProcGlobal, PGPROC::recoveryConflictPending, ShmemVariableCache, PGPROC::statusFlags, PROC_HDR::subxidStates, PGPROC::subxidStatus, VariableCacheData::xactCompletionCount, PGPROC::xid, PROC_HDR::xids, and PGPROC::xmin.

Referenced by PrepareTransaction().

◆ ProcArrayEndTransaction()

void ProcArrayEndTransaction ( PGPROC proc,
TransactionId  latestXid 
)

Definition at line 667 of file procarray.c.

668 {
669  if (TransactionIdIsValid(latestXid))
670  {
671  /*
672  * We must lock ProcArrayLock while clearing our advertised XID, so
673  * that we do not exit the set of "running" transactions while someone
674  * else is taking a snapshot. See discussion in
675  * src/backend/access/transam/README.
676  */
678 
679  /*
680  * If we can immediately acquire ProcArrayLock, we clear our own XID
681  * and release the lock. If not, use group XID clearing to improve
682  * efficiency.
683  */
684  if (LWLockConditionalAcquire(ProcArrayLock, LW_EXCLUSIVE))
685  {
686  ProcArrayEndTransactionInternal(proc, latestXid);
687  LWLockRelease(ProcArrayLock);
688  }
689  else
690  ProcArrayGroupClearXid(proc, latestXid);
691  }
692  else
693  {
694  /*
695  * If we have no XID, we don't need to lock, since we won't affect
696  * anyone else's calculation of a snapshot. We might change their
697  * estimate of global xmin, but that's OK.
698  */
700  Assert(proc->subxidStatus.count == 0);
702 
704  proc->xmin = InvalidTransactionId;
705 
706  /* be sure this is cleared in abort */
707  proc->delayChkptFlags = 0;
708 
709  proc->recoveryConflictPending = false;
710 
711  /* must be cleared with xid/xmin: */
712  /* avoid unnecessarily dirtying shared cachelines */
714  {
715  Assert(!LWLockHeldByMe(ProcArrayLock));
716  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
720  LWLockRelease(ProcArrayLock);
721  }
722  }
723 }
bool LWLockConditionalAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1366
static void ProcArrayEndTransactionInternal(PGPROC *proc, TransactionId latestXid)
Definition: procarray.c:731
static void ProcArrayGroupClearXid(PGPROC *proc, TransactionId latestXid)
Definition: procarray.c:792

References Assert(), XidCacheStatus::count, PGPROC::delayChkptFlags, InvalidLocalTransactionId, InvalidTransactionId, LW_EXCLUSIVE, LWLockAcquire(), LWLockConditionalAcquire(), LWLockHeldByMe(), LWLockRelease(), PGPROC::lxid, XidCacheStatus::overflowed, PGPROC::pgxactoff, PROC_VACUUM_STATE_MASK, ProcArrayEndTransactionInternal(), ProcArrayGroupClearXid(), ProcGlobal, PGPROC::recoveryConflictPending, PGPROC::statusFlags, PROC_HDR::statusFlags, PGPROC::subxidStatus, TransactionIdIsValid, PGPROC::xid, and PGPROC::xmin.

Referenced by AbortTransaction(), and CommitTransaction().

◆ ProcArrayEndTransactionInternal()

static void ProcArrayEndTransactionInternal ( PGPROC proc,
TransactionId  latestXid 
)
inlinestatic

Definition at line 731 of file procarray.c.

732 {
733  int pgxactoff = proc->pgxactoff;
734 
735  /*
736  * Note: we need exclusive lock here because we're going to change other
737  * processes' PGPROC entries.
738  */
739  Assert(LWLockHeldByMeInMode(ProcArrayLock, LW_EXCLUSIVE));
741  Assert(ProcGlobal->xids[pgxactoff] == proc->xid);
742 
743  ProcGlobal->xids[pgxactoff] = InvalidTransactionId;
744  proc->xid = InvalidTransactionId;
746  proc->xmin = InvalidTransactionId;
747 
748  /* be sure this is cleared in abort */
749  proc->delayChkptFlags = 0;
750 
751  proc->recoveryConflictPending = false;
752 
753  /* must be cleared with xid/xmin: */
754  /* avoid unnecessarily dirtying shared cachelines */
756  {
759  }
760 
761  /* Clear the subtransaction-XID cache too while holding the lock */
762  Assert(ProcGlobal->subxidStates[pgxactoff].count == proc->subxidStatus.count &&
764  if (proc->subxidStatus.count > 0 || proc->subxidStatus.overflowed)
765  {
766  ProcGlobal->subxidStates[pgxactoff].count = 0;
767  ProcGlobal->subxidStates[pgxactoff].overflowed = false;
768  proc->subxidStatus.count = 0;
769  proc->subxidStatus.overflowed = false;
770  }
771 
772  /* Also advance global latestCompletedXid while holding the lock */
773  MaintainLatestCompletedXid(latestXid);
774 
775  /* Same with xactCompletionCount */
777 }
bool LWLockHeldByMeInMode(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1964
static void MaintainLatestCompletedXid(TransactionId latestXid)
Definition: procarray.c:966

References Assert(), XidCacheStatus::count, PGPROC::delayChkptFlags, InvalidLocalTransactionId, InvalidTransactionId, LW_EXCLUSIVE, LWLockHeldByMeInMode(), PGPROC::lxid, MaintainLatestCompletedXid(), XidCacheStatus::overflowed, PGPROC::pgxactoff, PROC_VACUUM_STATE_MASK, ProcGlobal, PGPROC::recoveryConflictPending, ShmemVariableCache, PGPROC::statusFlags, PROC_HDR::statusFlags, PROC_HDR::subxidStates, PGPROC::subxidStatus, TransactionIdIsValid, VariableCacheData::xactCompletionCount, PGPROC::xid, PROC_HDR::xids, and PGPROC::xmin.

Referenced by ProcArrayEndTransaction(), and ProcArrayGroupClearXid().

◆ ProcArrayGetReplicationSlotXmin()

void ProcArrayGetReplicationSlotXmin ( TransactionId xmin,
TransactionId catalog_xmin 
)

Definition at line 3872 of file procarray.c.

3874 {
3875  LWLockAcquire(ProcArrayLock, LW_SHARED);
3876 
3877  if (xmin != NULL)
3879 
3880  if (catalog_xmin != NULL)
3881  *catalog_xmin = procArray->replication_slot_catalog_xmin;
3882 
3883  LWLockRelease(ProcArrayLock);
3884 }

References LW_SHARED, LWLockAcquire(), LWLockRelease(), procArray, ProcArrayStruct::replication_slot_catalog_xmin, and ProcArrayStruct::replication_slot_xmin.

Referenced by logical_begin_heap_rewrite().

◆ ProcArrayGroupClearXid()

static void ProcArrayGroupClearXid ( PGPROC proc,
TransactionId  latestXid 
)
static

Definition at line 792 of file procarray.c.

793 {
794  PROC_HDR *procglobal = ProcGlobal;
795  uint32 nextidx;
796  uint32 wakeidx;
797 
798  /* We should definitely have an XID to clear. */
800 
801  /* Add ourselves to the list of processes needing a group XID clear. */
802  proc->procArrayGroupMember = true;
803  proc->procArrayGroupMemberXid = latestXid;
804  nextidx = pg_atomic_read_u32(&procglobal->procArrayGroupFirst);
805  while (true)
806  {
807  pg_atomic_write_u32(&proc->procArrayGroupNext, nextidx);
808 
810  &nextidx,
811  (uint32) proc->pgprocno))
812  break;
813  }
814 
815  /*
816  * If the list was not empty, the leader will clear our XID. It is
817  * impossible to have followers without a leader because the first process
818  * that has added itself to the list will always have nextidx as
819  * INVALID_PGPROCNO.
820  */
821  if (nextidx != INVALID_PGPROCNO)
822  {
823  int extraWaits = 0;
824 
825  /* Sleep until the leader clears our XID. */
826  pgstat_report_wait_start(WAIT_EVENT_PROCARRAY_GROUP_UPDATE);
827  for (;;)
828  {
829  /* acts as a read barrier */
830  PGSemaphoreLock(proc->sem);
831  if (!proc->procArrayGroupMember)
832  break;
833  extraWaits++;
834  }
836 
838 
839  /* Fix semaphore count for any absorbed wakeups */
840  while (extraWaits-- > 0)
841  PGSemaphoreUnlock(proc->sem);
842  return;
843  }
844 
845  /* We are the leader. Acquire the lock on behalf of everyone. */
846  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
847 
848  /*
849  * Now that we've got the lock, clear the list of processes waiting for
850  * group XID clearing, saving a pointer to the head of the list. Trying
851  * to pop elements one at a time could lead to an ABA problem.
852  */
853  nextidx = pg_atomic_exchange_u32(&procglobal->procArrayGroupFirst,
855 
856  /* Remember head of list so we can perform wakeups after dropping lock. */
857  wakeidx = nextidx;
858 
859  /* Walk the list and clear all XIDs. */
860  while (nextidx != INVALID_PGPROCNO)
861  {
862  PGPROC *nextproc = &allProcs[nextidx];
863 
865 
866  /* Move to next proc in list. */
867  nextidx = pg_atomic_read_u32(&nextproc->procArrayGroupNext);
868  }
869 
870  /* We're done with the lock now. */
871  LWLockRelease(ProcArrayLock);
872 
873  /*
874  * Now that we've released the lock, go back and wake everybody up. We
875  * don't do this under the lock so as to keep lock hold times to a
876  * minimum. The system calls we need to perform to wake other processes
877  * up are probably much slower than the simple memory writes we did while
878  * holding the lock.
879  */
880  while (wakeidx != INVALID_PGPROCNO)
881  {
882  PGPROC *nextproc = &allProcs[wakeidx];
883 
884  wakeidx = pg_atomic_read_u32(&nextproc->procArrayGroupNext);
886 
887  /* ensure all previous writes are visible before follower continues. */
889 
890  nextproc->procArrayGroupMember = false;
891 
892  if (nextproc != MyProc)
893  PGSemaphoreUnlock(nextproc->sem);
894  }
895 }
static bool pg_atomic_compare_exchange_u32(volatile pg_atomic_uint32 *ptr, uint32 *expected, uint32 newval)
Definition: atomics.h:306
static void pg_atomic_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition: atomics.h:253
static uint32 pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
Definition: atomics.h:236
static uint32 pg_atomic_exchange_u32(volatile pg_atomic_uint32 *ptr, uint32 newval)
Definition: atomics.h:287
unsigned int uint32
Definition: c.h:495
void PGSemaphoreUnlock(PGSemaphore sema)
Definition: posix_sema.c:340
void PGSemaphoreLock(PGSemaphore sema)
Definition: posix_sema.c:320
#define INVALID_PGPROCNO
Definition: proc.h:85
bool procArrayGroupMember
Definition: proc.h:260
pg_atomic_uint32 procArrayGroupNext
Definition: proc.h:262
TransactionId procArrayGroupMemberXid
Definition: proc.h:268
PGSemaphore sem
Definition: proc.h:167
Definition: proc.h:360
pg_atomic_uint32 procArrayGroupFirst
Definition: proc.h:390
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: wait_event.h:88
static void pgstat_report_wait_end(void)
Definition: wait_event.h:104

References allProcs, Assert(), INVALID_PGPROCNO, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MyProc, pg_atomic_compare_exchange_u32(), pg_atomic_exchange_u32(), pg_atomic_read_u32(), pg_atomic_write_u32(), pg_write_barrier, PGPROC::pgprocno, PGSemaphoreLock(), PGSemaphoreUnlock(), pgstat_report_wait_end(), pgstat_report_wait_start(), ProcArrayEndTransactionInternal(), PROC_HDR::procArrayGroupFirst, PGPROC::procArrayGroupMember, PGPROC::procArrayGroupMemberXid, PGPROC::procArrayGroupNext, ProcGlobal, PGPROC::sem, TransactionIdIsValid, and PGPROC::xid.

Referenced by ProcArrayEndTransaction().

◆ ProcArrayInitRecovery()

void ProcArrayInitRecovery ( TransactionId  initializedUptoXID)

Definition at line 1022 of file procarray.c.

1023 {
1025  Assert(TransactionIdIsNormal(initializedUptoXID));
1026 
1027  /*
1028  * we set latestObservedXid to the xid SUBTRANS has been initialized up
1029  * to, so we can extend it from that point onwards in
1030  * RecordKnownAssignedTransactionIds, and when we get consistent in
1031  * ProcArrayApplyRecoveryInfo().
1032  */
1033  latestObservedXid = initializedUptoXID;
1035 }

References Assert(), latestObservedXid, STANDBY_INITIALIZED, standbyState, TransactionIdIsNormal, and TransactionIdRetreat.

Referenced by StartupXLOG().

◆ ProcArrayInstallImportedXmin()

bool ProcArrayInstallImportedXmin ( TransactionId  xmin,
VirtualTransactionId sourcevxid 
)

Definition at line 2518 of file procarray.c.

2520 {
2521  bool result = false;
2522  ProcArrayStruct *arrayP = procArray;
2523  int index;
2524 
2526  if (!sourcevxid)
2527  return false;
2528 
2529  /* Get lock so source xact can't end while we're doing this */
2530  LWLockAcquire(ProcArrayLock, LW_SHARED);
2531 
2532  for (index = 0; index < arrayP->numProcs; index++)
2533  {
2534  int pgprocno = arrayP->pgprocnos[index];
2535  PGPROC *proc = &allProcs[pgprocno];
2536  int statusFlags = ProcGlobal->statusFlags[index];
2537  TransactionId xid;
2538 
2539  /* Ignore procs running LAZY VACUUM */
2540  if (statusFlags & PROC_IN_VACUUM)
2541  continue;
2542 
2543  /* We are only interested in the specific virtual transaction. */
2544  if (proc->backendId != sourcevxid->backendId)
2545  continue;
2546  if (proc->lxid != sourcevxid->localTransactionId)
2547  continue;
2548 
2549  /*
2550  * We check the transaction's database ID for paranoia's sake: if it's
2551  * in another DB then its xmin does not cover us. Caller should have
2552  * detected this already, so we just treat any funny cases as
2553  * "transaction not found".
2554  */
2555  if (proc->databaseId != MyDatabaseId)
2556  continue;
2557 
2558  /*
2559  * Likewise, let's just make real sure its xmin does cover us.
2560  */
2561  xid = UINT32_ACCESS_ONCE(proc->xmin);
2562  if (!TransactionIdIsNormal(xid) ||
2563  !TransactionIdPrecedesOrEquals(xid, xmin))
2564  continue;
2565 
2566  /*
2567  * We're good. Install the new xmin. As in GetSnapshotData, set
2568  * TransactionXmin too. (Note that because snapmgr.c called
2569  * GetSnapshotData first, we'll be overwriting a valid xmin here, so
2570  * we don't check that.)
2571  */
2572  MyProc->xmin = TransactionXmin = xmin;
2573 
2574  result = true;
2575  break;
2576  }
2577 
2578  LWLockRelease(ProcArrayLock);
2579 
2580  return result;
2581 }
BackendId backendId
Definition: proc.h:197

References allProcs, Assert(), VirtualTransactionId::backendId, PGPROC::backendId, PGPROC::databaseId, VirtualTransactionId::localTransactionId, LW_SHARED, LWLockAcquire(), LWLockRelease(), PGPROC::lxid, MyDatabaseId, MyProc, ProcArrayStruct::numProcs, ProcArrayStruct::pgprocnos, PROC_IN_VACUUM, procArray, ProcGlobal, PROC_HDR::statusFlags, TransactionIdIsNormal, TransactionIdPrecedesOrEquals(), TransactionXmin, UINT32_ACCESS_ONCE, and PGPROC::xmin.

Referenced by GetSerializableTransactionSnapshotInt(), and SetTransactionSnapshot().

◆ ProcArrayInstallRestoredXmin()

bool ProcArrayInstallRestoredXmin ( TransactionId  xmin,
PGPROC proc 
)

Definition at line 2597 of file procarray.c.

2598 {
2599  bool result = false;
2600  TransactionId xid;
2601 
2603  Assert(proc != NULL);
2604 
2605  /*
2606  * Get an exclusive lock so that we can copy statusFlags from source proc.
2607  */
2608  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
2609 
2610  /*
2611  * Be certain that the referenced PGPROC has an advertised xmin which is
2612  * no later than the one we're installing, so that the system-wide xmin
2613  * can't go backwards. Also, make sure it's running in the same database,
2614  * so that the per-database xmin cannot go backwards.
2615  */
2616  xid = UINT32_ACCESS_ONCE(proc->xmin);
2617  if (proc->databaseId == MyDatabaseId &&
2618  TransactionIdIsNormal(xid) &&
2619  TransactionIdPrecedesOrEquals(xid, xmin))
2620  {
2621  /*
2622  * Install xmin and propagate the statusFlags that affect how the
2623  * value is interpreted by vacuum.
2624  */
2625  MyProc->xmin = TransactionXmin = xmin;
2627  (proc->statusFlags & PROC_XMIN_FLAGS);
2629 
2630  result = true;
2631  }
2632 
2633  LWLockRelease(ProcArrayLock);
2634 
2635  return result;
2636 }
#define PROC_XMIN_FLAGS
Definition: proc.h:71

References Assert(), PGPROC::databaseId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MyDatabaseId, MyProc, PGPROC::pgxactoff, PROC_XMIN_FLAGS, ProcGlobal, PGPROC::statusFlags, PROC_HDR::statusFlags, TransactionIdIsNormal, TransactionIdPrecedesOrEquals(), TransactionXmin, UINT32_ACCESS_ONCE, and PGPROC::xmin.

Referenced by SetTransactionSnapshot().

◆ ProcArrayRemove()

void ProcArrayRemove ( PGPROC proc,
TransactionId  latestXid 
)

Definition at line 565 of file procarray.c.

566 {
567  ProcArrayStruct *arrayP = procArray;
568  int myoff;
569  int movecount;
570 
571 #ifdef XIDCACHE_DEBUG
572  /* dump stats at backend shutdown, but not prepared-xact end */
573  if (proc->pid != 0)
574  DisplayXidCache();
575 #endif
576 
577  /* See ProcGlobal comment explaining why both locks are held */
578  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
579  LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
580 
581  myoff = proc->pgxactoff;
582 
583  Assert(myoff >= 0 && myoff < arrayP->numProcs);
584  Assert(ProcGlobal->allProcs[arrayP->pgprocnos[myoff]].pgxactoff == myoff);
585 
586  if (TransactionIdIsValid(latestXid))
587  {
589 
590  /* Advance global latestCompletedXid while holding the lock */
591  MaintainLatestCompletedXid(latestXid);
592 
593  /* Same with xactCompletionCount */
595 
597  ProcGlobal->subxidStates[myoff].overflowed = false;
598  ProcGlobal->subxidStates[myoff].count = 0;
599  }
600  else
601  {
602  /* Shouldn't be trying to remove a live transaction here */
604  }
605 
607  Assert(ProcGlobal->subxidStates[myoff].count == 0);
608  Assert(ProcGlobal->subxidStates[myoff].overflowed == false);
609 
610  ProcGlobal->statusFlags[myoff] = 0;
611 
612  /* Keep the PGPROC array sorted. See notes above */
613  movecount = arrayP->numProcs - myoff - 1;
614  memmove(&arrayP->pgprocnos[myoff],
615  &arrayP->pgprocnos[myoff + 1],
616  movecount * sizeof(*arrayP->pgprocnos));
617  memmove(&ProcGlobal->xids[myoff],
618  &ProcGlobal->xids[myoff + 1],
619  movecount * sizeof(*ProcGlobal->xids));
620  memmove(&ProcGlobal->subxidStates[myoff],
621  &ProcGlobal->subxidStates[myoff + 1],
622  movecount * sizeof(*ProcGlobal->subxidStates));
623  memmove(&ProcGlobal->statusFlags[myoff],
624  &ProcGlobal->statusFlags[myoff + 1],
625  movecount * sizeof(*ProcGlobal->statusFlags));
626 
627  arrayP->pgprocnos[arrayP->numProcs - 1] = -1; /* for debugging */
628  arrayP->numProcs--;
629 
630  /*
631  * Adjust pgxactoff of following procs for removed PGPROC (note that
632  * numProcs already has been decremented).
633  */
634  for (int index = myoff; index < arrayP->numProcs; index++)
635  {
636  int procno = arrayP->pgprocnos[index];
637 
638  Assert(procno >= 0 && procno < (arrayP->maxProcs + NUM_AUXILIARY_PROCS));
639  Assert(allProcs[procno].pgxactoff - 1 == index);
640 
641  allProcs[procno].pgxactoff = index;
642  }
643 
644  /*
645  * Release in reversed acquisition order, to reduce frequency of having to
646  * wait for XidGenLock while holding ProcArrayLock.
647  */
648  LWLockRelease(XidGenLock);
649  LWLockRelease(ProcArrayLock);
650 }

References allProcs, PROC_HDR::allProcs, Assert(), XidCacheStatus::count, InvalidTransactionId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MaintainLatestCompletedXid(), ProcArrayStruct::maxProcs, NUM_AUXILIARY_PROCS, ProcArrayStruct::numProcs, XidCacheStatus::overflowed, ProcArrayStruct::pgprocnos, PGPROC::pgxactoff, PGPROC::pid, procArray, ProcGlobal, ShmemVariableCache, PROC_HDR::statusFlags, PROC_HDR::subxidStates, TransactionIdIsValid, VariableCacheData::xactCompletionCount, and PROC_HDR::xids.

Referenced by FinishPreparedTransaction(), and RemoveProcFromArray().

◆ ProcArraySetReplicationSlotXmin()

void ProcArraySetReplicationSlotXmin ( TransactionId  xmin,
TransactionId  catalog_xmin,
bool  already_locked 
)

Definition at line 3847 of file procarray.c.

3849 {
3850  Assert(!already_locked || LWLockHeldByMe(ProcArrayLock));
3851 
3852  if (!already_locked)
3853  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3854 
3856  procArray->replication_slot_catalog_xmin = catalog_xmin;
3857 
3858  if (!already_locked)
3859  LWLockRelease(ProcArrayLock);
3860 
3861  elog(DEBUG1, "xmin required by slots: data %u, catalog %u",
3862  xmin, catalog_xmin);
3863 }

References Assert(), DEBUG1, elog(), LW_EXCLUSIVE, LWLockAcquire(), LWLockHeldByMe(), LWLockRelease(), procArray, ProcArrayStruct::replication_slot_catalog_xmin, and ProcArrayStruct::replication_slot_xmin.

Referenced by ReplicationSlotsComputeRequiredXmin().

◆ ProcArrayShmemSize()

Size ProcArrayShmemSize ( void  )

Definition at line 377 of file procarray.c.

378 {
379  Size size;
380 
381  /* Size of the ProcArray structure itself */
382 #define PROCARRAY_MAXPROCS (MaxBackends + max_prepared_xacts)
383 
384  size = offsetof(ProcArrayStruct, pgprocnos);
385  size = add_size(size, mul_size(sizeof(int), PROCARRAY_MAXPROCS));
386 
387  /*
388  * During Hot Standby processing we have a data structure called
389  * KnownAssignedXids, created in shared memory. Local data structures are
390  * also created in various backends during GetSnapshotData(),
391  * TransactionIdIsInProgress() and GetRunningTransactionData(). All of the
392  * main structures created in those functions must be identically sized,
393  * since we may at times copy the whole of the data structures around. We
394  * refer to this size as TOTAL_MAX_CACHED_SUBXIDS.
395  *
396  * Ideally we'd only create this structure if we were actually doing hot
397  * standby in the current run, but we don't know that yet at the time
398  * shared memory is being set up.
399  */
400 #define TOTAL_MAX_CACHED_SUBXIDS \
401  ((PGPROC_MAX_CACHED_SUBXIDS + 1) * PROCARRAY_MAXPROCS)
402 
403  if (EnableHotStandby)
404  {
405  size = add_size(size,
406  mul_size(sizeof(TransactionId),
408  size = add_size(size,
409  mul_size(sizeof(bool), TOTAL_MAX_CACHED_SUBXIDS));
410  }
411 
412  return size;
413 }
size_t Size
Definition: c.h:594

References add_size(), EnableHotStandby, mul_size(), PROCARRAY_MAXPROCS, and TOTAL_MAX_CACHED_SUBXIDS.

Referenced by CalculateShmemSize().

◆ RecordKnownAssignedTransactionIds()

void RecordKnownAssignedTransactionIds ( TransactionId  xid)

Definition at line 4337 of file procarray.c.

4338 {
4342 
4343  elog(trace_recovery(DEBUG4), "record known xact %u latestObservedXid %u",
4344  xid, latestObservedXid);
4345 
4346  /*
4347  * When a newly observed xid arrives, it is frequently the case that it is
4348  * *not* the next xid in sequence. When this occurs, we must treat the
4349  * intervening xids as running also.
4350  */
4352  {
4353  TransactionId next_expected_xid;
4354 
4355  /*
4356  * Extend subtrans like we do in GetNewTransactionId() during normal
4357  * operation using individual extend steps. Note that we do not need
4358  * to extend clog since its extensions are WAL logged.
4359  *
4360  * This part has to be done regardless of standbyState since we
4361  * immediately start assigning subtransactions to their toplevel
4362  * transactions.
4363  */
4364  next_expected_xid = latestObservedXid;
4365  while (TransactionIdPrecedes(next_expected_xid, xid))
4366  {
4367  TransactionIdAdvance(next_expected_xid);
4368  ExtendSUBTRANS(next_expected_xid);
4369  }
4370  Assert(next_expected_xid == xid);
4371 
4372  /*
4373  * If the KnownAssignedXids machinery isn't up yet, there's nothing
4374  * more to do since we don't track assigned xids yet.
4375  */
4377  {
4378  latestObservedXid = xid;
4379  return;
4380  }
4381 
4382  /*
4383  * Add (latestObservedXid, xid] onto the KnownAssignedXids array.
4384  */
4385  next_expected_xid = latestObservedXid;
4386  TransactionIdAdvance(next_expected_xid);
4387  KnownAssignedXidsAdd(next_expected_xid, xid, false);
4388 
4389  /*
4390  * Now we can advance latestObservedXid
4391  */
4392  latestObservedXid = xid;
4393 
4394  /* ShmemVariableCache->nextXid must be beyond any observed xid */
4396  }
4397 }

References AdvanceNextFullTransactionIdPastXid(), Assert(), DEBUG4, elog(), ExtendSUBTRANS(), KnownAssignedXidsAdd(), latestObservedXid, STANDBY_INITIALIZED, standbyState, trace_recovery(), TransactionIdAdvance, TransactionIdFollows(), TransactionIdIsValid, and TransactionIdPrecedes().

Referenced by ApplyWalRecord(), ProcArrayApplyXidAssignment(), xact_redo_abort(), and xact_redo_commit().

◆ SignalVirtualTransaction()

pid_t SignalVirtualTransaction ( VirtualTransactionId  vxid,
ProcSignalReason  sigmode,
bool  conflictPending 
)

Definition at line 3404 of file procarray.c.

3406 {
3407  ProcArrayStruct *arrayP = procArray;
3408  int index;
3409  pid_t pid = 0;
3410 
3411  LWLockAcquire(ProcArrayLock, LW_SHARED);
3412 
3413  for (index = 0; index < arrayP->numProcs; index++)
3414  {
3415  int pgprocno = arrayP->pgprocnos[index];
3416  PGPROC *proc = &allProcs[pgprocno];
3417  VirtualTransactionId procvxid;
3418 
3419  GET_VXID_FROM_PGPROC(procvxid, *proc);
3420 
3421  if (procvxid.backendId == vxid.backendId &&
3422  procvxid.localTransactionId == vxid.localTransactionId)
3423  {
3424  proc->recoveryConflictPending = conflictPending;
3425  pid = proc->pid;
3426  if (pid != 0)
3427  {
3428  /*
3429  * Kill the pid if it's still here. If not, that's what we
3430  * wanted so ignore any errors.
3431  */
3432  (void) SendProcSignal(pid, sigmode, vxid.backendId);
3433  }
3434  break;
3435  }
3436  }
3437 
3438  LWLockRelease(ProcArrayLock);
3439 
3440  return pid;
3441 }

References allProcs, VirtualTransactionId::backendId, GET_VXID_FROM_PGPROC, VirtualTransactionId::localTransactionId, LW_SHARED, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::numProcs, ProcArrayStruct::pgprocnos, PGPROC::pid, procArray, PGPROC::recoveryConflictPending, and SendProcSignal().

Referenced by CancelVirtualTransaction(), and ResolveRecoveryConflictWithLock().

◆ TerminateOtherDBBackends()

void TerminateOtherDBBackends ( Oid  databaseId)

Definition at line 3735 of file procarray.c.

3736 {
3737  ProcArrayStruct *arrayP = procArray;
3738  List *pids = NIL;
3739  int nprepared = 0;
3740  int i;
3741 
3742  LWLockAcquire(ProcArrayLock, LW_SHARED);
3743 
3744  for (i = 0; i < procArray->numProcs; i++)
3745  {
3746  int pgprocno = arrayP->pgprocnos[i];
3747  PGPROC *proc = &allProcs[pgprocno];
3748 
3749  if (proc->databaseId != databaseId)
3750  continue;
3751  if (proc == MyProc)
3752  continue;
3753 
3754  if (proc->pid != 0)
3755  pids = lappend_int(pids, proc->pid);
3756  else
3757  nprepared++;
3758  }
3759 
3760  LWLockRelease(ProcArrayLock);
3761 
3762  if (nprepared > 0)
3763  ereport(ERROR,
3764  (errcode(ERRCODE_OBJECT_IN_USE),
3765  errmsg("database \"%s\" is being used by prepared transactions",
3766  get_database_name(databaseId)),
3767  errdetail_plural("There is %d prepared transaction using the database.",
3768  "There are %d prepared transactions using the database.",
3769  nprepared,
3770  nprepared)));
3771 
3772  if (pids)
3773  {
3774  ListCell *lc;
3775 
3776  /*
3777  * Check whether we have the necessary rights to terminate other
3778  * sessions. We don't terminate any session until we ensure that we
3779  * have rights on all the sessions to be terminated. These checks are
3780  * the same as we do in pg_terminate_backend.
3781  *
3782  * In this case we don't raise some warnings - like "PID %d is not a
3783  * PostgreSQL server process", because for us already finished session
3784  * is not a problem.
3785  */
3786  foreach(lc, pids)
3787  {
3788  int pid = lfirst_int(lc);
3789  PGPROC *proc = BackendPidGetProc(pid);
3790 
3791  if (proc != NULL)
3792  {
3793  /* Only allow superusers to signal superuser-owned backends. */
3794  if (superuser_arg(proc->roleId) && !superuser())
3795  ereport(ERROR,
3796  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3797  errmsg("permission denied to terminate process"),
3798  errdetail("Only roles with the %s attribute may terminate processes of roles with the %s attribute.",
3799  "SUPERUSER", "SUPERUSER")));
3800 
3801  /* Users can signal backends they have role membership in. */
3802  if (!has_privs_of_role(GetUserId(), proc->roleId) &&
3803  !has_privs_of_role(GetUserId(), ROLE_PG_SIGNAL_BACKEND))
3804  ereport(ERROR,
3805  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3806  errmsg("permission denied to terminate process"),
3807  errdetail("Only roles with privileges of the role whose process is being terminated or with privileges of the \"%s\" role may terminate this process.",
3808  "pg_signal_backend")));
3809  }
3810  }
3811 
3812  /*
3813  * There's a race condition here: once we release the ProcArrayLock,
3814  * it's possible for the session to exit before we issue kill. That
3815  * race condition possibility seems too unlikely to worry about. See
3816  * pg_signal_backend.
3817  */
3818  foreach(lc, pids)
3819  {
3820  int pid = lfirst_int(lc);
3821  PGPROC *proc = BackendPidGetProc(pid);
3822 
3823  if (proc != NULL)
3824  {
3825  /*
3826  * If we have setsid(), signal the backend's whole process
3827  * group
3828  */
3829 #ifdef HAVE_SETSID
3830  (void) kill(-pid, SIGTERM);
3831 #else
3832  (void) kill(pid, SIGTERM);
3833 #endif
3834  }
3835  }
3836  }
3837 }
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:4961
char * get_database_name(Oid dbid)
Definition: dbcommands.c:3084
int errdetail(const char *fmt,...)
Definition: elog.c:1202
int errdetail_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1294
List * lappend_int(List *list, int datum)
Definition: list.c:356
Oid GetUserId(void)
Definition: miscinit.c:509
#define NIL
Definition: pg_list.h:68
#define lfirst_int(lc)
Definition: pg_list.h:173
Definition: pg_list.h:54
bool superuser_arg(Oid roleid)
Definition: superuser.c:56
bool superuser(void)
Definition: superuser.c:46

References allProcs, BackendPidGetProc(), PGPROC::databaseId, ereport, errcode(), errdetail(), errdetail_plural(), errmsg(), ERROR, get_database_name(), GetUserId(), has_privs_of_role(), i, kill, lappend_int(), lfirst_int, LW_SHARED, LWLockAcquire(), LWLockRelease(), MyProc, NIL, ProcArrayStruct::numProcs, ProcArrayStruct::pgprocnos, PGPROC::pid, procArray, PGPROC::roleId, superuser(), and superuser_arg().

Referenced by dropdb().

◆ TransactionIdIsActive()

bool TransactionIdIsActive ( TransactionId  xid)

Definition at line 1615 of file procarray.c.

1616 {
1617  bool result = false;
1618  ProcArrayStruct *arrayP = procArray;
1619  TransactionId *other_xids = ProcGlobal->xids;
1620  int i;
1621 
1622  /*
1623  * Don't bother checking a transaction older than RecentXmin; it could not
1624  * possibly still be running.
1625  */
1627  return false;
1628 
1629  LWLockAcquire(ProcArrayLock, LW_SHARED);
1630 
1631  for (i = 0; i < arrayP->numProcs; i++)
1632  {
1633  int pgprocno = arrayP->pgprocnos[i];
1634  PGPROC *proc = &allProcs[pgprocno];
1635  TransactionId pxid;
1636 
1637  /* Fetch xid just once - see GetNewTransactionId */
1638  pxid = UINT32_ACCESS_ONCE(other_xids[i]);
1639 
1640  if (!TransactionIdIsValid(pxid))
1641  continue;
1642 
1643  if (proc->pid == 0)
1644  continue; /* ignore prepared transactions */
1645 
1646  if (TransactionIdEquals(pxid, xid))
1647  {
1648  result = true;
1649  break;
1650  }
1651  }
1652 
1653  LWLockRelease(ProcArrayLock);
1654 
1655  return result;
1656 }

References allProcs, i, LW_SHARED, LWLockAcquire(), LWLockRelease(), ProcArrayStruct::numProcs, ProcArrayStruct::pgprocnos, PGPROC::pid, procArray, ProcGlobal, RecentXmin, TransactionIdEquals, TransactionIdIsValid, TransactionIdPrecedes(), UINT32_ACCESS_ONCE, and PROC_HDR::xids.

◆ TransactionIdIsInProgress()

bool TransactionIdIsInProgress ( TransactionId  xid)

Definition at line 1383 of file procarray.c.

1384 {
1385  static TransactionId *xids = NULL;
1386  static TransactionId *other_xids;
1387  XidCacheStatus *other_subxidstates;
1388  int nxids = 0;
1389  ProcArrayStruct *arrayP = procArray;
1390  TransactionId topxid;
1391  TransactionId latestCompletedXid;
1392  int mypgxactoff;
1393  int numProcs;
1394  int j;
1395 
1396  /*
1397  * Don't bother checking a transaction older than RecentXmin; it could not
1398  * possibly still be running. (Note: in particular, this guarantees that
1399  * we reject InvalidTransactionId, FrozenTransactionId, etc as not
1400  * running.)
1401  */
1403  {
1405  return false;
1406  }
1407 
1408  /*
1409  * We may have just checked the status of this transaction, so if it is
1410  * already known to be completed, we can fall out without any access to
1411  * shared memory.
1412  */
1414  {
1416  return false;
1417  }
1418 
1419  /*
1420  * Also, we can handle our own transaction (and subtransactions) without
1421  * any access to shared memory.
1422  */
1424  {
1426  return true;
1427  }
1428 
1429  /*
1430  * If first time through, get workspace to remember main XIDs in. We
1431  * malloc it permanently to avoid repeated palloc/pfree overhead.
1432  */
1433  if (xids == NULL)
1434  {
1435  /*
1436  * In hot standby mode, reserve enough space to hold all xids in the
1437  * known-assigned list. If we later finish recovery, we no longer need
1438  * the bigger array, but we don't bother to shrink it.
1439  */
1440  int maxxids = RecoveryInProgress() ? TOTAL_MAX_CACHED_SUBXIDS : arrayP->maxProcs;
1441 
1442  xids = (TransactionId *) malloc(maxxids * sizeof(TransactionId));
1443  if (xids == NULL)
1444  ereport(ERROR,
1445  (errcode(ERRCODE_OUT_OF_MEMORY),
1446  errmsg("out of memory")));
1447  }
1448 
1449  other_xids = ProcGlobal->xids;
1450  other_subxidstates = ProcGlobal->subxidStates;
1451 
1452  LWLockAcquire(ProcArrayLock, LW_SHARED);
1453 
1454  /*
1455  * Now that we have the lock, we can check latestCompletedXid; if the
1456  * target Xid is after that, it's surely still running.
1457  */
1458  latestCompletedXid =
1460  if (TransactionIdPrecedes(latestCompletedXid, xid))
1461  {
1462  LWLockRelease(ProcArrayLock);
1464  return true;
1465  }
1466 
1467  /* No shortcuts, gotta grovel through the array */
1468  mypgxactoff = MyProc->pgxactoff;
1469  numProcs = arrayP->numProcs;
1470  for (int pgxactoff = 0; pgxactoff < numProcs; pgxactoff++)
1471  {
1472  int pgprocno;
1473  PGPROC *proc;
1474  TransactionId pxid;
1475  int pxids;
1476 
1477  /* Ignore ourselves --- dealt with it above */
1478  if (pgxactoff == mypgxactoff)
1479  continue;
1480 
1481  /* Fetch xid just once - see GetNewTransactionId */
1482  pxid = UINT32_ACCESS_ONCE(other_xids[pgxactoff]);
1483 
1484  if (!TransactionIdIsValid(pxid))
1485  continue;
1486 
1487  /*
1488  * Step 1: check the main Xid
1489  */
1490  if (TransactionIdEquals(pxid, xid))
1491  {
1492  LWLockRelease(ProcArrayLock);
1494  return true;
1495  }
1496 
1497  /*
1498  * We can ignore main Xids that are younger than the target Xid, since
1499  * the target could not possibly be their child.
1500  */
1501  if (TransactionIdPrecedes(xid, pxid))
1502  continue;
1503 
1504  /*
1505  * Step 2: check the cached child-Xids arrays
1506  */
1507  pxids = other_subxidstates[pgxactoff].count;
1508  pg_read_barrier(); /* pairs with barrier in GetNewTransactionId() */
1509  pgprocno = arrayP->pgprocnos[pgxactoff];
1510  proc = &allProcs[pgprocno];
1511  for (j = pxids - 1; j >= 0; j--)
1512  {
1513  /* Fetch xid just once - see GetNewTransactionId */
1515 
1516  if (TransactionIdEquals(cxid, xid))
1517  {
1518  LWLockRelease(ProcArrayLock);
1520  return true;
1521  }
1522  }
1523 
1524  /*
1525  * Save the main Xid for step 4. We only need to remember main Xids
1526  * that have uncached children. (Note: there is no race condition
1527  * here because the overflowed flag cannot be cleared, only set, while
1528  * we hold ProcArrayLock. So we can't miss an Xid that we need to
1529  * worry about.)
1530  */
1531  if (other_subxidstates[pgxactoff].overflowed)
1532  xids[nxids++] = pxid;
1533  }
1534 
1535  /*
1536  * Step 3: in hot standby mode, check the known-assigned-xids list. XIDs
1537  * in the list must be treated as running.
1538  */
1539  if (RecoveryInProgress())
1540  {
1541  /* none of the PGPROC entries should have XIDs in hot standby mode */
1542  Assert(nxids == 0);
1543 
1544  if (KnownAssignedXidExists(xid))
1545  {
1546  LWLockRelease(ProcArrayLock);
1548  return true;
1549  }
1550 
1551  /*
1552  * If the KnownAssignedXids overflowed, we have to check pg_subtrans
1553  * too. Fetch all xids from KnownAssignedXids that are lower than
1554  * xid, since if xid is a subtransaction its parent will always have a
1555  * lower value. Note we will collect both main and subXIDs here, but
1556  * there's no help for it.
1557  */
1559  nxids = KnownAssignedXidsGet(xids, xid);
1560  }
1561 
1562  LWLockRelease(ProcArrayLock);
1563 
1564  /*
1565  * If none of the relevant caches overflowed, we know the Xid is not
1566  * running without even looking at pg_subtrans.
1567  */
1568  if (nxids == 0)
1569  {
1572  return false;
1573  }
1574 
1575  /*
1576  * Step 4: have to check pg_subtrans.
1577  *
1578  * At this point, we know it's either a subtransaction of one of the Xids
1579  * in xids[], or it's not running. If it's an already-failed
1580  * subtransaction, we want to say "not running" even though its parent may
1581  * still be running. So first, check pg_xact to see if it's been aborted.
1582  */
1584 
1585  if (TransactionIdDidAbort(xid))
1586  {
1588  return false;
1589  }
1590 
1591  /*
1592  * It isn't aborted, so check whether the transaction tree it belongs to
1593  * is still running (or, more precisely, whether it was running when we
1594  * held ProcArrayLock).
1595  */
1596  topxid = SubTransGetTopmostTransaction(xid);
1597  Assert(TransactionIdIsValid(topxid));
1598  if (!TransactionIdEquals(topxid, xid) &&
1599  pg_lfind32(topxid, xids, nxids))
1600  return true;
1601 
1603  return false;
1604 }
int j
Definition: isn.c:74
static bool pg_lfind32(uint32 key, uint32 *base, uint32 nelem)
Definition: pg_lfind.h:90
#define xc_no_overflow_inc()
Definition: procarray.c:343
#define xc_by_recent_xmin_inc()
Definition: procarray.c:336
static int KnownAssignedXidsGet(TransactionId *xarray, TransactionId xmax)
Definition: procarray.c:5023
#define xc_by_my_xact_inc()
Definition: procarray.c:338
#define xc_by_known_assigned_inc()
Definition: procarray.c:342
#define xc_by_child_xid_inc()
Definition: procarray.c:341
#define xc_slow_answer_inc()
Definition: procarray.c:344
#define xc_by_main_xid_inc()
Definition: procarray.c:340
static bool KnownAssignedXidExists(TransactionId xid)
Definition: procarray.c:4884
#define xc_by_latest_xid_inc()
Definition: procarray.c:339
#define xc_by_known_xact_inc()
Definition: procarray.c:337
static TransactionId cachedXidIsNotInProgress
Definition: procarray.c:277
TransactionId SubTransGetTopmostTransaction(TransactionId xid)
Definition: subtrans.c:150
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition: xact.c:926

References allProcs, Assert(), cachedXidIsNotInProgress, XidCacheStatus::count, ereport, errcode(), errmsg(), ERROR, j, KnownAssignedXidExists(), KnownAssignedXidsGet(), ProcArrayStruct::lastOverflowedXid, VariableCacheData::latestCompletedXid, LW_SHARED, LWLockAcquire(), LWLockRelease(), malloc, ProcArrayStruct::maxProcs, MyProc, ProcArrayStruct::numProcs, pg_lfind32(), pg_read_barrier, ProcArrayStruct::pgprocnos, PGPROC::pgxactoff, procArray, ProcGlobal, RecentXmin, RecoveryInProgress(), ShmemVariableCache, SubTransGetTopmostTransaction(), PGPROC::subxids, PROC_HDR::subxidStates, TOTAL_MAX_CACHED_SUBXIDS, TransactionIdDidAbort(), TransactionIdEquals, TransactionIdIsCurrentTransactionId(), TransactionIdIsValid, TransactionIdPrecedes(), TransactionIdPrecedesOrEquals(), UINT32_ACCESS_ONCE, xc_by_child_xid_inc, xc_by_known_assigned_inc, xc_by_known_xact_inc, xc_by_latest_xid_inc, xc_by_main_xid_inc, xc_by_my_xact_inc, xc_by_recent_xmin_inc, xc_no_overflow_inc, xc_slow_answer_inc, XidFromFullTransactionId, XidCache::xids, and PROC_HDR::xids.

Referenced by check_safe_enum_use(), compute_new_xmax_infomask(), ConditionalXactLockTableWait(), Do_MultiXactIdWait(), DoesMultiXactIdConflict(), FreezeMultiXactId(), HandleConcurrentAbort(), HeapTupleHeaderIsOnlyLocked(), HeapTupleSatisfiesDirty(), HeapTupleSatisfiesSelf(), HeapTupleSatisfiesToast(), HeapTupleSatisfiesUpdate(), HeapTupleSatisfiesVacuumHorizon(), MultiXactIdExpand(), MultiXactIdIsRunning(), pg_xact_status(), test_lockmode_for_conflict(), verify_heapam(), and XactLockTableWait().

◆ XidCacheRemoveRunningXids()

void XidCacheRemoveRunningXids ( TransactionId  xid,
int  nxids,
const TransactionId xids,
TransactionId  latestXid 
)

Definition at line 3895 of file procarray.c.

3898 {
3899  int i,
3900  j;
3901  XidCacheStatus *mysubxidstat;
3902 
3904 
3905  /*
3906  * We must hold ProcArrayLock exclusively in order to remove transactions
3907  * from the PGPROC array. (See src/backend/access/transam/README.) It's
3908  * possible this could be relaxed since we know this routine is only used
3909  * to abort subtransactions, but pending closer analysis we'd best be
3910  * conservative.
3911  *
3912  * Note that we do not have to be careful about memory ordering of our own
3913  * reads wrt. GetNewTransactionId() here - only this process can modify
3914  * relevant fields of MyProc/ProcGlobal->xids[]. But we do have to be
3915  * careful about our own writes being well ordered.
3916  */
3917  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3918 
3919  mysubxidstat = &ProcGlobal->subxidStates[MyProc->pgxactoff];
3920 
3921  /*
3922  * Under normal circumstances xid and xids[] will be in increasing order,
3923  * as will be the entries in subxids. Scan backwards to avoid O(N^2)
3924  * behavior when removing a lot of xids.
3925  */
3926  for (i = nxids - 1; i >= 0; i--)
3927  {
3928  TransactionId anxid = xids[i];
3929 
3930  for (j = MyProc->subxidStatus.count - 1; j >= 0; j--)
3931  {
3932  if (TransactionIdEquals(MyProc->subxids.xids[j], anxid))
3933  {
3935  pg_write_barrier();
3936  mysubxidstat->count--;
3938  break;
3939  }
3940  }
3941 
3942  /*
3943  * Ordinarily we should have found it, unless the cache has
3944  * overflowed. However it's also possible for this routine to be
3945  * invoked multiple times for the same subtransaction, in case of an
3946  * error during AbortSubTransaction. So instead of Assert, emit a
3947  * debug warning.
3948  */
3949  if (j < 0 && !MyProc->subxidStatus.overflowed)
3950  elog(WARNING, "did not find subXID %u in MyProc", anxid);
3951  }
3952 
3953  for (j =