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 "storage/spin.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 void GetSnapshotDataInitOldSnapshot (Snapshot snapshot)
 
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 70 of file procarray.c.

◆ xc_by_child_xid_inc

#define xc_by_child_xid_inc ( )    ((void) 0)

Definition at line 343 of file procarray.c.

◆ xc_by_known_assigned_inc

#define xc_by_known_assigned_inc ( )    ((void) 0)

Definition at line 344 of file procarray.c.

◆ xc_by_known_xact_inc

#define xc_by_known_xact_inc ( )    ((void) 0)

Definition at line 339 of file procarray.c.

◆ xc_by_latest_xid_inc

#define xc_by_latest_xid_inc ( )    ((void) 0)

Definition at line 341 of file procarray.c.

◆ xc_by_main_xid_inc

#define xc_by_main_xid_inc ( )    ((void) 0)

Definition at line 342 of file procarray.c.

◆ xc_by_my_xact_inc

#define xc_by_my_xact_inc ( )    ((void) 0)

Definition at line 340 of file procarray.c.

◆ xc_by_recent_xmin_inc

#define xc_by_recent_xmin_inc ( )    ((void) 0)

Definition at line 338 of file procarray.c.

◆ xc_no_overflow_inc

#define xc_no_overflow_inc ( )    ((void) 0)

Definition at line 345 of file procarray.c.

◆ xc_slow_answer_inc

#define xc_slow_answer_inc ( )    ((void) 0)

Definition at line 346 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 252 of file procarray.c.

253 {
GlobalVisHorizonKind
Definition: procarray.c:253
@ VISHORIZON_SHARED
Definition: procarray.c:254
@ VISHORIZON_DATA
Definition: procarray.c:256
@ VISHORIZON_CATALOG
Definition: procarray.c:255
@ VISHORIZON_TEMP
Definition: procarray.c:257

◆ KAXCompressReason

Enumerator
KAX_NO_SPACE 
KAX_PRUNE 
KAX_TRANSACTION_END 
KAX_STARTUP_PROCESS_IDLE 

Definition at line 263 of file procarray.c.

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

Function Documentation

◆ BackendPidGetProc()

PGPROC* BackendPidGetProc ( int  pid)

Definition at line 3134 of file procarray.c.

3135 {
3136  PGPROC *result;
3137 
3138  if (pid == 0) /* never match dummy PGPROCs */
3139  return NULL;
3140 
3141  LWLockAcquire(ProcArrayLock, LW_SHARED);
3142 
3143  result = BackendPidGetProcWithLock(pid);
3144 
3145  LWLockRelease(ProcArrayLock);
3146 
3147  return result;
3148 }
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1195
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803
@ LW_SHARED
Definition: lwlock.h:117
PGPROC * BackendPidGetProcWithLock(int pid)
Definition: procarray.c:3157
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 3157 of file procarray.c.

3158 {
3159  PGPROC *result = NULL;
3160  ProcArrayStruct *arrayP = procArray;
3161  int index;
3162 
3163  if (pid == 0) /* never match dummy PGPROCs */
3164  return NULL;
3165 
3166  for (index = 0; index < arrayP->numProcs; index++)
3167  {
3168  PGPROC *proc = &allProcs[arrayP->pgprocnos[index]];
3169 
3170  if (proc->pid == pid)
3171  {
3172  result = proc;
3173  break;
3174  }
3175  }
3176 
3177  return result;
3178 }
static PGPROC * allProcs
Definition: procarray.c:274
static ProcArrayStruct * procArray
Definition: procarray.c:272
int pid
Definition: proc.h:186
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:102
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 3194 of file procarray.c.

3195 {
3196  int result = 0;
3197  ProcArrayStruct *arrayP = procArray;
3198  TransactionId *other_xids = ProcGlobal->xids;
3199  int index;
3200 
3201  if (xid == InvalidTransactionId) /* never match invalid xid */
3202  return 0;
3203 
3204  LWLockAcquire(ProcArrayLock, LW_SHARED);
3205 
3206  for (index = 0; index < arrayP->numProcs; index++)
3207  {
3208  int pgprocno = arrayP->pgprocnos[index];
3209  PGPROC *proc = &allProcs[pgprocno];
3210 
3211  if (other_xids[index] == xid)
3212  {
3213  result = proc->pid;
3214  break;
3215  }
3216  }
3217 
3218  LWLockRelease(ProcArrayLock);
3219 
3220  return result;
3221 }
uint32 TransactionId
Definition: c.h:636
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 3598 of file procarray.c.

3599 {
3600  ProcArrayStruct *arrayP = procArray;
3601  int index;
3602 
3603  /* tell all backends to die */
3604  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3605 
3606  for (index = 0; index < arrayP->numProcs; index++)
3607  {
3608  int pgprocno = arrayP->pgprocnos[index];
3609  PGPROC *proc = &allProcs[pgprocno];
3610 
3611  if (databaseid == InvalidOid || proc->databaseId == databaseid)
3612  {
3613  VirtualTransactionId procvxid;
3614  pid_t pid;
3615 
3616  GET_VXID_FROM_PGPROC(procvxid, *proc);
3617 
3618  proc->recoveryConflictPending = conflictPending;
3619  pid = proc->pid;
3620  if (pid != 0)
3621  {
3622  /*
3623  * Kill the pid if it's still here. If not, that's what we
3624  * wanted so ignore any errors.
3625  */
3626  (void) SendProcSignal(pid, sigmode, procvxid.backendId);
3627  }
3628  }
3629  }
3630 
3631  LWLockRelease(ProcArrayLock);
3632 }
#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 3429 of file procarray.c.

3430 {
3431  return SignalVirtualTransaction(vxid, sigmode, true);
3432 }
pid_t SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode, bool conflictPending)
Definition: procarray.c:3435

References SignalVirtualTransaction().

Referenced by ResolveRecoveryConflictWithVirtualXIDs().

◆ ComputeXidHorizons()

static void ComputeXidHorizons ( ComputeXidHorizonsResult h)
static

Definition at line 1719 of file procarray.c.

1720 {
1721  ProcArrayStruct *arrayP = procArray;
1722  TransactionId kaxmin;
1723  bool in_recovery = RecoveryInProgress();
1724  TransactionId *other_xids = ProcGlobal->xids;
1725 
1726  /* inferred after ProcArrayLock is released */
1728 
1729  LWLockAcquire(ProcArrayLock, LW_SHARED);
1730 
1732 
1733  /*
1734  * We initialize the MIN() calculation with latestCompletedXid + 1. This
1735  * is a lower bound for the XIDs that might appear in the ProcArray later,
1736  * and so protects us against overestimating the result due to future
1737  * additions.
1738  */
1739  {
1740  TransactionId initial;
1741 
1743  Assert(TransactionIdIsValid(initial));
1744  TransactionIdAdvance(initial);
1745 
1746  h->oldest_considered_running = initial;
1747  h->shared_oldest_nonremovable = initial;
1748  h->data_oldest_nonremovable = initial;
1749 
1750  /*
1751  * Only modifications made by this backend affect the horizon for
1752  * temporary relations. Instead of a check in each iteration of the
1753  * loop over all PGPROCs it is cheaper to just initialize to the
1754  * current top-level xid any.
1755  *
1756  * Without an assigned xid we could use a horizon as aggressive as
1757  * GetNewTransactionId(), but we can get away with the much cheaper
1758  * latestCompletedXid + 1: If this backend has no xid there, by
1759  * definition, can't be any newer changes in the temp table than
1760  * latestCompletedXid.
1761  */
1764  else
1765  h->temp_oldest_nonremovable = initial;
1766  }
1767 
1768  /*
1769  * Fetch slot horizons while ProcArrayLock is held - the
1770  * LWLockAcquire/LWLockRelease are a barrier, ensuring this happens inside
1771  * the lock.
1772  */
1775 
1776  for (int index = 0; index < arrayP->numProcs; index++)
1777  {
1778  int pgprocno = arrayP->pgprocnos[index];
1779  PGPROC *proc = &allProcs[pgprocno];
1780  int8 statusFlags = ProcGlobal->statusFlags[index];
1781  TransactionId xid;
1782  TransactionId xmin;
1783 
1784  /* Fetch xid just once - see GetNewTransactionId */
1785  xid = UINT32_ACCESS_ONCE(other_xids[index]);
1786  xmin = UINT32_ACCESS_ONCE(proc->xmin);
1787 
1788  /*
1789  * Consider both the transaction's Xmin, and its Xid.
1790  *
1791  * We must check both because a transaction might have an Xmin but not
1792  * (yet) an Xid; conversely, if it has an Xid, that could determine
1793  * some not-yet-set Xmin.
1794  */
1795  xmin = TransactionIdOlder(xmin, xid);
1796 
1797  /* if neither is set, this proc doesn't influence the horizon */
1798  if (!TransactionIdIsValid(xmin))
1799  continue;
1800 
1801  /*
1802  * Don't ignore any procs when determining which transactions might be
1803  * considered running. While slots should ensure logical decoding
1804  * backends are protected even without this check, it can't hurt to
1805  * include them here as well..
1806  */
1809 
1810  /*
1811  * Skip over backends either vacuuming (which is ok with rows being
1812  * removed, as long as pg_subtrans is not truncated) or doing logical
1813  * decoding (which manages xmin separately, check below).
1814  */
1815  if (statusFlags & (PROC_IN_VACUUM | PROC_IN_LOGICAL_DECODING))
1816  continue;
1817 
1818  /* shared tables need to take backends in all databases into account */
1821 
1822  /*
1823  * Normally sessions in other databases are ignored for anything but
1824  * the shared horizon.
1825  *
1826  * However, include them when MyDatabaseId is not (yet) set. A
1827  * backend in the process of starting up must not compute a "too
1828  * aggressive" horizon, otherwise we could end up using it to prune
1829  * still-needed data away. If the current backend never connects to a
1830  * database this is harmless, because data_oldest_nonremovable will
1831  * never be utilized.
1832  *
1833  * Also, sessions marked with PROC_AFFECTS_ALL_HORIZONS should always
1834  * be included. (This flag is used for hot standby feedback, which
1835  * can't be tied to a specific database.)
1836  *
1837  * Also, while in recovery we cannot compute an accurate per-database
1838  * horizon, as all xids are managed via the KnownAssignedXids
1839  * machinery.
1840  */
1841  if (proc->databaseId == MyDatabaseId ||
1842  MyDatabaseId == InvalidOid ||
1843  (statusFlags & PROC_AFFECTS_ALL_HORIZONS) ||
1844  in_recovery)
1845  {
1848  }
1849  }
1850 
1851  /*
1852  * If in recovery fetch oldest xid in KnownAssignedXids, will be applied
1853  * after lock is released.
1854  */
1855  if (in_recovery)
1856  kaxmin = KnownAssignedXidsGetOldestXmin();
1857 
1858  /*
1859  * No other information from shared state is needed, release the lock
1860  * immediately. The rest of the computations can be done without a lock.
1861  */
1862  LWLockRelease(ProcArrayLock);
1863 
1864  if (in_recovery)
1865  {
1872  /* temp relations cannot be accessed in recovery */
1873  }
1874 
1879 
1880  /*
1881  * Check whether there are replication slots requiring an older xmin.
1882  */
1887 
1888  /*
1889  * The only difference between catalog / data horizons is that the slot's
1890  * catalog xmin is applied to the catalog one (so catalogs can be accessed
1891  * for logical decoding). Initialize with data horizon, and then back up
1892  * further if necessary. Have to back up the shared horizon as well, since
1893  * that also can contain catalogs.
1894  */
1898  h->slot_catalog_xmin);
1902  h->slot_catalog_xmin);
1903 
1904  /*
1905  * It's possible that slots backed up the horizons further than
1906  * oldest_considered_running. Fix.
1907  */
1917 
1918  /*
1919  * shared horizons have to be at least as old as the oldest visible in
1920  * current db
1921  */
1926 
1927  /*
1928  * Horizons need to ensure that pg_subtrans access is still possible for
1929  * the relevant backends.
1930  */
1941  h->slot_xmin));
1944  h->slot_catalog_xmin));
1945 
1946  /* update approximate horizons with the computed horizons */
1948 }
signed char int8
Definition: c.h:476
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:70
static void GlobalVisUpdateApply(ComputeXidHorizonsResult *horizons)
Definition: procarray.c:4099
static TransactionId KnownAssignedXidsGetOldestXmin(void)
Definition: procarray.c:5139
PGPROC * MyProc
Definition: proc.c:66
TransactionId slot_catalog_xmin
Definition: procarray.c:195
TransactionId data_oldest_nonremovable
Definition: procarray.c:240
TransactionId temp_oldest_nonremovable
Definition: procarray.c:246
TransactionId shared_oldest_nonremovable
Definition: procarray.c:217
TransactionId oldest_considered_running
Definition: procarray.c:208
TransactionId slot_xmin
Definition: procarray.c:194
FullTransactionId latest_completed
Definition: procarray.c:188
TransactionId catalog_oldest_nonremovable
Definition: procarray.c:234
TransactionId shared_oldest_nonremovable_raw
Definition: procarray.c:228
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:97
TransactionId replication_slot_catalog_xmin
Definition: procarray.c:99
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:5921

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 3537 of file procarray.c.

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

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 3567 of file procarray.c.

3568 {
3569  ProcArrayStruct *arrayP = procArray;
3570  int count = 0;
3571  int index;
3572 
3573  LWLockAcquire(ProcArrayLock, LW_SHARED);
3574 
3575  for (index = 0; index < arrayP->numProcs; index++)
3576  {
3577  int pgprocno = arrayP->pgprocnos[index];
3578  PGPROC *proc = &allProcs[pgprocno];
3579 
3580  if (proc->pid == 0)
3581  continue; /* do not count prepared xacts */
3582  if (proc->isBackgroundWorker)
3583  continue; /* do not count background workers */
3584  if (!OidIsValid(databaseid) ||
3585  proc->databaseId == databaseid)
3586  count++;
3587  }
3588 
3589  LWLockRelease(ProcArrayLock);
3590 
3591  return count;
3592 }
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 3688 of file procarray.c.

3689 {
3690  ProcArrayStruct *arrayP = procArray;
3691 
3692 #define MAXAUTOVACPIDS 10 /* max autovacs to SIGTERM per iteration */
3693  int autovac_pids[MAXAUTOVACPIDS];
3694  int tries;
3695 
3696  /* 50 tries with 100ms sleep between tries makes 5 sec total wait */
3697  for (tries = 0; tries < 50; tries++)
3698  {
3699  int nautovacs = 0;
3700  bool found = false;
3701  int index;
3702 
3704 
3705  *nbackends = *nprepared = 0;
3706 
3707  LWLockAcquire(ProcArrayLock, LW_SHARED);
3708 
3709  for (index = 0; index < arrayP->numProcs; index++)
3710  {
3711  int pgprocno = arrayP->pgprocnos[index];
3712  PGPROC *proc = &allProcs[pgprocno];
3713  uint8 statusFlags = ProcGlobal->statusFlags[index];
3714 
3715  if (proc->databaseId != databaseId)
3716  continue;
3717  if (proc == MyProc)
3718  continue;
3719 
3720  found = true;
3721 
3722  if (proc->pid == 0)
3723  (*nprepared)++;
3724  else
3725  {
3726  (*nbackends)++;
3727  if ((statusFlags & PROC_IS_AUTOVACUUM) &&
3728  nautovacs < MAXAUTOVACPIDS)
3729  autovac_pids[nautovacs++] = proc->pid;
3730  }
3731  }
3732 
3733  LWLockRelease(ProcArrayLock);
3734 
3735  if (!found)
3736  return false; /* no conflicting backends, so done */
3737 
3738  /*
3739  * Send SIGTERM to any conflicting autovacuums before sleeping. We
3740  * postpone this step until after the loop because we don't want to
3741  * hold ProcArrayLock while issuing kill(). We have no idea what might
3742  * block kill() inside the kernel...
3743  */
3744  for (index = 0; index < nautovacs; index++)
3745  (void) kill(autovac_pids[index], SIGTERM); /* ignore any error */
3746 
3747  /* sleep, then try again */
3748  pg_usleep(100 * 1000L); /* 100ms */
3749  }
3750 
3751  return true; /* timed out, still conflicts */
3752 }
unsigned char uint8
Definition: c.h:488
#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:495

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 3638 of file procarray.c.

3639 {
3640  ProcArrayStruct *arrayP = procArray;
3641  int count = 0;
3642  int index;
3643 
3644  LWLockAcquire(ProcArrayLock, LW_SHARED);
3645 
3646  for (index = 0; index < arrayP->numProcs; index++)
3647  {
3648  int pgprocno = arrayP->pgprocnos[index];
3649  PGPROC *proc = &allProcs[pgprocno];
3650 
3651  if (proc->pid == 0)
3652  continue; /* do not count prepared xacts */
3653  if (proc->isBackgroundWorker)
3654  continue; /* do not count background workers */
3655  if (proc->roleId == roleid)
3656  count++;
3657  }
3658 
3659  LWLockRelease(ProcArrayLock);
3660 
3661  return count;
3662 }
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 421 of file procarray.c.

422 {
423  bool found;
424 
425  /* Create or attach to the ProcArray shared structure */
427  ShmemInitStruct("Proc Array",
428  add_size(offsetof(ProcArrayStruct, pgprocnos),
429  mul_size(sizeof(int),
431  &found);
432 
433  if (!found)
434  {
435  /*
436  * We're the first - initialize.
437  */
438  procArray->numProcs = 0;
449  }
450 
452 
453  /* Create or attach to the KnownAssignedXids arrays too, if needed */
454  if (EnableHotStandby)
455  {
457  ShmemInitStruct("KnownAssignedXids",
458  mul_size(sizeof(TransactionId),
460  &found);
461  KnownAssignedXidsValid = (bool *)
462  ShmemInitStruct("KnownAssignedXidsValid",
463  mul_size(sizeof(bool), TOTAL_MAX_CACHED_SUBXIDS),
464  &found);
465  }
466 }
#define TOTAL_MAX_CACHED_SUBXIDS
#define PROCARRAY_MAXPROCS
static TransactionId * KnownAssignedXids
Definition: procarray.c:284
static bool * KnownAssignedXidsValid
Definition: procarray.c:285
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
#define SpinLockInit(lock)
Definition: spin.h:60
PGPROC * allProcs
Definition: proc.h:362
int maxKnownAssignedXids
Definition: procarray.c:81
slock_t known_assigned_xids_lck
Definition: procarray.c:85
int numKnownAssignedXids
Definition: procarray.c:82
TransactionId lastOverflowedXid
Definition: procarray.c:94
int tailKnownAssignedXids
Definition: procarray.c:83
int headKnownAssignedXids
Definition: procarray.c:84
uint64 xactCompletionCount
Definition: transam.h:248
bool EnableHotStandby
Definition: xlog.c:124

References add_size(), allProcs, PROC_HDR::allProcs, EnableHotStandby, ProcArrayStruct::headKnownAssignedXids, InvalidTransactionId, ProcArrayStruct::known_assigned_xids_lck, 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, SpinLockInit, ProcArrayStruct::tailKnownAssignedXids, TOTAL_MAX_CACHED_SUBXIDS, and VariableCacheData::xactCompletionCount.

Referenced by CreateSharedMemoryAndSemaphores().

◆ ExpireAllKnownAssignedTransactionIds()

void ExpireAllKnownAssignedTransactionIds ( void  )

Definition at line 4461 of file procarray.c.

4462 {
4463  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4465 
4466  /*
4467  * Reset lastOverflowedXid. Currently, lastOverflowedXid has no use after
4468  * the call of this function. But do this for unification with what
4469  * ExpireOldKnownAssignedTransactionIds() do.
4470  */
4472  LWLockRelease(ProcArrayLock);
4473 }
static void KnownAssignedXidsRemovePreceding(TransactionId removeXid)
Definition: procarray.c:4989

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

Referenced by ShutdownRecoveryTransactionEnvironment().

◆ ExpireOldKnownAssignedTransactionIds()

void ExpireOldKnownAssignedTransactionIds ( TransactionId  xid)

Definition at line 4481 of file procarray.c.

4482 {
4483  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4484 
4485  /*
4486  * Reset lastOverflowedXid if we know all transactions that have been
4487  * possibly running are being gone. Not doing so could cause an incorrect
4488  * lastOverflowedXid value, which makes extra snapshots be marked as
4489  * suboverflowed.
4490  */
4494  LWLockRelease(ProcArrayLock);
4495 }
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 4435 of file procarray.c.

4437 {
4439 
4440  /*
4441  * Uses same locking as transaction commit
4442  */
4443  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4444 
4445  KnownAssignedXidsRemoveTree(xid, nsubxids, subxids);
4446 
4447  /* As in ProcArrayEndTransaction, advance latestCompletedXid */
4449 
4450  /* ... and xactCompletionCount */
4452 
4453  LWLockRelease(ProcArrayLock);
4454 }
static void KnownAssignedXidsRemoveTree(TransactionId xid, int nsubxids, TransactionId *subxids)
Definition: procarray.c:4967
static void MaintainLatestCompletedXidRecovery(TransactionId latestXid)
Definition: procarray.c:991
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 4284 of file procarray.c.

4285 {
4286  TransactionId rel_xid = XidFromFullTransactionId(rel);
4287 
4289  Assert(TransactionIdIsValid(rel_xid));
4290 
4291  /* not guaranteed to find issues, but likely to catch mistakes */
4293 
4295  + (int32) (xid - rel_xid));
4296 }
signed int int32
Definition: c.h:478
#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 3355 of file procarray.c.

3356 {
3357  static VirtualTransactionId *vxids;
3358  ProcArrayStruct *arrayP = procArray;
3359  int count = 0;
3360  int index;
3361 
3362  /*
3363  * If first time through, get workspace to remember main XIDs in. We
3364  * malloc it permanently to avoid repeated palloc/pfree overhead. Allow
3365  * result space, remembering room for a terminator.
3366  */
3367  if (vxids == NULL)
3368  {
3369  vxids = (VirtualTransactionId *)
3370  malloc(sizeof(VirtualTransactionId) * (arrayP->maxProcs + 1));
3371  if (vxids == NULL)
3372  ereport(ERROR,
3373  (errcode(ERRCODE_OUT_OF_MEMORY),
3374  errmsg("out of memory")));
3375  }
3376 
3377  LWLockAcquire(ProcArrayLock, LW_SHARED);
3378 
3379  for (index = 0; index < arrayP->numProcs; index++)
3380  {
3381  int pgprocno = arrayP->pgprocnos[index];
3382  PGPROC *proc = &allProcs[pgprocno];
3383 
3384  /* Exclude prepared transactions */
3385  if (proc->pid == 0)
3386  continue;
3387 
3388  if (!OidIsValid(dbOid) ||
3389  proc->databaseId == dbOid)
3390  {
3391  /* Fetch xmin just once - can't change on us, but good coding */
3392  TransactionId pxmin = UINT32_ACCESS_ONCE(proc->xmin);
3393 
3394  /*
3395  * We ignore an invalid pxmin because this means that backend has
3396  * no snapshot currently. We hold a Share lock to avoid contention
3397  * with users taking snapshots. That is not a problem because the
3398  * current xmin is always at least one higher than the latest
3399  * removed xid, so any new snapshot would never conflict with the
3400  * test here.
3401  */
3402  if (!TransactionIdIsValid(limitXmin) ||
3403  (TransactionIdIsValid(pxmin) && !TransactionIdFollows(pxmin, limitXmin)))
3404  {
3405  VirtualTransactionId vxid;
3406 
3407  GET_VXID_FROM_PGPROC(vxid, *proc);
3408  if (VirtualTransactionIdIsValid(vxid))
3409  vxids[count++] = vxid;
3410  }
3411  }
3412  }
3413 
3414  LWLockRelease(ProcArrayLock);
3415 
3416  /* add the terminator */
3417  vxids[count].backendId = InvalidBackendId;
3419 
3420  return vxids;
3421 }
#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 3262 of file procarray.c.

3265 {
3266  VirtualTransactionId *vxids;
3267  ProcArrayStruct *arrayP = procArray;
3268  int count = 0;
3269  int index;
3270 
3271  /* allocate what's certainly enough result space */
3272  vxids = (VirtualTransactionId *)
3273  palloc(sizeof(VirtualTransactionId) * arrayP->maxProcs);
3274 
3275  LWLockAcquire(ProcArrayLock, LW_SHARED);
3276 
3277  for (index = 0; index < arrayP->numProcs; index++)
3278  {
3279  int pgprocno = arrayP->pgprocnos[index];
3280  PGPROC *proc = &allProcs[pgprocno];
3281  uint8 statusFlags = ProcGlobal->statusFlags[index];
3282 
3283  if (proc == MyProc)
3284  continue;
3285 
3286  if (excludeVacuum & statusFlags)
3287  continue;
3288 
3289  if (allDbs || proc->databaseId == MyDatabaseId)
3290  {
3291  /* Fetch xmin just once - might change on us */
3292  TransactionId pxmin = UINT32_ACCESS_ONCE(proc->xmin);
3293 
3294  if (excludeXmin0 && !TransactionIdIsValid(pxmin))
3295  continue;
3296 
3297  /*
3298  * InvalidTransactionId precedes all other XIDs, so a proc that
3299  * hasn't set xmin yet will not be rejected by this test.
3300  */
3301  if (!TransactionIdIsValid(limitXmin) ||
3302  TransactionIdPrecedesOrEquals(pxmin, limitXmin))
3303  {
3304  VirtualTransactionId vxid;
3305 
3306  GET_VXID_FROM_PGPROC(vxid, *proc);
3307  if (VirtualTransactionIdIsValid(vxid))
3308  vxids[count++] = vxid;
3309  }
3310  }
3311  }
3312 
3313  LWLockRelease(ProcArrayLock);
3314 
3315  *nvxids = count;
3316  return vxids;
3317 }
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 2064 of file procarray.c.

2065 {
2066  return TOTAL_MAX_CACHED_SUBXIDS;
2067 }

References TOTAL_MAX_CACHED_SUBXIDS.

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

◆ GetMaxSnapshotXidCount()

int GetMaxSnapshotXidCount ( void  )

Definition at line 2053 of file procarray.c.

2054 {
2055  return procArray->maxProcs;
2056 }

References ProcArrayStruct::maxProcs, and procArray.

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

◆ GetOldestActiveTransactionId()

TransactionId GetOldestActiveTransactionId ( void  )

Definition at line 2876 of file procarray.c.

2877 {
2878  ProcArrayStruct *arrayP = procArray;
2879  TransactionId *other_xids = ProcGlobal->xids;
2880  TransactionId oldestRunningXid;
2881  int index;
2882 
2884 
2885  /*
2886  * Read nextXid, as the upper bound of what's still active.
2887  *
2888  * Reading a TransactionId is atomic, but we must grab the lock to make
2889  * sure that all XIDs < nextXid are already present in the proc array (or
2890  * have already completed), when we spin over it.
2891  */
2892  LWLockAcquire(XidGenLock, LW_SHARED);
2894  LWLockRelease(XidGenLock);
2895 
2896  /*
2897  * Spin over procArray collecting all xids and subxids.
2898  */
2899  LWLockAcquire(ProcArrayLock, LW_SHARED);
2900  for (index = 0; index < arrayP->numProcs; index++)
2901  {
2902  TransactionId xid;
2903 
2904  /* Fetch xid just once - see GetNewTransactionId */
2905  xid = UINT32_ACCESS_ONCE(other_xids[index]);
2906 
2907  if (!TransactionIdIsNormal(xid))
2908  continue;
2909 
2910  if (TransactionIdPrecedes(xid, oldestRunningXid))
2911  oldestRunningXid = xid;
2912 
2913  /*
2914  * Top-level XID of a transaction is always less than any of its
2915  * subxids, so we don't need to check if any of the subxids are
2916  * smaller than oldestRunningXid
2917  */
2918  }
2919  LWLockRelease(ProcArrayLock);
2920 
2921  return oldestRunningXid;
2922 }
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 1989 of file procarray.c.

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

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 2941 of file procarray.c.

2942 {
2943  ProcArrayStruct *arrayP = procArray;
2944  TransactionId oldestSafeXid;
2945  int index;
2946  bool recovery_in_progress = RecoveryInProgress();
2947 
2948  Assert(LWLockHeldByMe(ProcArrayLock));
2949 
2950  /*
2951  * Acquire XidGenLock, so no transactions can acquire an xid while we're
2952  * running. If no transaction with xid were running concurrently a new xid
2953  * could influence the RecentXmin et al.
2954  *
2955  * We initialize the computation to nextXid since that's guaranteed to be
2956  * a safe, albeit pessimal, value.
2957  */
2958  LWLockAcquire(XidGenLock, LW_SHARED);
2960 
2961  /*
2962  * If there's already a slot pegging the xmin horizon, we can start with
2963  * that value, it's guaranteed to be safe since it's computed by this
2964  * routine initially and has been enforced since. We can always use the
2965  * slot's general xmin horizon, but the catalog horizon is only usable
2966  * when only catalog data is going to be looked at.
2967  */
2970  oldestSafeXid))
2971  oldestSafeXid = procArray->replication_slot_xmin;
2972 
2973  if (catalogOnly &&
2976  oldestSafeXid))
2977  oldestSafeXid = procArray->replication_slot_catalog_xmin;
2978 
2979  /*
2980  * If we're not in recovery, we walk over the procarray and collect the
2981  * lowest xid. Since we're called with ProcArrayLock held and have
2982  * acquired XidGenLock, no entries can vanish concurrently, since
2983  * ProcGlobal->xids[i] is only set with XidGenLock held and only cleared
2984  * with ProcArrayLock held.
2985  *
2986  * In recovery we can't lower the safe value besides what we've computed
2987  * above, so we'll have to wait a bit longer there. We unfortunately can
2988  * *not* use KnownAssignedXidsGetOldestXmin() since the KnownAssignedXids
2989  * machinery can miss values and return an older value than is safe.
2990  */
2991  if (!recovery_in_progress)
2992  {
2993  TransactionId *other_xids = ProcGlobal->xids;
2994 
2995  /*
2996  * Spin over procArray collecting min(ProcGlobal->xids[i])
2997  */
2998  for (index = 0; index < arrayP->numProcs; index++)
2999  {
3000  TransactionId xid;
3001 
3002  /* Fetch xid just once - see GetNewTransactionId */
3003  xid = UINT32_ACCESS_ONCE(other_xids[index]);
3004 
3005  if (!TransactionIdIsNormal(xid))
3006  continue;
3007 
3008  if (TransactionIdPrecedes(xid, oldestSafeXid))
3009  oldestSafeXid = xid;
3010  }
3011  }
3012 
3013  LWLockRelease(XidGenLock);
3014 
3015  return oldestSafeXid;
3016 }
bool LWLockHeldByMe(LWLock *lock)
Definition: lwlock.c:1919

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 2018 of file procarray.c.

2019 {
2020  ComputeXidHorizonsResult horizons;
2021 
2022  ComputeXidHorizons(&horizons);
2023 
2024  return horizons.oldest_considered_running;
2025 }

References ComputeXidHorizons(), and ComputeXidHorizonsResult::oldest_considered_running.

Referenced by CreateCheckPoint(), and CreateRestartPoint().

◆ GetReplicationHorizons()

void GetReplicationHorizons ( TransactionId xmin,
TransactionId catalog_xmin 
)

Definition at line 2031 of file procarray.c.

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

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

Referenced by XLogWalRcvSendHSFeedback().

◆ GetRunningTransactionData()

RunningTransactions GetRunningTransactionData ( void  )

Definition at line 2701 of file procarray.c.

2702 {
2703  /* result workspace */
2704  static RunningTransactionsData CurrentRunningXactsData;
2705 
2706  ProcArrayStruct *arrayP = procArray;
2707  TransactionId *other_xids = ProcGlobal->xids;
2708  RunningTransactions CurrentRunningXacts = &CurrentRunningXactsData;
2709  TransactionId latestCompletedXid;
2710  TransactionId oldestRunningXid;
2711  TransactionId *xids;
2712  int index;
2713  int count;
2714  int subcount;
2715  bool suboverflowed;
2716 
2718 
2719  /*
2720  * Allocating space for maxProcs xids is usually overkill; numProcs would
2721  * be sufficient. But it seems better to do the malloc while not holding
2722  * the lock, so we can't look at numProcs. Likewise, we allocate much
2723  * more subxip storage than is probably needed.
2724  *
2725  * Should only be allocated in bgwriter, since only ever executed during
2726  * checkpoints.
2727  */
2728  if (CurrentRunningXacts->xids == NULL)
2729  {
2730  /*
2731  * First call
2732  */
2733  CurrentRunningXacts->xids = (TransactionId *)
2735  if (CurrentRunningXacts->xids == NULL)
2736  ereport(ERROR,
2737  (errcode(ERRCODE_OUT_OF_MEMORY),
2738  errmsg("out of memory")));
2739  }
2740 
2741  xids = CurrentRunningXacts->xids;
2742 
2743  count = subcount = 0;
2744  suboverflowed = false;
2745 
2746  /*
2747  * Ensure that no xids enter or leave the procarray while we obtain
2748  * snapshot.
2749  */
2750  LWLockAcquire(ProcArrayLock, LW_SHARED);
2751  LWLockAcquire(XidGenLock, LW_SHARED);
2752 
2753  latestCompletedXid =
2755  oldestRunningXid =
2757 
2758  /*
2759  * Spin over procArray collecting all xids
2760  */
2761  for (index = 0; index < arrayP->numProcs; index++)
2762  {
2763  TransactionId xid;
2764 
2765  /* Fetch xid just once - see GetNewTransactionId */
2766  xid = UINT32_ACCESS_ONCE(other_xids[index]);
2767 
2768  /*
2769  * We don't need to store transactions that don't have a TransactionId
2770  * yet because they will not show as running on a standby server.
2771  */
2772  if (!TransactionIdIsValid(xid))
2773  continue;
2774 
2775  /*
2776  * Be careful not to exclude any xids before calculating the values of
2777  * oldestRunningXid and suboverflowed, since these are used to clean
2778  * up transaction information held on standbys.
2779  */
2780  if (TransactionIdPrecedes(xid, oldestRunningXid))
2781  oldestRunningXid = xid;
2782 
2784  suboverflowed = true;
2785 
2786  /*
2787  * If we wished to exclude xids this would be the right place for it.
2788  * Procs with the PROC_IN_VACUUM flag set don't usually assign xids,
2789  * but they do during truncation at the end when they get the lock and
2790  * truncate, so it is not much of a problem to include them if they
2791  * are seen and it is cleaner to include them.
2792  */
2793 
2794  xids[count++] = xid;
2795  }
2796 
2797  /*
2798  * Spin over procArray collecting all subxids, but only if there hasn't
2799  * been a suboverflow.
2800  */
2801  if (!suboverflowed)
2802  {
2803  XidCacheStatus *other_subxidstates = ProcGlobal->subxidStates;
2804 
2805  for (index = 0; index < arrayP->numProcs; index++)
2806  {
2807  int pgprocno = arrayP->pgprocnos[index];
2808  PGPROC *proc = &allProcs[pgprocno];
2809  int nsubxids;
2810 
2811  /*
2812  * Save subtransaction XIDs. Other backends can't add or remove
2813  * entries while we're holding XidGenLock.
2814  */
2815  nsubxids = other_subxidstates[index].count;
2816  if (nsubxids > 0)
2817  {
2818  /* barrier not really required, as XidGenLock is held, but ... */
2819  pg_read_barrier(); /* pairs with GetNewTransactionId */
2820 
2821  memcpy(&xids[count], proc->subxids.xids,
2822  nsubxids * sizeof(TransactionId));
2823  count += nsubxids;
2824  subcount += nsubxids;
2825 
2826  /*
2827  * Top-level XID of a transaction is always less than any of
2828  * its subxids, so we don't need to check if any of the
2829  * subxids are smaller than oldestRunningXid
2830  */
2831  }
2832  }
2833  }
2834 
2835  /*
2836  * It's important *not* to include the limits set by slots here because
2837  * snapbuild.c uses oldestRunningXid to manage its xmin horizon. If those
2838  * were to be included here the initial value could never increase because
2839  * of a circular dependency where slots only increase their limits when
2840  * running xacts increases oldestRunningXid and running xacts only
2841  * increases if slots do.
2842  */
2843 
2844  CurrentRunningXacts->xcnt = count - subcount;
2845  CurrentRunningXacts->subxcnt = subcount;
2846  CurrentRunningXacts->subxid_overflow = suboverflowed;
2848  CurrentRunningXacts->oldestRunningXid = oldestRunningXid;
2849  CurrentRunningXacts->latestCompletedXid = latestCompletedXid;
2850 
2851  Assert(TransactionIdIsValid(CurrentRunningXacts->nextXid));
2852  Assert(TransactionIdIsValid(CurrentRunningXacts->oldestRunningXid));
2853  Assert(TransactionIdIsNormal(CurrentRunningXacts->latestCompletedXid));
2854 
2855  /* We don't release the locks here, the caller is responsible for that */
2856 
2857  return CurrentRunningXacts;
2858 }
#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 2190 of file procarray.c.

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

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(), GetSnapshotDataInitOldSnapshot(), GetSnapshotDataReuse(), GlobalVisCatalogRels, GlobalVisDataRels, GlobalVisSharedRels, GlobalVisTempRels, InvalidTransactionId, KnownAssignedXidsGetAndSetXmin(), ProcArrayStruct::lastOverflowedXid, VariableCacheData::latestCompletedXid, likely, 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, 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().

◆ GetSnapshotDataInitOldSnapshot()

static void GetSnapshotDataInitOldSnapshot ( Snapshot  snapshot)
static

Definition at line 2073 of file procarray.c.

2074 {
2076  {
2077  /*
2078  * If not using "snapshot too old" feature, fill related fields with
2079  * dummy values that don't require any locking.
2080  */
2081  snapshot->lsn = InvalidXLogRecPtr;
2082  snapshot->whenTaken = 0;
2083  }
2084  else
2085  {
2086  /*
2087  * Capture the current time and WAL stream location in case this
2088  * snapshot becomes old enough to need to fall back on the special
2089  * "old snapshot" logic.
2090  */
2091  snapshot->lsn = GetXLogInsertRecPtr();
2092  snapshot->whenTaken = GetSnapshotCurrentTimestamp();
2093  MaintainOldSnapshotTimeMapping(snapshot->whenTaken, snapshot->xmin);
2094  }
2095 }
void MaintainOldSnapshotTimeMapping(TimestampTz whenTaken, TransactionId xmin)
Definition: snapmgr.c:1903
TimestampTz GetSnapshotCurrentTimestamp(void)
Definition: snapmgr.c:1680
static bool OldSnapshotThresholdActive(void)
Definition: snapmgr.h:102
TimestampTz whenTaken
Definition: snapshot.h:208
XLogRecPtr lsn
Definition: snapshot.h:209
XLogRecPtr GetXLogInsertRecPtr(void)
Definition: xlog.c:8896
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28

References GetSnapshotCurrentTimestamp(), GetXLogInsertRecPtr(), InvalidXLogRecPtr, SnapshotData::lsn, MaintainOldSnapshotTimeMapping(), OldSnapshotThresholdActive(), SnapshotData::whenTaken, and SnapshotData::xmin.

Referenced by GetSnapshotData(), and GetSnapshotDataReuse().

◆ GetSnapshotDataReuse()

static bool GetSnapshotDataReuse ( Snapshot  snapshot)
static

Definition at line 2107 of file procarray.c.

2108 {
2109  uint64 curXactCompletionCount;
2110 
2111  Assert(LWLockHeldByMe(ProcArrayLock));
2112 
2113  if (unlikely(snapshot->snapXactCompletionCount == 0))
2114  return false;
2115 
2116  curXactCompletionCount = ShmemVariableCache->xactCompletionCount;
2117  if (curXactCompletionCount != snapshot->snapXactCompletionCount)
2118  return false;
2119 
2120  /*
2121  * If the current xactCompletionCount is still the same as it was at the
2122  * time the snapshot was built, we can be sure that rebuilding the
2123  * contents of the snapshot the hard way would result in the same snapshot
2124  * contents:
2125  *
2126  * As explained in transam/README, the set of xids considered running by
2127  * GetSnapshotData() cannot change while ProcArrayLock is held. Snapshot
2128  * contents only depend on transactions with xids and xactCompletionCount
2129  * is incremented whenever a transaction with an xid finishes (while
2130  * holding ProcArrayLock) exclusively). Thus the xactCompletionCount check
2131  * ensures we would detect if the snapshot would have changed.
2132  *
2133  * As the snapshot contents are the same as it was before, it is safe to
2134  * re-enter the snapshot's xmin into the PGPROC array. None of the rows
2135  * visible under the snapshot could already have been removed (that'd
2136  * require the set of running transactions to change) and it fulfills the
2137  * requirement that concurrent GetSnapshotData() calls yield the same
2138  * xmin.
2139  */
2141  MyProc->xmin = TransactionXmin = snapshot->xmin;
2142 
2143  RecentXmin = snapshot->xmin;
2145 
2146  snapshot->curcid = GetCurrentCommandId(false);
2147  snapshot->active_count = 0;
2148  snapshot->regd_count = 0;
2149  snapshot->copied = false;
2150 
2152 
2153  return true;
2154 }
#define unlikely(x)
Definition: c.h:295

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

Referenced by GetSnapshotData().

◆ GetVirtualXIDsDelayingChkpt()

VirtualTransactionId* GetVirtualXIDsDelayingChkpt ( int *  nvxids,
int  type 
)

Definition at line 3039 of file procarray.c.

3040 {
3041  VirtualTransactionId *vxids;
3042  ProcArrayStruct *arrayP = procArray;
3043  int count = 0;
3044  int index;
3045 
3046  Assert(type != 0);
3047 
3048  /* allocate what's certainly enough result space */
3049  vxids = (VirtualTransactionId *)
3050  palloc(sizeof(VirtualTransactionId) * arrayP->maxProcs);
3051 
3052  LWLockAcquire(ProcArrayLock, LW_SHARED);
3053 
3054  for (index = 0; index < arrayP->numProcs; index++)
3055  {
3056  int pgprocno = arrayP->pgprocnos[index];
3057  PGPROC *proc = &allProcs[pgprocno];
3058 
3059  if ((proc->delayChkptFlags & type) != 0)
3060  {
3061  VirtualTransactionId vxid;
3062 
3063  GET_VXID_FROM_PGPROC(vxid, *proc);
3064  if (VirtualTransactionIdIsValid(vxid))
3065  vxids[count++] = vxid;
3066  }
3067  }
3068 
3069  LWLockRelease(ProcArrayLock);
3070 
3071  *nvxids = count;
3072  return vxids;
3073 }
int delayChkptFlags
Definition: proc.h:231

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

Referenced by CreateCheckPoint().

◆ GlobalVisCheckRemovableFullXid()

bool GlobalVisCheckRemovableFullXid ( Relation  rel,
FullTransactionId  fxid 
)

Definition at line 4249 of file procarray.c.

4250 {
4252 
4253  state = GlobalVisTestFor(rel);
4254 
4255  return GlobalVisTestIsRemovableFullXid(state, fxid);
4256 }
bool GlobalVisTestIsRemovableFullXid(GlobalVisState *state, FullTransactionId fxid)
Definition: procarray.c:4155
GlobalVisState * GlobalVisTestFor(Relation rel)
Definition: procarray.c:4040
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 4263 of file procarray.c.

4264 {
4266 
4267  state = GlobalVisTestFor(rel);
4268 
4269  return GlobalVisTestIsRemovableXid(state, xid);
4270 }
bool GlobalVisTestIsRemovableXid(GlobalVisState *state, TransactionId xid)
Definition: procarray.c:4197

References GlobalVisTestFor(), and GlobalVisTestIsRemovableXid().

Referenced by GinPageIsRecyclable().

◆ GlobalVisHorizonKindForRel()

static GlobalVisHorizonKind GlobalVisHorizonKindForRel ( Relation  rel)
inlinestatic

Definition at line 1955 of file procarray.c.

1956 {
1957  /*
1958  * Other relkinds currently don't contain xids, nor always the necessary
1959  * logical decoding markers.
1960  */
1961  Assert(!rel ||
1962  rel->rd_rel->relkind == RELKIND_RELATION ||
1963  rel->rd_rel->relkind == RELKIND_MATVIEW ||
1964  rel->rd_rel->relkind == RELKIND_TOASTVALUE);
1965 
1966  if (rel == NULL || rel->rd_rel->relisshared || RecoveryInProgress())
1967  return VISHORIZON_SHARED;
1968  else if (IsCatalogRelation(rel) ||
1970  return VISHORIZON_CATALOG;
1971  else if (!RELATION_IS_LOCAL(rel))
1972  return VISHORIZON_DATA;
1973  else
1974  return VISHORIZON_TEMP;
1975 }
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 4040 of file procarray.c.

4041 {
4042  GlobalVisState *state = NULL;
4043 
4044  /* XXX: we should assert that a snapshot is pushed or registered */
4045  Assert(RecentXmin);
4046 
4047  switch (GlobalVisHorizonKindForRel(rel))
4048  {
4049  case VISHORIZON_SHARED:
4051  break;
4052  case VISHORIZON_CATALOG:
4054  break;
4055  case VISHORIZON_DATA:
4057  break;
4058  case VISHORIZON_TEMP:
4060  break;
4061  }
4062 
4063  Assert(FullTransactionIdIsValid(state->definitely_needed) &&
4064  FullTransactionIdIsValid(state->maybe_needed));
4065 
4066  return state;
4067 }
#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 4155 of file procarray.c.

4157 {
4158  /*
4159  * If fxid is older than maybe_needed bound, it definitely is visible to
4160  * everyone.
4161  */
4162  if (FullTransactionIdPrecedes(fxid, state->maybe_needed))
4163  return true;
4164 
4165  /*
4166  * If fxid is >= definitely_needed bound, it is very likely to still be
4167  * considered running.
4168  */
4169  if (FullTransactionIdFollowsOrEquals(fxid, state->definitely_needed))
4170  return false;
4171 
4172  /*
4173  * fxid is between maybe_needed and definitely_needed, i.e. there might or
4174  * might not exist a snapshot considering fxid running. If it makes sense,
4175  * update boundaries and recheck.
4176  */
4178  {
4179  GlobalVisUpdate();
4180 
4181  Assert(FullTransactionIdPrecedes(fxid, state->definitely_needed));
4182 
4183  return FullTransactionIdPrecedes(fxid, state->maybe_needed);
4184  }
4185  else
4186  return false;
4187 }
static bool GlobalVisTestShouldUpdate(GlobalVisState *state)
Definition: procarray.c:4080
static void GlobalVisUpdate(void)
Definition: procarray.c:4138
#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 4197 of file procarray.c.

4198 {
4199  FullTransactionId fxid;
4200 
4201  /*
4202  * Convert 32 bit argument to FullTransactionId. We can do so safely
4203  * because we know the xid has to, at the very least, be between
4204  * [oldestXid, nextXid), i.e. within 2 billion of xid. To avoid taking a
4205  * lock to determine either, we can just compare with
4206  * state->definitely_needed, which was based on those value at the time
4207  * the current snapshot was built.
4208  */
4209  fxid = FullXidRelativeTo(state->definitely_needed, xid);
4210 
4211  return GlobalVisTestIsRemovableFullXid(state, fxid);
4212 }

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 4224 of file procarray.c.

4225 {
4226  /* acquire accurate horizon if not already done */
4228  GlobalVisUpdate();
4229 
4230  return state->maybe_needed;
4231 }

References GlobalVisTestShouldUpdate(), and GlobalVisUpdate().

Referenced by GlobalVisTestNonRemovableHorizon().

◆ GlobalVisTestNonRemovableHorizon()

TransactionId GlobalVisTestNonRemovableHorizon ( GlobalVisState state)

Definition at line 4235 of file procarray.c.

4236 {
4237  FullTransactionId cutoff;
4238 
4240 
4241  return XidFromFullTransactionId(cutoff);
4242 }
FullTransactionId GlobalVisTestNonRemovableFullHorizon(GlobalVisState *state)
Definition: procarray.c:4224

References GlobalVisTestNonRemovableFullHorizon(), and XidFromFullTransactionId.

Referenced by heap_page_prune_opt(), and heap_prune_satisfies_vacuum().

◆ GlobalVisTestShouldUpdate()

static bool GlobalVisTestShouldUpdate ( GlobalVisState state)
static

Definition at line 4080 of file procarray.c.

4081 {
4082  /* hasn't been updated yet */
4084  return true;
4085 
4086  /*
4087  * If the maybe_needed/definitely_needed boundaries are the same, it's
4088  * unlikely to be beneficial to refresh boundaries.
4089  */
4090  if (FullTransactionIdFollowsOrEquals(state->maybe_needed,
4091  state->definitely_needed))
4092  return false;
4093 
4094  /* does the last snapshot built have a different xmin? */
4096 }
static TransactionId ComputeXidHorizonsResultLastXmin
Definition: procarray.c:310

References ComputeXidHorizonsResultLastXmin, FullTransactionIdFollowsOrEquals, RecentXmin, and TransactionIdIsValid.

Referenced by GlobalVisTestIsRemovableFullXid(), and GlobalVisTestNonRemovableFullHorizon().

◆ GlobalVisUpdate()

static void GlobalVisUpdate ( void  )
static

Definition at line 4138 of file procarray.c.

4139 {
4140  ComputeXidHorizonsResult horizons;
4141 
4142  /* updates the horizons as a side-effect */
4143  ComputeXidHorizons(&horizons);
4144 }

References ComputeXidHorizons().

Referenced by GlobalVisTestIsRemovableFullXid(), and GlobalVisTestNonRemovableFullHorizon().

◆ GlobalVisUpdateApply()

static void GlobalVisUpdateApply ( ComputeXidHorizonsResult horizons)
static

Definition at line 4099 of file procarray.c.

4100 {
4103  horizons->shared_oldest_nonremovable);
4106  horizons->catalog_oldest_nonremovable);
4109  horizons->data_oldest_nonremovable);
4112  horizons->temp_oldest_nonremovable);
4113 
4114  /*
4115  * In longer running transactions it's possible that transactions we
4116  * previously needed to treat as running aren't around anymore. So update
4117  * definitely_needed to not be earlier than maybe_needed.
4118  */
4129 
4131 }

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 3085 of file procarray.c.

3086 {
3087  bool result = false;
3088  ProcArrayStruct *arrayP = procArray;
3089  int index;
3090 
3091  Assert(type != 0);
3092 
3093  LWLockAcquire(ProcArrayLock, LW_SHARED);
3094 
3095  for (index = 0; index < arrayP->numProcs; index++)
3096  {
3097  int pgprocno = arrayP->pgprocnos[index];
3098  PGPROC *proc = &allProcs[pgprocno];
3099  VirtualTransactionId vxid;
3100 
3101  GET_VXID_FROM_PGPROC(vxid, *proc);
3102 
3103  if ((proc->delayChkptFlags & type) != 0 &&
3105  {
3106  int i;
3107 
3108  for (i = 0; i < nvxids; i++)
3109  {
3110  if (VirtualTransactionIdEquals(vxid, vxids[i]))
3111  {
3112  result = true;
3113  break;
3114  }
3115  }
3116  if (result)
3117  break;
3118  }
3119  }
3120 
3121  LWLockRelease(ProcArrayLock);
3122 
3123  return result;
3124 }
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, generate_unaccent_rules::type, VirtualTransactionIdEquals, and VirtualTransactionIdIsValid.

Referenced by CreateCheckPoint().

◆ IsBackendPid()

bool IsBackendPid ( int  pid)

Definition at line 3229 of file procarray.c.

3230 {
3231  return (BackendPidGetProc(pid) != NULL);
3232 }
PGPROC * BackendPidGetProc(int pid)
Definition: procarray.c:3134

References BackendPidGetProc().

Referenced by pg_stat_get_subscription().

◆ KnownAssignedTransactionIdsIdleMaintenance()

void KnownAssignedTransactionIdsIdleMaintenance ( void  )

Definition at line 4503 of file procarray.c.

4504 {
4506 }
static void KnownAssignedXidsCompress(KAXCompressReason reason, bool haveLock)
Definition: procarray.c:4607

References KAX_STARTUP_PROCESS_IDLE, and KnownAssignedXidsCompress().

Referenced by WaitForWALToBecomeAvailable().

◆ KnownAssignedXidExists()

static bool KnownAssignedXidExists ( TransactionId  xid)
static

Definition at line 4928 of file procarray.c.

4929 {
4931 
4932  return KnownAssignedXidsSearch(xid, false);
4933 }
static bool KnownAssignedXidsSearch(TransactionId xid, bool remove)
Definition: procarray.c:4835

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 4724 of file procarray.c.

4726 {
4727  ProcArrayStruct *pArray = procArray;
4728  TransactionId next_xid;
4729  int head,
4730  tail;
4731  int nxids;
4732  int i;
4733 
4734  Assert(TransactionIdPrecedesOrEquals(from_xid, to_xid));
4735 
4736  /*
4737  * Calculate how many array slots we'll need. Normally this is cheap; in
4738  * the unusual case where the XIDs cross the wrap point, we do it the hard
4739  * way.
4740  */
4741  if (to_xid >= from_xid)
4742  nxids = to_xid - from_xid + 1;
4743  else
4744  {
4745  nxids = 1;
4746  next_xid = from_xid;
4747  while (TransactionIdPrecedes(next_xid, to_xid))
4748  {
4749  nxids++;
4750  TransactionIdAdvance(next_xid);
4751  }
4752  }
4753 
4754  /*
4755  * Since only the startup process modifies the head/tail pointers, we
4756  * don't need a lock to read them here.
4757  */
4758  head = pArray->headKnownAssignedXids;
4759  tail = pArray->tailKnownAssignedXids;
4760 
4761  Assert(head >= 0 && head <= pArray->maxKnownAssignedXids);
4762  Assert(tail >= 0 && tail < pArray->maxKnownAssignedXids);
4763 
4764  /*
4765  * Verify that insertions occur in TransactionId sequence. Note that even
4766  * if the last existing element is marked invalid, it must still have a
4767  * correctly sequenced XID value.
4768  */
4769  if (head > tail &&
4770  TransactionIdFollowsOrEquals(KnownAssignedXids[head - 1], from_xid))
4771  {
4773  elog(ERROR, "out-of-order XID insertion in KnownAssignedXids");
4774  }
4775 
4776  /*
4777  * If our xids won't fit in the remaining space, compress out free space
4778  */
4779  if (head + nxids > pArray->maxKnownAssignedXids)
4780  {
4781  KnownAssignedXidsCompress(KAX_NO_SPACE, exclusive_lock);
4782 
4783  head = pArray->headKnownAssignedXids;
4784  /* note: we no longer care about the tail pointer */
4785 
4786  /*
4787  * If it still won't fit then we're out of memory
4788  */
4789  if (head + nxids > pArray->maxKnownAssignedXids)
4790  elog(ERROR, "too many KnownAssignedXids");
4791  }
4792 
4793  /* Now we can insert the xids into the space starting at head */
4794  next_xid = from_xid;
4795  for (i = 0; i < nxids; i++)
4796  {
4797  KnownAssignedXids[head] = next_xid;
4798  KnownAssignedXidsValid[head] = true;
4799  TransactionIdAdvance(next_xid);
4800  head++;
4801  }
4802 
4803  /* Adjust count of number of valid entries */
4804  pArray->numKnownAssignedXids += nxids;
4805 
4806  /*
4807  * Now update the head pointer. We use a spinlock to protect this
4808  * pointer, not because the update is likely to be non-atomic, but to
4809  * ensure that other processors see the above array updates before they
4810  * see the head pointer change.
4811  *
4812  * If we're holding ProcArrayLock exclusively, there's no need to take the
4813  * spinlock.
4814  */
4815  if (exclusive_lock)
4816  pArray->headKnownAssignedXids = head;
4817  else
4818  {
4820  pArray->headKnownAssignedXids = head;
4822  }
4823 }
#define LOG
Definition: elog.h:31
static void KnownAssignedXidsDisplay(int trace_level)
Definition: procarray.c:5174
#define SpinLockRelease(lock)
Definition: spin.h:64
#define SpinLockAcquire(lock)
Definition: spin.h:62
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:329

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

Referenced by ProcArrayApplyRecoveryInfo(), and RecordKnownAssignedTransactionIds().

◆ KnownAssignedXidsCompress()

static void KnownAssignedXidsCompress ( KAXCompressReason  reason,
bool  haveLock 
)
static

Definition at line 4607 of file procarray.c.

4608 {
4609  ProcArrayStruct *pArray = procArray;
4610  int head,
4611  tail,
4612  nelements;
4613  int compress_index;
4614  int i;
4615 
4616  /* Counters for compression heuristics */
4617  static unsigned int transactionEndsCounter;
4618  static TimestampTz lastCompressTs;
4619 
4620  /* Tuning constants */
4621 #define KAX_COMPRESS_FREQUENCY 128 /* in transactions */
4622 #define KAX_COMPRESS_IDLE_INTERVAL 1000 /* in ms */
4623 
4624  /*
4625  * Since only the startup process modifies the head/tail pointers, we
4626  * don't need a lock to read them here.
4627  */
4628  head = pArray->headKnownAssignedXids;
4629  tail = pArray->tailKnownAssignedXids;
4630  nelements = head - tail;
4631 
4632  /*
4633  * If we can choose whether to compress, use a heuristic to avoid
4634  * compressing too often or not often enough. "Compress" here simply
4635  * means moving the values to the beginning of the array, so it is not as
4636  * complex or costly as typical data compression algorithms.
4637  */
4638  if (nelements == pArray->numKnownAssignedXids)
4639  {
4640  /*
4641  * When there are no gaps between head and tail, don't bother to
4642  * compress, except in the KAX_NO_SPACE case where we must compress to
4643  * create some space after the head.
4644  */
4645  if (reason != KAX_NO_SPACE)
4646  return;
4647  }
4648  else if (reason == KAX_TRANSACTION_END)
4649  {
4650  /*
4651  * Consider compressing only once every so many commits. Frequency
4652  * determined by benchmarks.
4653  */
4654  if ((transactionEndsCounter++) % KAX_COMPRESS_FREQUENCY != 0)
4655  return;
4656 
4657  /*
4658  * Furthermore, compress only if the used part of the array is less
4659  * than 50% full (see comments above).
4660  */
4661  if (nelements < 2 * pArray->numKnownAssignedXids)
4662  return;
4663  }
4664  else if (reason == KAX_STARTUP_PROCESS_IDLE)
4665  {
4666  /*
4667  * We're about to go idle for lack of new WAL, so we might as well
4668  * compress. But not too often, to avoid ProcArray lock contention
4669  * with readers.
4670  */
4671  if (lastCompressTs != 0)
4672  {
4673  TimestampTz compress_after;
4674 
4675  compress_after = TimestampTzPlusMilliseconds(lastCompressTs,
4677  if (GetCurrentTimestamp() < compress_after)
4678  return;
4679  }
4680  }
4681 
4682  /* Need to compress, so get the lock if we don't have it. */
4683  if (!haveLock)
4684  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4685 
4686  /*
4687  * We compress the array by reading the valid values from tail to head,
4688  * re-aligning data to 0th element.
4689  */
4690  compress_index = 0;
4691  for (i = tail; i < head; i++)
4692  {
4694  {
4695  KnownAssignedXids[compress_index] = KnownAssignedXids[i];
4696  KnownAssignedXidsValid[compress_index] = true;
4697  compress_index++;
4698  }
4699  }
4700  Assert(compress_index == pArray->numKnownAssignedXids);
4701 
4702  pArray->tailKnownAssignedXids = 0;
4703  pArray->headKnownAssignedXids = compress_index;
4704 
4705  if (!haveLock)
4706  LWLockRelease(ProcArrayLock);
4707 
4708  /* Update timestamp for maintenance. No need to hold lock for this. */
4709  lastCompressTs = GetCurrentTimestamp();
4710 }
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 5174 of file procarray.c.

5175 {
5176  ProcArrayStruct *pArray = procArray;
5178  int head,
5179  tail,
5180  i;
5181  int nxids = 0;
5182 
5183  tail = pArray->tailKnownAssignedXids;
5184  head = pArray->headKnownAssignedXids;
5185 
5186  initStringInfo(&buf);
5187 
5188  for (i = tail; i < head; i++)
5189  {
5191  {
5192  nxids++;
5193  appendStringInfo(&buf, "[%d]=%u ", i, KnownAssignedXids[i]);
5194  }
5195  }
5196 
5197  elog(trace_level, "%d KnownAssignedXids (num=%d tail=%d head=%d) %s",
5198  nxids,
5199  pArray->numKnownAssignedXids,
5200  pArray->tailKnownAssignedXids,
5201  pArray->headKnownAssignedXids,
5202  buf.data);
5203 
5204  pfree(buf.data);
5205 }
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 5067 of file procarray.c.

5068 {
5070 
5071  return KnownAssignedXidsGetAndSetXmin(xarray, &xtmp, xmax);
5072 }

References InvalidTransactionId, and KnownAssignedXidsGetAndSetXmin().

Referenced by TransactionIdIsInProgress().

◆ KnownAssignedXidsGetAndSetXmin()

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

Definition at line 5081 of file procarray.c.

5083 {
5084  int count = 0;
5085  int head,
5086  tail;
5087  int i;
5088 
5089  /*
5090  * Fetch head just once, since it may change while we loop. We can stop
5091  * once we reach the initially seen head, since we are certain that an xid
5092  * cannot enter and then leave the array while we hold ProcArrayLock. We
5093  * might miss newly-added xids, but they should be >= xmax so irrelevant
5094  * anyway.
5095  *
5096  * Must take spinlock to ensure we see up-to-date array contents.
5097  */
5102 
5103  for (i = tail; i < head; i++)
5104  {
5105  /* Skip any gaps in the array */
5107  {
5108  TransactionId knownXid = KnownAssignedXids[i];
5109 
5110  /*
5111  * Update xmin if required. Only the first XID need be checked,
5112  * since the array is sorted.
5113  */
5114  if (count == 0 &&
5115  TransactionIdPrecedes(knownXid, *xmin))
5116  *xmin = knownXid;
5117 
5118  /*
5119  * Filter out anything >= xmax, again relying on sorted property
5120  * of array.
5121  */
5122  if (TransactionIdIsValid(xmax) &&
5123  TransactionIdFollowsOrEquals(knownXid, xmax))
5124  break;
5125 
5126  /* Add knownXid into output array */
5127  xarray[count++] = knownXid;
5128  }
5129  }
5130 
5131  return count;
5132 }

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

Referenced by GetSnapshotData(), and KnownAssignedXidsGet().

◆ KnownAssignedXidsGetOldestXmin()

static TransactionId KnownAssignedXidsGetOldestXmin ( void  )
static

Definition at line 5139 of file procarray.c.

5140 {
5141  int head,
5142  tail;
5143  int i;
5144 
5145  /*
5146  * Fetch head just once, since it may change while we loop.
5147  */
5152 
5153  for (i = tail; i < head; i++)
5154  {
5155  /* Skip any gaps in the array */
5157  return KnownAssignedXids[i];
5158  }
5159 
5160  return InvalidTransactionId;
5161 }

References ProcArrayStruct::headKnownAssignedXids, i, InvalidTransactionId, ProcArrayStruct::known_assigned_xids_lck, KnownAssignedXids, KnownAssignedXidsValid, procArray, SpinLockAcquire, SpinLockRelease, and ProcArrayStruct::tailKnownAssignedXids.

Referenced by ComputeXidHorizons().

◆ KnownAssignedXidsRemove()

static void KnownAssignedXidsRemove ( TransactionId  xid)
static

Definition at line 4941 of file procarray.c.

4942 {
4944 
4945  elog(trace_recovery(DEBUG4), "remove KnownAssignedXid %u", xid);
4946 
4947  /*
4948  * Note: we cannot consider it an error to remove an XID that's not
4949  * present. We intentionally remove subxact IDs while processing
4950  * XLOG_XACT_ASSIGNMENT, to avoid array overflow. Then those XIDs will be
4951  * removed again when the top-level xact commits or aborts.
4952  *
4953  * It might be possible to track such XIDs to distinguish this case from
4954  * actual errors, but it would be complicated and probably not worth it.
4955  * So, just ignore the search result.
4956  */
4957  (void) KnownAssignedXidsSearch(xid, true);
4958 }
int trace_recovery(int trace_level)
Definition: elog.c:3749
#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 4989 of file procarray.c.

4990 {
4991  ProcArrayStruct *pArray = procArray;
4992  int count = 0;
4993  int head,
4994  tail,
4995  i;
4996 
4997  if (!TransactionIdIsValid(removeXid))
4998  {
4999  elog(trace_recovery(DEBUG4), "removing all KnownAssignedXids");
5000  pArray->numKnownAssignedXids = 0;
5001  pArray->headKnownAssignedXids = pArray->tailKnownAssignedXids = 0;
5002  return;
5003  }
5004 
5005  elog(trace_recovery(DEBUG4), "prune KnownAssignedXids to %u", removeXid);
5006 
5007  /*
5008  * Mark entries invalid starting at the tail. Since array is sorted, we
5009  * can stop as soon as we reach an entry >= removeXid.
5010  */
5011  tail = pArray->tailKnownAssignedXids;
5012  head = pArray->headKnownAssignedXids;
5013 
5014  for (i = tail; i < head; i++)
5015  {
5017  {
5018  TransactionId knownXid = KnownAssignedXids[i];
5019 
5020  if (TransactionIdFollowsOrEquals(knownXid, removeXid))
5021  break;
5022 
5023  if (!StandbyTransactionIdIsPrepared(knownXid))
5024  {
5025  KnownAssignedXidsValid[i] = false;
5026  count++;
5027  }
5028  }
5029  }
5030 
5031  pArray->numKnownAssignedXids -= count;
5032  Assert(pArray->numKnownAssignedXids >= 0);
5033 
5034  /*
5035  * Advance the tail pointer if we've marked the tail item invalid.
5036  */
5037  for (i = tail; i < head; i++)
5038  {
5040  break;
5041  }
5042  if (i >= head)
5043  {
5044  /* Array is empty, so we can reset both pointers */
5045  pArray->headKnownAssignedXids = 0;
5046  pArray->tailKnownAssignedXids = 0;
5047  }
5048  else
5049  {
5050  pArray->tailKnownAssignedXids = i;
5051  }
5052 
5053  /* Opportunistically compress the array */
5055 }
bool StandbyTransactionIdIsPrepared(TransactionId xid)
Definition: twophase.c:1452

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 4967 of file procarray.c.

4969 {
4970  int i;
4971 
4972  if (TransactionIdIsValid(xid))
4974 
4975  for (i = 0; i < nsubxids; i++)
4976  KnownAssignedXidsRemove(subxids[i]);
4977 
4978  /* Opportunistically compress the array */
4980 }
static void KnownAssignedXidsRemove(TransactionId xid)
Definition: procarray.c:4941

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

Referenced by ExpireTreeKnownAssignedTransactionIds(), and ProcArrayApplyXidAssignment().

◆ KnownAssignedXidsReset()

static void KnownAssignedXidsReset ( void  )
static

Definition at line 5212 of file procarray.c.

5213 {
5214  ProcArrayStruct *pArray = procArray;
5215 
5216  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
5217 
5218  pArray->numKnownAssignedXids = 0;
5219  pArray->tailKnownAssignedXids = 0;
5220  pArray->headKnownAssignedXids = 0;
5221 
5222  LWLockRelease(ProcArrayLock);
5223 }

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 4835 of file procarray.c.

4836 {
4837  ProcArrayStruct *pArray = procArray;
4838  int first,
4839  last;
4840  int head;
4841  int tail;
4842  int result_index = -1;
4843 
4844  if (remove)
4845  {
4846  /* we hold ProcArrayLock exclusively, so no need for spinlock */
4847  tail = pArray->tailKnownAssignedXids;
4848  head = pArray->headKnownAssignedXids;
4849  }
4850  else
4851  {
4852  /* take spinlock to ensure we see up-to-date array contents */
4854  tail = pArray->tailKnownAssignedXids;
4855  head = pArray->headKnownAssignedXids;
4857  }
4858 
4859  /*
4860  * Standard binary search. Note we can ignore the KnownAssignedXidsValid
4861  * array here, since even invalid entries will contain sorted XIDs.
4862  */
4863  first = tail;
4864  last = head - 1;
4865  while (first <= last)
4866  {
4867  int mid_index;
4868  TransactionId mid_xid;
4869 
4870  mid_index = (first + last) / 2;
4871  mid_xid = KnownAssignedXids[mid_index];
4872 
4873  if (xid == mid_xid)
4874  {
4875  result_index = mid_index;
4876  break;
4877  }
4878  else if (TransactionIdPrecedes(xid, mid_xid))
4879  last = mid_index - 1;
4880  else
4881  first = mid_index + 1;
4882  }
4883 
4884  if (result_index < 0)
4885  return false; /* not in array */
4886 
4887  if (!KnownAssignedXidsValid[result_index])
4888  return false; /* in array, but invalid */
4889 
4890  if (remove)
4891  {
4892  KnownAssignedXidsValid[result_index] = false;
4893 
4894  pArray->numKnownAssignedXids--;
4895  Assert(pArray->numKnownAssignedXids >= 0);
4896 
4897  /*
4898  * If we're removing the tail element then advance tail pointer over
4899  * any invalid elements. This will speed future searches.
4900  */
4901  if (result_index == tail)
4902  {
4903  tail++;
4904  while (tail < head && !KnownAssignedXidsValid[tail])
4905  tail++;
4906  if (tail >= head)
4907  {
4908  /* Array is empty, so we can reset both pointers */
4909  pArray->headKnownAssignedXids = 0;
4910  pArray->tailKnownAssignedXids = 0;
4911  }
4912  else
4913  {
4914  pArray->tailKnownAssignedXids = tail;
4915  }
4916  }
4917  }
4918 
4919  return true;
4920 }

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

Referenced by KnownAssignedXidExists(), and KnownAssignedXidsRemove().

◆ MaintainLatestCompletedXid()

◆ MaintainLatestCompletedXidRecovery()

static void MaintainLatestCompletedXidRecovery ( TransactionId  latestXid)
static

Definition at line 991 of file procarray.c.

992 {
994  FullTransactionId rel;
995 
997  Assert(LWLockHeldByMe(ProcArrayLock));
998 
999  /*
1000  * Need a FullTransactionId to compare latestXid with. Can't rely on
1001  * latestCompletedXid to be initialized in recovery. But in recovery it's
1002  * safe to access nextXid without a lock for the startup process.
1003  */
1004  rel = ShmemVariableCache->nextXid;
1006 
1007  if (!FullTransactionIdIsValid(cur_latest) ||
1008  TransactionIdPrecedes(XidFromFullTransactionId(cur_latest), latestXid))
1009  {
1011  FullXidRelativeTo(rel, latestXid);
1012  }
1013 
1015 }
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 3484 of file procarray.c.

3485 {
3486  ProcArrayStruct *arrayP = procArray;
3487  int count = 0;
3488  int index;
3489 
3490  /* Quick short-circuit if no minimum is specified */
3491  if (min == 0)
3492  return true;
3493 
3494  /*
3495  * Note: for speed, we don't acquire ProcArrayLock. This is a little bit
3496  * bogus, but since we are only testing fields for zero or nonzero, it
3497  * should be OK. The result is only used for heuristic purposes anyway...
3498  */
3499  for (index = 0; index < arrayP->numProcs; index++)
3500  {
3501  int pgprocno = arrayP->pgprocnos[index];
3502  PGPROC *proc = &allProcs[pgprocno];
3503 
3504  /*
3505  * Since we're not holding a lock, need to be prepared to deal with
3506  * garbage, as someone could have incremented numProcs but not yet
3507  * filled the structure.
3508  *
3509  * If someone just decremented numProcs, 'proc' could also point to a
3510  * PGPROC entry that's no longer in the array. It still points to a
3511  * PGPROC struct, though, because freed PGPROC entries just go to the
3512  * free list and are recycled. Its contents are nonsense in that case,
3513  * but that's acceptable for this function.
3514  */
3515  if (pgprocno == -1)
3516  continue; /* do not count deleted entries */
3517  if (proc == MyProc)
3518  continue; /* do not count myself */
3519  if (proc->xid == InvalidTransactionId)
3520  continue; /* do not count if no XID assigned */
3521  if (proc->pid == 0)
3522  continue; /* do not count prepared xacts */
3523  if (proc->waitLock != NULL)
3524  continue; /* do not count if blocked on a lock */
3525  count++;
3526  if (count >= min)
3527  break;
3528  }
3529 
3530  return count >= min;
3531 }
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 472 of file procarray.c.

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

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

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

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

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

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 734 of file procarray.c.

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

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 3901 of file procarray.c.

3903 {
3904  LWLockAcquire(ProcArrayLock, LW_SHARED);
3905 
3906  if (xmin != NULL)
3908 
3909  if (catalog_xmin != NULL)
3910  *catalog_xmin = procArray->replication_slot_catalog_xmin;
3911 
3912  LWLockRelease(ProcArrayLock);
3913 }

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 795 of file procarray.c.

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

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, WAIT_EVENT_PROCARRAY_GROUP_UPDATE, and PGPROC::xid.

Referenced by ProcArrayEndTransaction().

◆ ProcArrayInitRecovery()

void ProcArrayInitRecovery ( TransactionId  initializedUptoXID)

Definition at line 1025 of file procarray.c.

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

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

Referenced by StartupXLOG().

◆ ProcArrayInstallImportedXmin()

bool ProcArrayInstallImportedXmin ( TransactionId  xmin,
VirtualTransactionId sourcevxid 
)

Definition at line 2549 of file procarray.c.

2551 {
2552  bool result = false;
2553  ProcArrayStruct *arrayP = procArray;
2554  int index;
2555 
2557  if (!sourcevxid)
2558  return false;
2559 
2560  /* Get lock so source xact can't end while we're doing this */
2561  LWLockAcquire(ProcArrayLock, LW_SHARED);
2562 
2563  for (index = 0; index < arrayP->numProcs; index++)
2564  {
2565  int pgprocno = arrayP->pgprocnos[index];
2566  PGPROC *proc = &allProcs[pgprocno];
2567  int statusFlags = ProcGlobal->statusFlags[index];
2568  TransactionId xid;
2569 
2570  /* Ignore procs running LAZY VACUUM */
2571  if (statusFlags & PROC_IN_VACUUM)
2572  continue;
2573 
2574  /* We are only interested in the specific virtual transaction. */
2575  if (proc->backendId != sourcevxid->backendId)
2576  continue;
2577  if (proc->lxid != sourcevxid->localTransactionId)
2578  continue;
2579 
2580  /*
2581  * We check the transaction's database ID for paranoia's sake: if it's
2582  * in another DB then its xmin does not cover us. Caller should have
2583  * detected this already, so we just treat any funny cases as
2584  * "transaction not found".
2585  */
2586  if (proc->databaseId != MyDatabaseId)
2587  continue;
2588 
2589  /*
2590  * Likewise, let's just make real sure its xmin does cover us.
2591  */
2592  xid = UINT32_ACCESS_ONCE(proc->xmin);
2593  if (!TransactionIdIsNormal(xid) ||
2594  !TransactionIdPrecedesOrEquals(xid, xmin))
2595  continue;
2596 
2597  /*
2598  * We're good. Install the new xmin. As in GetSnapshotData, set
2599  * TransactionXmin too. (Note that because snapmgr.c called
2600  * GetSnapshotData first, we'll be overwriting a valid xmin here, so
2601  * we don't check that.)
2602  */
2603  MyProc->xmin = TransactionXmin = xmin;
2604 
2605  result = true;
2606  break;
2607  }
2608 
2609  LWLockRelease(ProcArrayLock);
2610 
2611  return result;
2612 }
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 2628 of file procarray.c.

2629 {
2630  bool result = false;
2631  TransactionId xid;
2632 
2634  Assert(proc != NULL);
2635 
2636  /*
2637  * Get an exclusive lock so that we can copy statusFlags from source proc.
2638  */
2639  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
2640 
2641  /*
2642  * Be certain that the referenced PGPROC has an advertised xmin which is
2643  * no later than the one we're installing, so that the system-wide xmin
2644  * can't go backwards. Also, make sure it's running in the same database,
2645  * so that the per-database xmin cannot go backwards.
2646  */
2647  xid = UINT32_ACCESS_ONCE(proc->xmin);
2648  if (proc->databaseId == MyDatabaseId &&
2649  TransactionIdIsNormal(xid) &&
2650  TransactionIdPrecedesOrEquals(xid, xmin))
2651  {
2652  /*
2653  * Install xmin and propagate the statusFlags that affect how the
2654  * value is interpreted by vacuum.
2655  */
2656  MyProc->xmin = TransactionXmin = xmin;
2658  (proc->statusFlags & PROC_XMIN_FLAGS);
2660 
2661  result = true;
2662  }
2663 
2664  LWLockRelease(ProcArrayLock);
2665 
2666  return result;
2667 }
#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 568 of file procarray.c.

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

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 3876 of file procarray.c.

3878 {
3879  Assert(!already_locked || LWLockHeldByMe(ProcArrayLock));
3880 
3881  if (!already_locked)
3882  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3883 
3885  procArray->replication_slot_catalog_xmin = catalog_xmin;
3886 
3887  if (!already_locked)
3888  LWLockRelease(ProcArrayLock);
3889 
3890  elog(DEBUG1, "xmin required by slots: data %u, catalog %u",
3891  xmin, catalog_xmin);
3892 }

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 379 of file procarray.c.

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

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

Referenced by CalculateShmemSize().

◆ RecordKnownAssignedTransactionIds()

void RecordKnownAssignedTransactionIds ( TransactionId  xid)

Definition at line 4366 of file procarray.c.

4367 {
4371 
4372  elog(trace_recovery(DEBUG4), "record known xact %u latestObservedXid %u",
4373  xid, latestObservedXid);
4374 
4375  /*
4376  * When a newly observed xid arrives, it is frequently the case that it is
4377  * *not* the next xid in sequence. When this occurs, we must treat the
4378  * intervening xids as running also.
4379  */
4381  {
4382  TransactionId next_expected_xid;
4383 
4384  /*
4385  * Extend subtrans like we do in GetNewTransactionId() during normal
4386  * operation using individual extend steps. Note that we do not need
4387  * to extend clog since its extensions are WAL logged.
4388  *
4389  * This part has to be done regardless of standbyState since we
4390  * immediately start assigning subtransactions to their toplevel
4391  * transactions.
4392  */
4393  next_expected_xid = latestObservedXid;
4394  while (TransactionIdPrecedes(next_expected_xid, xid))
4395  {
4396  TransactionIdAdvance(next_expected_xid);
4397  ExtendSUBTRANS(next_expected_xid);
4398  }
4399  Assert(next_expected_xid == xid);
4400 
4401  /*
4402  * If the KnownAssignedXids machinery isn't up yet, there's nothing
4403  * more to do since we don't track assigned xids yet.
4404  */
4406  {
4407  latestObservedXid = xid;
4408  return;
4409  }
4410 
4411  /*
4412  * Add (latestObservedXid, xid] onto the KnownAssignedXids array.
4413  */
4414  next_expected_xid = latestObservedXid;
4415  TransactionIdAdvance(next_expected_xid);
4416  KnownAssignedXidsAdd(next_expected_xid, xid, false);
4417 
4418  /*
4419  * Now we can advance latestObservedXid
4420  */
4421  latestObservedXid = xid;
4422 
4423  /* ShmemVariableCache->nextXid must be beyond any observed xid */
4425  }
4426 }

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 3435 of file procarray.c.

3437 {
3438  ProcArrayStruct *arrayP = procArray;
3439  int index;
3440  pid_t pid = 0;
3441 
3442  LWLockAcquire(ProcArrayLock, LW_SHARED);
3443 
3444  for (index = 0; index < arrayP->numProcs; index++)
3445  {
3446  int pgprocno = arrayP->pgprocnos[index];
3447  PGPROC *proc = &allProcs[pgprocno];
3448  VirtualTransactionId procvxid;
3449 
3450  GET_VXID_FROM_PGPROC(procvxid, *proc);
3451 
3452  if (procvxid.backendId == vxid.backendId &&
3453  procvxid.localTransactionId == vxid.localTransactionId)
3454  {
3455  proc->recoveryConflictPending = conflictPending;
3456  pid = proc->pid;
3457  if (pid != 0)
3458  {
3459  /*
3460  * Kill the pid if it's still here. If not, that's what we
3461  * wanted so ignore any errors.
3462  */
3463  (void) SendProcSignal(pid, sigmode, vxid.backendId);
3464  }
3465  break;
3466  }
3467  }
3468 
3469  LWLockRelease(ProcArrayLock);
3470 
3471  return pid;
3472 }

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 3766 of file procarray.c.

3767 {
3768  ProcArrayStruct *arrayP = procArray;
3769  List *pids = NIL;
3770  int nprepared = 0;
3771  int i;
3772 
3773  LWLockAcquire(ProcArrayLock, LW_SHARED);
3774 
3775  for (i = 0; i < procArray->numProcs; i++)
3776  {
3777  int pgprocno = arrayP->pgprocnos[i];
3778  PGPROC *proc = &allProcs[pgprocno];
3779 
3780  if (proc->databaseId != databaseId)
3781  continue;
3782  if (proc == MyProc)
3783  continue;
3784 
3785  if (proc->pid != 0)
3786  pids = lappend_int(pids, proc->pid);
3787  else
3788  nprepared++;
3789  }
3790 
3791  LWLockRelease(ProcArrayLock);
3792 
3793  if (nprepared > 0)
3794  ereport(ERROR,
3795  (errcode(ERRCODE_OBJECT_IN_USE),
3796  errmsg("database \"%s\" is being used by prepared transactions",
3797  get_database_name(databaseId)),
3798  errdetail_plural("There is %d prepared transaction using the database.",
3799  "There are %d prepared transactions using the database.",
3800  nprepared,
3801  nprepared)));
3802 
3803  if (pids)
3804  {
3805  ListCell *lc;
3806 
3807  /*
3808  * Check whether we have the necessary rights to terminate other
3809  * sessions. We don't terminate any session until we ensure that we
3810  * have rights on all the sessions to be terminated. These checks are
3811  * the same as we do in pg_terminate_backend.
3812  *
3813  * In this case we don't raise some warnings - like "PID %d is not a
3814  * PostgreSQL server process", because for us already finished session
3815  * is not a problem.
3816  */
3817  foreach(lc, pids)
3818  {
3819  int pid = lfirst_int(lc);
3820  PGPROC *proc = BackendPidGetProc(pid);
3821 
3822  if (proc != NULL)
3823  {
3824  /* Only allow superusers to signal superuser-owned backends. */
3825  if (superuser_arg(proc->roleId) && !superuser())
3826  ereport(ERROR,
3827  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3828  errmsg("must be a superuser to terminate superuser process")));
3829 
3830  /* Users can signal backends they have role membership in. */
3831  if (!has_privs_of_role(GetUserId(), proc->roleId) &&
3832  !has_privs_of_role(GetUserId(), ROLE_PG_SIGNAL_BACKEND))
3833  ereport(ERROR,
3834  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3835  errmsg("permission denied to terminate process"),
3836  errdetail("Only roles with privileges of the role whose process is being terminated or with privileges of the \"%s\" role may terminate this process.",
3837  "pg_signal_backend")));
3838  }
3839  }
3840 
3841  /*
3842  * There's a race condition here: once we release the ProcArrayLock,
3843  * it's possible for the session to exit before we issue kill. That
3844  * race condition possibility seems too unlikely to worry about. See
3845  * pg_signal_backend.
3846  */
3847  foreach(lc, pids)
3848  {
3849  int pid = lfirst_int(lc);
3850  PGPROC *proc = BackendPidGetProc(pid);
3851 
3852  if (proc != NULL)
3853  {
3854  /*
3855  * If we have setsid(), signal the backend's whole process
3856  * group
3857  */
3858 #ifdef HAVE_SETSID
3859  (void) kill(-pid, SIGTERM);
3860 #else
3861  (void) kill(pid, SIGTERM);
3862 #endif
3863  }
3864  }
3865  }
3866 }
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:4969
char * get_database_name(Oid dbid)
Definition: dbcommands.c:3043
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:510
#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 1618 of file procarray.c.

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

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 1386 of file procarray.c.

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