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 "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 */
 

Typedefs

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

Enumerations

enum  GlobalVisHorizonKind { VISHORIZON_SHARED , VISHORIZON_CATALOG , VISHORIZON_DATA , VISHORIZON_TEMP }
 

Functions

static void KnownAssignedXidsCompress (bool force)
 
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 xid)
 
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)
 
bool HaveVirtualXIDsDelayingChkpt (VirtualTransactionId *vxids, int nvxids)
 
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)
 

Variables

static ProcArrayStructprocArray
 
static PGPROCallProcs
 
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

◆ MAXAUTOVACPIDS

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

◆ PROCARRAY_MAXPROCS

#define PROCARRAY_MAXPROCS   (MaxBackends + max_prepared_xacts)

◆ TOTAL_MAX_CACHED_SUBXIDS

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

◆ UINT32_ACCESS_ONCE

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

Definition at line 69 of file procarray.c.

◆ xc_by_child_xid_inc

#define xc_by_child_xid_inc ( )    ((void) 0)

Definition at line 327 of file procarray.c.

◆ xc_by_known_assigned_inc

#define xc_by_known_assigned_inc ( )    ((void) 0)

Definition at line 328 of file procarray.c.

◆ xc_by_known_xact_inc

#define xc_by_known_xact_inc ( )    ((void) 0)

Definition at line 323 of file procarray.c.

◆ xc_by_latest_xid_inc

#define xc_by_latest_xid_inc ( )    ((void) 0)

Definition at line 325 of file procarray.c.

◆ xc_by_main_xid_inc

#define xc_by_main_xid_inc ( )    ((void) 0)

Definition at line 326 of file procarray.c.

◆ xc_by_my_xact_inc

#define xc_by_my_xact_inc ( )    ((void) 0)

Definition at line 324 of file procarray.c.

◆ xc_by_recent_xmin_inc

#define xc_by_recent_xmin_inc ( )    ((void) 0)

Definition at line 322 of file procarray.c.

◆ xc_no_overflow_inc

#define xc_no_overflow_inc ( )    ((void) 0)

Definition at line 329 of file procarray.c.

◆ xc_slow_answer_inc

#define xc_slow_answer_inc ( )    ((void) 0)

Definition at line 330 of file procarray.c.

Typedef Documentation

◆ ComputeXidHorizonsResult

◆ GlobalVisHorizonKind

◆ 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

Function Documentation

◆ BackendPidGetProc()

PGPROC* BackendPidGetProc ( int  pid)

Definition at line 3146 of file procarray.c.

3147 {
3148  PGPROC *result;
3149 
3150  if (pid == 0) /* never match dummy PGPROCs */
3151  return NULL;
3152 
3153  LWLockAcquire(ProcArrayLock, LW_SHARED);
3154 
3155  result = BackendPidGetProcWithLock(pid);
3156 
3157  LWLockRelease(ProcArrayLock);
3158 
3159  return result;
3160 }
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1199
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1803
@ LW_SHARED
Definition: lwlock.h:105
PGPROC * BackendPidGetProcWithLock(int pid)
Definition: procarray.c:3169
Definition: proc.h:125

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

3170 {
3171  PGPROC *result = NULL;
3172  ProcArrayStruct *arrayP = procArray;
3173  int index;
3174 
3175  if (pid == 0) /* never match dummy PGPROCs */
3176  return NULL;
3177 
3178  for (index = 0; index < arrayP->numProcs; index++)
3179  {
3180  PGPROC *proc = &allProcs[arrayP->pgprocnos[index]];
3181 
3182  if (proc->pid == pid)
3183  {
3184  result = proc;
3185  break;
3186  }
3187  }
3188 
3189  return result;
3190 }
static PGPROC * allProcs
Definition: procarray.c:263
static ProcArrayStruct * procArray
Definition: procarray.c:261
int pid
Definition: proc.h:149
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
Definition: type.h:90

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

Referenced by BackendPidGetProc(), and GetBlockerStatusData().

◆ BackendXidGetPid()

int BackendXidGetPid ( TransactionId  xid)

Definition at line 3206 of file procarray.c.

3207 {
3208  int result = 0;
3209  ProcArrayStruct *arrayP = procArray;
3210  TransactionId *other_xids = ProcGlobal->xids;
3211  int index;
3212 
3213  if (xid == InvalidTransactionId) /* never match invalid xid */
3214  return 0;
3215 
3216  LWLockAcquire(ProcArrayLock, LW_SHARED);
3217 
3218  for (index = 0; index < arrayP->numProcs; index++)
3219  {
3220  int pgprocno = arrayP->pgprocnos[index];
3221  PGPROC *proc = &allProcs[pgprocno];
3222 
3223  if (other_xids[index] == xid)
3224  {
3225  result = proc->pid;
3226  break;
3227  }
3228  }
3229 
3230  LWLockRelease(ProcArrayLock);
3231 
3232  return result;
3233 }
uint32 TransactionId
Definition: c.h:587
PROC_HDR * ProcGlobal
Definition: proc.c:80
TransactionId * xids
Definition: proc.h:324
#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 3605 of file procarray.c.

3606 {
3607  ProcArrayStruct *arrayP = procArray;
3608  int index;
3609 
3610  /* tell all backends to die */
3611  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3612 
3613  for (index = 0; index < arrayP->numProcs; index++)
3614  {
3615  int pgprocno = arrayP->pgprocnos[index];
3616  PGPROC *proc = &allProcs[pgprocno];
3617 
3618  if (databaseid == InvalidOid || proc->databaseId == databaseid)
3619  {
3620  VirtualTransactionId procvxid;
3621  pid_t pid;
3622 
3623  GET_VXID_FROM_PGPROC(procvxid, *proc);
3624 
3625  proc->recoveryConflictPending = conflictPending;
3626  pid = proc->pid;
3627  if (pid != 0)
3628  {
3629  /*
3630  * Kill the pid if it's still here. If not, that's what we
3631  * wanted so ignore any errors.
3632  */
3633  (void) SendProcSignal(pid, sigmode, procvxid.backendId);
3634  }
3635  }
3636  }
3637 
3638  LWLockRelease(ProcArrayLock);
3639 }
#define GET_VXID_FROM_PGPROC(vxid, proc)
Definition: lock.h:82
@ LW_EXCLUSIVE
Definition: lwlock.h:104
#define InvalidOid
Definition: postgres_ext.h:36
int SendProcSignal(pid_t pid, ProcSignalReason reason, BackendId backendId)
Definition: procsignal.c:261
bool recoveryConflictPending
Definition: proc.h:170
Oid databaseId
Definition: proc.h:157
BackendId backendId
Definition: lock.h:66

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

3437 {
3438  return SignalVirtualTransaction(vxid, sigmode, true);
3439 }
pid_t SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode, bool conflictPending)
Definition: procarray.c:3442

References SignalVirtualTransaction().

Referenced by ResolveRecoveryConflictWithVirtualXIDs().

◆ ComputeXidHorizons()

static void ComputeXidHorizons ( ComputeXidHorizonsResult h)
static

Definition at line 1701 of file procarray.c.

1702 {
1703  ProcArrayStruct *arrayP = procArray;
1704  TransactionId kaxmin;
1705  bool in_recovery = RecoveryInProgress();
1706  TransactionId *other_xids = ProcGlobal->xids;
1707 
1708  LWLockAcquire(ProcArrayLock, LW_SHARED);
1709 
1711 
1712  /*
1713  * We initialize the MIN() calculation with latestCompletedXid + 1. This
1714  * is a lower bound for the XIDs that might appear in the ProcArray later,
1715  * and so protects us against overestimating the result due to future
1716  * additions.
1717  */
1718  {
1719  TransactionId initial;
1720 
1722  Assert(TransactionIdIsValid(initial));
1723  TransactionIdAdvance(initial);
1724 
1725  h->oldest_considered_running = initial;
1726  h->shared_oldest_nonremovable = initial;
1727  h->catalog_oldest_nonremovable = initial;
1728  h->data_oldest_nonremovable = initial;
1729 
1730  /*
1731  * Only modifications made by this backend affect the horizon for
1732  * temporary relations. Instead of a check in each iteration of the
1733  * loop over all PGPROCs it is cheaper to just initialize to the
1734  * current top-level xid any.
1735  *
1736  * Without an assigned xid we could use a horizon as aggressive as
1737  * ReadNewTransactionid(), but we can get away with the much cheaper
1738  * latestCompletedXid + 1: If this backend has no xid there, by
1739  * definition, can't be any newer changes in the temp table than
1740  * latestCompletedXid.
1741  */
1744  else
1745  h->temp_oldest_nonremovable = initial;
1746  }
1747 
1748  /*
1749  * Fetch slot horizons while ProcArrayLock is held - the
1750  * LWLockAcquire/LWLockRelease are a barrier, ensuring this happens inside
1751  * the lock.
1752  */
1755 
1756  for (int index = 0; index < arrayP->numProcs; index++)
1757  {
1758  int pgprocno = arrayP->pgprocnos[index];
1759  PGPROC *proc = &allProcs[pgprocno];
1760  int8 statusFlags = ProcGlobal->statusFlags[index];
1761  TransactionId xid;
1762  TransactionId xmin;
1763 
1764  /* Fetch xid just once - see GetNewTransactionId */
1765  xid = UINT32_ACCESS_ONCE(other_xids[index]);
1766  xmin = UINT32_ACCESS_ONCE(proc->xmin);
1767 
1768  /*
1769  * Consider both the transaction's Xmin, and its Xid.
1770  *
1771  * We must check both because a transaction might have an Xmin but not
1772  * (yet) an Xid; conversely, if it has an Xid, that could determine
1773  * some not-yet-set Xmin.
1774  */
1775  xmin = TransactionIdOlder(xmin, xid);
1776 
1777  /* if neither is set, this proc doesn't influence the horizon */
1778  if (!TransactionIdIsValid(xmin))
1779  continue;
1780 
1781  /*
1782  * Don't ignore any procs when determining which transactions might be
1783  * considered running. While slots should ensure logical decoding
1784  * backends are protected even without this check, it can't hurt to
1785  * include them here as well..
1786  */
1789 
1790  /*
1791  * Skip over backends either vacuuming (which is ok with rows being
1792  * removed, as long as pg_subtrans is not truncated) or doing logical
1793  * decoding (which manages xmin separately, check below).
1794  */
1795  if (statusFlags & (PROC_IN_VACUUM | PROC_IN_LOGICAL_DECODING))
1796  continue;
1797 
1798  /* shared tables need to take backends in all databases into account */
1801 
1802  /*
1803  * Normally queries in other databases are ignored for anything but
1804  * the shared horizon. But in recovery we cannot compute an accurate
1805  * per-database horizon as all xids are managed via the
1806  * KnownAssignedXids machinery.
1807  *
1808  * Be careful to compute a pessimistic value when MyDatabaseId is not
1809  * set. If this is a backend in the process of starting up, we may not
1810  * use a "too aggressive" horizon (otherwise we could end up using it
1811  * to prune still needed data away). If the current backend never
1812  * connects to a database that is harmless, because
1813  * data_oldest_nonremovable will never be utilized.
1814  */
1815  if (in_recovery ||
1817  proc->databaseId == 0) /* always include WalSender */
1818  {
1819  /*
1820  * We can ignore this backend if it's running CREATE INDEX
1821  * CONCURRENTLY or REINDEX CONCURRENTLY on a "safe" index -- but
1822  * only on vacuums of user-defined tables.
1823  */
1824  if (!(statusFlags & PROC_IN_SAFE_IC))
1827 
1828  /* Catalog tables need to consider all backends in this db */
1831 
1832  }
1833  }
1834 
1835  /* catalog horizon should never be later than data */
1838 
1839  /*
1840  * If in recovery fetch oldest xid in KnownAssignedXids, will be applied
1841  * after lock is released.
1842  */
1843  if (in_recovery)
1844  kaxmin = KnownAssignedXidsGetOldestXmin();
1845 
1846  /*
1847  * No other information from shared state is needed, release the lock
1848  * immediately. The rest of the computations can be done without a lock.
1849  */
1850  LWLockRelease(ProcArrayLock);
1851 
1852  if (in_recovery)
1853  {
1862  /* temp relations cannot be accessed in recovery */
1863  }
1864  else
1865  {
1866  /*
1867  * Compute the cutoff XID by subtracting vacuum_defer_cleanup_age.
1868  *
1869  * vacuum_defer_cleanup_age provides some additional "slop" for the
1870  * benefit of hot standby queries on standby servers. This is quick
1871  * and dirty, and perhaps not all that useful unless the primary has a
1872  * predictable transaction rate, but it offers some protection when
1873  * there's no walsender connection. Note that we are assuming
1874  * vacuum_defer_cleanup_age isn't large enough to cause wraparound ---
1875  * so guc.c should limit it to no more than the xidStopLimit threshold
1876  * in varsup.c. Also note that we intentionally don't apply
1877  * vacuum_defer_cleanup_age on standby servers.
1878  */
1891  /* defer doesn't apply to temp relations */
1892  }
1893 
1894  /*
1895  * Check whether there are replication slots requiring an older xmin.
1896  */
1901 
1902  /*
1903  * The only difference between catalog / data horizons is that the slot's
1904  * catalog xmin is applied to the catalog one (so catalogs can be accessed
1905  * for logical decoding). Initialize with data horizon, and then back up
1906  * further if necessary. Have to back up the shared horizon as well, since
1907  * that also can contain catalogs.
1908  */
1912  h->slot_catalog_xmin);
1915  h->slot_xmin);
1918  h->slot_catalog_xmin);
1919 
1920  /*
1921  * It's possible that slots / vacuum_defer_cleanup_age backed up the
1922  * horizons further than oldest_considered_running. Fix.
1923  */
1933 
1934  /*
1935  * shared horizons have to be at least as old as the oldest visible in
1936  * current db
1937  */
1942 
1943  /*
1944  * Horizons need to ensure that pg_subtrans access is still possible for
1945  * the relevant backends.
1946  */
1957  h->slot_xmin));
1960  h->slot_catalog_xmin));
1961 
1962  /* update approximate horizons with the computed horizons */
1964 }
signed char int8
Definition: c.h:427
Oid MyDatabaseId
Definition: globals.c:88
Assert(fmt[strlen(fmt) - 1] !='\n')
#define PROC_IN_LOGICAL_DECODING
Definition: proc.h:58
#define PROC_IN_SAFE_IC
Definition: proc.h:56
#define PROC_IN_VACUUM
Definition: proc.h:55
#define UINT32_ACCESS_ONCE(var)
Definition: procarray.c:69
static void GlobalVisUpdateApply(ComputeXidHorizonsResult *horizons)
Definition: procarray.c:4101
static TransactionId KnownAssignedXidsGetOldestXmin(void)
Definition: procarray.c:5079
PGPROC * MyProc
Definition: proc.c:68
int vacuum_defer_cleanup_age
Definition: standby.c:39
TransactionId slot_catalog_xmin
Definition: procarray.c:194
TransactionId data_oldest_nonremovable
Definition: procarray.c:239
TransactionId temp_oldest_nonremovable
Definition: procarray.c:245
TransactionId shared_oldest_nonremovable
Definition: procarray.c:216
TransactionId oldest_considered_running
Definition: procarray.c:207
TransactionId slot_xmin
Definition: procarray.c:193
FullTransactionId latest_completed
Definition: procarray.c:187
TransactionId catalog_oldest_nonremovable
Definition: procarray.c:233
TransactionId shared_oldest_nonremovable_raw
Definition: procarray.c:227
TransactionId xmin
Definition: proc.h:141
TransactionId xid
Definition: proc.h:136
uint8 * statusFlags
Definition: proc.h:336
TransactionId replication_slot_xmin
Definition: procarray.c:96
TransactionId replication_slot_catalog_xmin
Definition: procarray.c:98
FullTransactionId latestCompletedXid
Definition: transam.h:238
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:319
static TransactionId TransactionIdRetreatedBy(TransactionId xid, uint32 amount)
Definition: transam.h:323
#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:335
VariableCache ShmemVariableCache
Definition: varsup.c:34
bool RecoveryInProgress(void)
Definition: xlog.c:8404

References allProcs, Assert(), ComputeXidHorizonsResult::catalog_oldest_nonremovable, ComputeXidHorizonsResult::data_oldest_nonremovable, PGPROC::databaseId, GlobalVisUpdateApply(), InvalidOid, KnownAssignedXidsGetOldestXmin(), ComputeXidHorizonsResult::latest_completed, VariableCacheData::latestCompletedXid, LW_SHARED, LWLockAcquire(), LWLockRelease(), MyDatabaseId, MyProc, ProcArrayStruct::numProcs, ComputeXidHorizonsResult::oldest_considered_running, ProcArrayStruct::pgprocnos, PROC_IN_LOGICAL_DECODING, PROC_IN_SAFE_IC, 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(), TransactionIdRetreatedBy(), UINT32_ACCESS_ONCE, vacuum_defer_cleanup_age, PGPROC::xid, XidFromFullTransactionId, PROC_HDR::xids, and PGPROC::xmin.

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

◆ CountDBBackends()

int CountDBBackends ( Oid  databaseid)

Definition at line 3544 of file procarray.c.

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

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

3575 {
3576  ProcArrayStruct *arrayP = procArray;
3577  int count = 0;
3578  int index;
3579 
3580  LWLockAcquire(ProcArrayLock, LW_SHARED);
3581 
3582  for (index = 0; index < arrayP->numProcs; index++)
3583  {
3584  int pgprocno = arrayP->pgprocnos[index];
3585  PGPROC *proc = &allProcs[pgprocno];
3586 
3587  if (proc->pid == 0)
3588  continue; /* do not count prepared xacts */
3589  if (proc->isBackgroundWorker)
3590  continue; /* do not count background workers */
3591  if (!OidIsValid(databaseid) ||
3592  proc->databaseId == databaseid)
3593  count++;
3594  }
3595 
3596  LWLockRelease(ProcArrayLock);
3597 
3598  return count;
3599 }
bool isBackgroundWorker
Definition: proc.h:163

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

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

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

3646 {
3647  ProcArrayStruct *arrayP = procArray;
3648  int count = 0;
3649  int index;
3650 
3651  LWLockAcquire(ProcArrayLock, LW_SHARED);
3652 
3653  for (index = 0; index < arrayP->numProcs; index++)
3654  {
3655  int pgprocno = arrayP->pgprocnos[index];
3656  PGPROC *proc = &allProcs[pgprocno];
3657 
3658  if (proc->pid == 0)
3659  continue; /* do not count prepared xacts */
3660  if (proc->isBackgroundWorker)
3661  continue; /* do not count background workers */
3662  if (proc->roleId == roleid)
3663  count++;
3664  }
3665 
3666  LWLockRelease(ProcArrayLock);
3667 
3668  return count;
3669 }
Oid roleId
Definition: proc.h:158

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

406 {
407  bool found;
408 
409  /* Create or attach to the ProcArray shared structure */
411  ShmemInitStruct("Proc Array",
412  add_size(offsetof(ProcArrayStruct, pgprocnos),
413  mul_size(sizeof(int),
415  &found);
416 
417  if (!found)
418  {
419  /*
420  * We're the first - initialize.
421  */
422  procArray->numProcs = 0;
433  }
434 
436 
437  /* Create or attach to the KnownAssignedXids arrays too, if needed */
438  if (EnableHotStandby)
439  {
441  ShmemInitStruct("KnownAssignedXids",
442  mul_size(sizeof(TransactionId),
444  &found);
445  KnownAssignedXidsValid = (bool *)
446  ShmemInitStruct("KnownAssignedXidsValid",
447  mul_size(sizeof(bool), TOTAL_MAX_CACHED_SUBXIDS),
448  &found);
449  }
450 }
#define offsetof(type, field)
Definition: c.h:727
#define TOTAL_MAX_CACHED_SUBXIDS
#define PROCARRAY_MAXPROCS
static TransactionId * KnownAssignedXids
Definition: procarray.c:268
static bool * KnownAssignedXidsValid
Definition: procarray.c:269
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:321
int maxKnownAssignedXids
Definition: procarray.c:80
slock_t known_assigned_xids_lck
Definition: procarray.c:84
int numKnownAssignedXids
Definition: procarray.c:81
TransactionId lastOverflowedXid
Definition: procarray.c:93
int tailKnownAssignedXids
Definition: procarray.c:82
int headKnownAssignedXids
Definition: procarray.c:83
uint64 xactCompletionCount
Definition: transam.h:248
bool EnableHotStandby
Definition: xlog.c:102

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, offsetof, 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 4463 of file procarray.c.

4464 {
4465  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4467 
4468  /*
4469  * Reset lastOverflowedXid. Currently, lastOverflowedXid has no use after
4470  * the call of this function. But do this for unification with what
4471  * ExpireOldKnownAssignedTransactionIds() do.
4472  */
4474  LWLockRelease(ProcArrayLock);
4475 }
static void KnownAssignedXidsRemovePreceding(TransactionId xid)
Definition: procarray.c:4929

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

Referenced by ShutdownRecoveryTransactionEnvironment().

◆ ExpireOldKnownAssignedTransactionIds()

void ExpireOldKnownAssignedTransactionIds ( TransactionId  xid)

Definition at line 4483 of file procarray.c.

4484 {
4485  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4486 
4487  /*
4488  * Reset lastOverflowedXid if we know all transactions that have been
4489  * possibly running are being gone. Not doing so could cause an incorrect
4490  * lastOverflowedXid value, which makes extra snapshots be marked as
4491  * suboverflowed.
4492  */
4496  LWLockRelease(ProcArrayLock);
4497 }
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300

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

4439 {
4441 
4442  /*
4443  * Uses same locking as transaction commit
4444  */
4445  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4446 
4447  KnownAssignedXidsRemoveTree(xid, nsubxids, subxids);
4448 
4449  /* As in ProcArrayEndTransaction, advance latestCompletedXid */
4451 
4452  /* ... and xactCompletionCount */
4454 
4455  LWLockRelease(ProcArrayLock);
4456 }
static void KnownAssignedXidsRemoveTree(TransactionId xid, int nsubxids, TransactionId *subxids)
Definition: procarray.c:4907
static void MaintainLatestCompletedXidRecovery(TransactionId latestXid)
Definition: procarray.c:969
HotStandbyState standbyState
Definition: xlogutils.c:55
@ 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 4286 of file procarray.c.

4287 {
4288  TransactionId rel_xid = XidFromFullTransactionId(rel);
4289 
4291  Assert(TransactionIdIsValid(rel_xid));
4292 
4293  /* not guaranteed to find issues, but likely to catch mistakes */
4295 
4297  + (int32) (xid - rel_xid));
4298 }
signed int int32
Definition: c.h:429
#define U64FromFullTransactionId(x)
Definition: transam.h:49
static FullTransactionId FullTransactionIdFromU64(uint64 value)
Definition: transam.h:81
#define AssertTransactionIdInAllowableRange(xid)
Definition: transam.h:302

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

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

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

3277 {
3278  VirtualTransactionId *vxids;
3279  ProcArrayStruct *arrayP = procArray;
3280  int count = 0;
3281  int index;
3282 
3283  /* allocate what's certainly enough result space */
3284  vxids = (VirtualTransactionId *)
3285  palloc(sizeof(VirtualTransactionId) * arrayP->maxProcs);
3286 
3287  LWLockAcquire(ProcArrayLock, LW_SHARED);
3288 
3289  for (index = 0; index < arrayP->numProcs; index++)
3290  {
3291  int pgprocno = arrayP->pgprocnos[index];
3292  PGPROC *proc = &allProcs[pgprocno];
3293  uint8 statusFlags = ProcGlobal->statusFlags[index];
3294 
3295  if (proc == MyProc)
3296  continue;
3297 
3298  if (excludeVacuum & statusFlags)
3299  continue;
3300 
3301  if (allDbs || proc->databaseId == MyDatabaseId)
3302  {
3303  /* Fetch xmin just once - might change on us */
3304  TransactionId pxmin = UINT32_ACCESS_ONCE(proc->xmin);
3305 
3306  if (excludeXmin0 && !TransactionIdIsValid(pxmin))
3307  continue;
3308 
3309  /*
3310  * InvalidTransactionId precedes all other XIDs, so a proc that
3311  * hasn't set xmin yet will not be rejected by this test.
3312  */
3313  if (!TransactionIdIsValid(limitXmin) ||
3314  TransactionIdPrecedesOrEquals(pxmin, limitXmin))
3315  {
3316  VirtualTransactionId vxid;
3317 
3318  GET_VXID_FROM_PGPROC(vxid, *proc);
3319  if (VirtualTransactionIdIsValid(vxid))
3320  vxids[count++] = vxid;
3321  }
3322  }
3323  }
3324 
3325  LWLockRelease(ProcArrayLock);
3326 
3327  *nvxids = count;
3328  return vxids;
3329 }
void * palloc(Size size)
Definition: mcxt.c:1062

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

2081 {
2082  return TOTAL_MAX_CACHED_SUBXIDS;
2083 }

References TOTAL_MAX_CACHED_SUBXIDS.

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

◆ GetMaxSnapshotXidCount()

int GetMaxSnapshotXidCount ( void  )

Definition at line 2069 of file procarray.c.

2070 {
2071  return procArray->maxProcs;
2072 }

References ProcArrayStruct::maxProcs, and procArray.

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

◆ GetOldestActiveTransactionId()

TransactionId GetOldestActiveTransactionId ( void  )

Definition at line 2895 of file procarray.c.

2896 {
2897  ProcArrayStruct *arrayP = procArray;
2898  TransactionId *other_xids = ProcGlobal->xids;
2899  TransactionId oldestRunningXid;
2900  int index;
2901 
2903 
2904  /*
2905  * Read nextXid, as the upper bound of what's still active.
2906  *
2907  * Reading a TransactionId is atomic, but we must grab the lock to make
2908  * sure that all XIDs < nextXid are already present in the proc array (or
2909  * have already completed), when we spin over it.
2910  */
2911  LWLockAcquire(XidGenLock, LW_SHARED);
2913  LWLockRelease(XidGenLock);
2914 
2915  /*
2916  * Spin over procArray collecting all xids and subxids.
2917  */
2918  LWLockAcquire(ProcArrayLock, LW_SHARED);
2919  for (index = 0; index < arrayP->numProcs; index++)
2920  {
2921  TransactionId xid;
2922 
2923  /* Fetch xid just once - see GetNewTransactionId */
2924  xid = UINT32_ACCESS_ONCE(other_xids[index]);
2925 
2926  if (!TransactionIdIsNormal(xid))
2927  continue;
2928 
2929  if (TransactionIdPrecedes(xid, oldestRunningXid))
2930  oldestRunningXid = xid;
2931 
2932  /*
2933  * Top-level XID of a transaction is always less than any of its
2934  * subxids, so we don't need to check if any of the subxids are
2935  * smaller than oldestRunningXid
2936  */
2937  }
2938  LWLockRelease(ProcArrayLock);
2939 
2940  return oldestRunningXid;
2941 }
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 2005 of file procarray.c.

2006 {
2007  ComputeXidHorizonsResult horizons;
2008 
2009  ComputeXidHorizons(&horizons);
2010 
2011  switch (GlobalVisHorizonKindForRel(rel))
2012  {
2013  case VISHORIZON_SHARED:
2014  return horizons.shared_oldest_nonremovable;
2015  case VISHORIZON_CATALOG:
2016  return horizons.catalog_oldest_nonremovable;
2017  case VISHORIZON_DATA:
2018  return horizons.data_oldest_nonremovable;
2019  case VISHORIZON_TEMP:
2020  return horizons.temp_oldest_nonremovable;
2021  }
2022 
2023  /* just to prevent compiler warnings */
2024  return InvalidTransactionId;
2025 }
static void ComputeXidHorizons(ComputeXidHorizonsResult *h)
Definition: procarray.c:1701
static GlobalVisHorizonKind GlobalVisHorizonKindForRel(Relation rel)
Definition: procarray.c:1971

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_set_xid_limits().

◆ GetOldestSafeDecodingTransactionId()

TransactionId GetOldestSafeDecodingTransactionId ( bool  catalogOnly)

Definition at line 2960 of file procarray.c.

2961 {
2962  ProcArrayStruct *arrayP = procArray;
2963  TransactionId oldestSafeXid;
2964  int index;
2965  bool recovery_in_progress = RecoveryInProgress();
2966 
2967  Assert(LWLockHeldByMe(ProcArrayLock));
2968 
2969  /*
2970  * Acquire XidGenLock, so no transactions can acquire an xid while we're
2971  * running. If no transaction with xid were running concurrently a new xid
2972  * could influence the RecentXmin et al.
2973  *
2974  * We initialize the computation to nextXid since that's guaranteed to be
2975  * a safe, albeit pessimal, value.
2976  */
2977  LWLockAcquire(XidGenLock, LW_SHARED);
2979 
2980  /*
2981  * If there's already a slot pegging the xmin horizon, we can start with
2982  * that value, it's guaranteed to be safe since it's computed by this
2983  * routine initially and has been enforced since. We can always use the
2984  * slot's general xmin horizon, but the catalog horizon is only usable
2985  * when only catalog data is going to be looked at.
2986  */
2989  oldestSafeXid))
2990  oldestSafeXid = procArray->replication_slot_xmin;
2991 
2992  if (catalogOnly &&
2995  oldestSafeXid))
2996  oldestSafeXid = procArray->replication_slot_catalog_xmin;
2997 
2998  /*
2999  * If we're not in recovery, we walk over the procarray and collect the
3000  * lowest xid. Since we're called with ProcArrayLock held and have
3001  * acquired XidGenLock, no entries can vanish concurrently, since
3002  * ProcGlobal->xids[i] is only set with XidGenLock held and only cleared
3003  * with ProcArrayLock held.
3004  *
3005  * In recovery we can't lower the safe value besides what we've computed
3006  * above, so we'll have to wait a bit longer there. We unfortunately can
3007  * *not* use KnownAssignedXidsGetOldestXmin() since the KnownAssignedXids
3008  * machinery can miss values and return an older value than is safe.
3009  */
3010  if (!recovery_in_progress)
3011  {
3012  TransactionId *other_xids = ProcGlobal->xids;
3013 
3014  /*
3015  * Spin over procArray collecting min(ProcGlobal->xids[i])
3016  */
3017  for (index = 0; index < arrayP->numProcs; index++)
3018  {
3019  TransactionId xid;
3020 
3021  /* Fetch xid just once - see GetNewTransactionId */
3022  xid = UINT32_ACCESS_ONCE(other_xids[index]);
3023 
3024  if (!TransactionIdIsNormal(xid))
3025  continue;
3026 
3027  if (TransactionIdPrecedes(xid, oldestSafeXid))
3028  oldestSafeXid = xid;
3029  }
3030  }
3031 
3032  LWLockRelease(XidGenLock);
3033 
3034  return oldestSafeXid;
3035 }
bool LWLockHeldByMe(LWLock *l)
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 2034 of file procarray.c.

2035 {
2036  ComputeXidHorizonsResult horizons;
2037 
2038  ComputeXidHorizons(&horizons);
2039 
2040  return horizons.oldest_considered_running;
2041 }

References ComputeXidHorizons(), and ComputeXidHorizonsResult::oldest_considered_running.

Referenced by CreateCheckPoint(), and CreateRestartPoint().

◆ GetReplicationHorizons()

void GetReplicationHorizons ( TransactionId xmin,
TransactionId catalog_xmin 
)

Definition at line 2047 of file procarray.c.

2048 {
2049  ComputeXidHorizonsResult horizons;
2050 
2051  ComputeXidHorizons(&horizons);
2052 
2053  /*
2054  * Don't want to use shared_oldest_nonremovable here, as that contains the
2055  * effect of replication slot's catalog_xmin. We want to send a separate
2056  * feedback for the catalog horizon, so the primary can remove data table
2057  * contents more aggressively.
2058  */
2059  *xmin = horizons.shared_oldest_nonremovable_raw;
2060  *catalog_xmin = horizons.slot_catalog_xmin;
2061 }

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

Referenced by XLogWalRcvSendHSFeedback().

◆ GetRunningTransactionData()

RunningTransactions GetRunningTransactionData ( void  )

Definition at line 2720 of file procarray.c.

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

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

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

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(), TransactionIdRetreatedBy(), TransactionXmin, UINT32_ACCESS_ONCE, vacuum_defer_cleanup_age, 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 2089 of file procarray.c.

2090 {
2092  {
2093  /*
2094  * If not using "snapshot too old" feature, fill related fields with
2095  * dummy values that don't require any locking.
2096  */
2097  snapshot->lsn = InvalidXLogRecPtr;
2098  snapshot->whenTaken = 0;
2099  }
2100  else
2101  {
2102  /*
2103  * Capture the current time and WAL stream location in case this
2104  * snapshot becomes old enough to need to fall back on the special
2105  * "old snapshot" logic.
2106  */
2107  snapshot->lsn = GetXLogInsertRecPtr();
2108  snapshot->whenTaken = GetSnapshotCurrentTimestamp();
2109  MaintainOldSnapshotTimeMapping(snapshot->whenTaken, snapshot->xmin);
2110  }
2111 }
void MaintainOldSnapshotTimeMapping(TimestampTz whenTaken, TransactionId xmin)
Definition: snapmgr.c:1873
TimestampTz GetSnapshotCurrentTimestamp(void)
Definition: snapmgr.c:1650
static bool OldSnapshotThresholdActive(void)
Definition: snapmgr.h:101
TimestampTz whenTaken
Definition: snapshot.h:208
XLogRecPtr lsn
Definition: snapshot.h:209
XLogRecPtr GetXLogInsertRecPtr(void)
Definition: xlog.c:11985
#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 2123 of file procarray.c.

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

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)

Definition at line 3056 of file procarray.c.

3057 {
3058  VirtualTransactionId *vxids;
3059  ProcArrayStruct *arrayP = procArray;
3060  int count = 0;
3061  int index;
3062 
3063  /* allocate what's certainly enough result space */
3064  vxids = (VirtualTransactionId *)
3065  palloc(sizeof(VirtualTransactionId) * arrayP->maxProcs);
3066 
3067  LWLockAcquire(ProcArrayLock, LW_SHARED);
3068 
3069  for (index = 0; index < arrayP->numProcs; index++)
3070  {
3071  int pgprocno = arrayP->pgprocnos[index];
3072  PGPROC *proc = &allProcs[pgprocno];
3073 
3074  if (proc->delayChkpt)
3075  {
3076  VirtualTransactionId vxid;
3077 
3078  GET_VXID_FROM_PGPROC(vxid, *proc);
3079  if (VirtualTransactionIdIsValid(vxid))
3080  vxids[count++] = vxid;
3081  }
3082  }
3083 
3084  LWLockRelease(ProcArrayLock);
3085 
3086  *nvxids = count;
3087  return vxids;
3088 }
bool delayChkpt
Definition: proc.h:190

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

Referenced by CreateCheckPoint().

◆ GlobalVisCheckRemovableFullXid()

bool GlobalVisCheckRemovableFullXid ( Relation  rel,
FullTransactionId  fxid 
)

Definition at line 4251 of file procarray.c.

4252 {
4254 
4255  state = GlobalVisTestFor(rel);
4256 
4257  return GlobalVisTestIsRemovableFullXid(state, fxid);
4258 }
bool GlobalVisTestIsRemovableFullXid(GlobalVisState *state, FullTransactionId fxid)
Definition: procarray.c:4157
GlobalVisState * GlobalVisTestFor(Relation rel)
Definition: procarray.c:4042
Definition: regguts.h:318

References GlobalVisTestFor(), and GlobalVisTestIsRemovableFullXid().

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

◆ GlobalVisCheckRemovableXid()

bool GlobalVisCheckRemovableXid ( Relation  rel,
TransactionId  xid 
)

Definition at line 4265 of file procarray.c.

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

References GlobalVisTestFor(), and GlobalVisTestIsRemovableXid().

Referenced by GinPageIsRecyclable().

◆ GlobalVisHorizonKindForRel()

static GlobalVisHorizonKind GlobalVisHorizonKindForRel ( Relation  rel)
inlinestatic

Definition at line 1971 of file procarray.c.

1972 {
1973  /*
1974  * Other relkkinds currently don't contain xids, nor always the necessary
1975  * logical decoding markers.
1976  */
1977  Assert(!rel ||
1978  rel->rd_rel->relkind == RELKIND_RELATION ||
1979  rel->rd_rel->relkind == RELKIND_MATVIEW ||
1980  rel->rd_rel->relkind == RELKIND_TOASTVALUE);
1981 
1982  if (rel == NULL || rel->rd_rel->relisshared || RecoveryInProgress())
1983  return VISHORIZON_SHARED;
1984  else if (IsCatalogRelation(rel) ||
1986  return VISHORIZON_CATALOG;
1987  else if (!RELATION_IS_LOCAL(rel))
1988  return VISHORIZON_DATA;
1989  else
1990  return VISHORIZON_TEMP;
1991 }
bool IsCatalogRelation(Relation relation)
Definition: catalog.c:104
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:622
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:658
Form_pg_class rd_rel
Definition: rel.h:109

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

4043 {
4044  GlobalVisState *state = NULL;
4045 
4046  /* XXX: we should assert that a snapshot is pushed or registered */
4047  Assert(RecentXmin);
4048 
4049  switch (GlobalVisHorizonKindForRel(rel))
4050  {
4051  case VISHORIZON_SHARED:
4053  break;
4054  case VISHORIZON_CATALOG:
4056  break;
4057  case VISHORIZON_DATA:
4059  break;
4060  case VISHORIZON_TEMP:
4062  break;
4063  }
4064 
4065  Assert(FullTransactionIdIsValid(state->definitely_needed) &&
4066  FullTransactionIdIsValid(state->maybe_needed));
4067 
4068  return state;
4069 }
#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(), lazy_scan_heap(), and vacuumRedirectAndPlaceholder().

◆ GlobalVisTestIsRemovableFullXid()

bool GlobalVisTestIsRemovableFullXid ( GlobalVisState state,
FullTransactionId  fxid 
)

Definition at line 4157 of file procarray.c.

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

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

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

4227 {
4228  /* acquire accurate horizon if not already done */
4230  GlobalVisUpdate();
4231 
4232  return state->maybe_needed;
4233 }

References GlobalVisTestShouldUpdate(), and GlobalVisUpdate().

Referenced by GlobalVisTestNonRemovableHorizon().

◆ GlobalVisTestNonRemovableHorizon()

TransactionId GlobalVisTestNonRemovableHorizon ( GlobalVisState state)

Definition at line 4237 of file procarray.c.

4238 {
4239  FullTransactionId cutoff;
4240 
4242 
4243  return XidFromFullTransactionId(cutoff);
4244 }
FullTransactionId GlobalVisTestNonRemovableFullHorizon(GlobalVisState *state)
Definition: procarray.c:4226

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

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

References ComputeXidHorizonsResultLastXmin, FullTransactionIdFollowsOrEquals, RecentXmin, and TransactionIdIsValid.

Referenced by GlobalVisTestIsRemovableFullXid(), and GlobalVisTestNonRemovableFullHorizon().

◆ GlobalVisUpdate()

static void GlobalVisUpdate ( void  )
static

Definition at line 4140 of file procarray.c.

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

References ComputeXidHorizons().

Referenced by GlobalVisTestIsRemovableFullXid(), and GlobalVisTestNonRemovableFullHorizon().

◆ GlobalVisUpdateApply()

static void GlobalVisUpdateApply ( ComputeXidHorizonsResult horizons)
static

Definition at line 4101 of file procarray.c.

4102 {
4105  horizons->shared_oldest_nonremovable);
4108  horizons->catalog_oldest_nonremovable);
4111  horizons->data_oldest_nonremovable);
4114  horizons->temp_oldest_nonremovable);
4115 
4116  /*
4117  * In longer running transactions it's possible that transactions we
4118  * previously needed to treat as running aren't around anymore. So update
4119  * definitely_needed to not be earlier than maybe_needed.
4120  */
4131 
4133 }

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 
)

Definition at line 3100 of file procarray.c.

3101 {
3102  bool result = false;
3103  ProcArrayStruct *arrayP = procArray;
3104  int index;
3105 
3106  LWLockAcquire(ProcArrayLock, LW_SHARED);
3107 
3108  for (index = 0; index < arrayP->numProcs; index++)
3109  {
3110  int pgprocno = arrayP->pgprocnos[index];
3111  PGPROC *proc = &allProcs[pgprocno];
3112  VirtualTransactionId vxid;
3113 
3114  GET_VXID_FROM_PGPROC(vxid, *proc);
3115 
3116  if (proc->delayChkpt && VirtualTransactionIdIsValid(vxid))
3117  {
3118  int i;
3119 
3120  for (i = 0; i < nvxids; i++)
3121  {
3122  if (VirtualTransactionIdEquals(vxid, vxids[i]))
3123  {
3124  result = true;
3125  break;
3126  }
3127  }
3128  if (result)
3129  break;
3130  }
3131  }
3132 
3133  LWLockRelease(ProcArrayLock);
3134 
3135  return result;
3136 }
int i
Definition: isn.c:73
#define VirtualTransactionIdEquals(vxid1, vxid2)
Definition: lock.h:76

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

Referenced by CreateCheckPoint().

◆ IsBackendPid()

bool IsBackendPid ( int  pid)

Definition at line 3241 of file procarray.c.

3242 {
3243  return (BackendPidGetProc(pid) != NULL);
3244 }
PGPROC * BackendPidGetProc(int pid)
Definition: procarray.c:3146

References BackendPidGetProc().

Referenced by pg_stat_get_subscription().

◆ KnownAssignedXidExists()

static bool KnownAssignedXidExists ( TransactionId  xid)
static

Definition at line 4868 of file procarray.c.

4869 {
4871 
4872  return KnownAssignedXidsSearch(xid, false);
4873 }
static bool KnownAssignedXidsSearch(TransactionId xid, bool remove)
Definition: procarray.c:4775

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

4659 {
4660  ProcArrayStruct *pArray = procArray;
4661  TransactionId next_xid;
4662  int head,
4663  tail;
4664  int nxids;
4665  int i;
4666 
4667  Assert(TransactionIdPrecedesOrEquals(from_xid, to_xid));
4668 
4669  /*
4670  * Calculate how many array slots we'll need. Normally this is cheap; in
4671  * the unusual case where the XIDs cross the wrap point, we do it the hard
4672  * way.
4673  */
4674  if (to_xid >= from_xid)
4675  nxids = to_xid - from_xid + 1;
4676  else
4677  {
4678  nxids = 1;
4679  next_xid = from_xid;
4680  while (TransactionIdPrecedes(next_xid, to_xid))
4681  {
4682  nxids++;
4683  TransactionIdAdvance(next_xid);
4684  }
4685  }
4686 
4687  /*
4688  * Since only the startup process modifies the head/tail pointers, we
4689  * don't need a lock to read them here.
4690  */
4691  head = pArray->headKnownAssignedXids;
4692  tail = pArray->tailKnownAssignedXids;
4693 
4694  Assert(head >= 0 && head <= pArray->maxKnownAssignedXids);
4695  Assert(tail >= 0 && tail < pArray->maxKnownAssignedXids);
4696 
4697  /*
4698  * Verify that insertions occur in TransactionId sequence. Note that even
4699  * if the last existing element is marked invalid, it must still have a
4700  * correctly sequenced XID value.
4701  */
4702  if (head > tail &&
4703  TransactionIdFollowsOrEquals(KnownAssignedXids[head - 1], from_xid))
4704  {
4706  elog(ERROR, "out-of-order XID insertion in KnownAssignedXids");
4707  }
4708 
4709  /*
4710  * If our xids won't fit in the remaining space, compress out free space
4711  */
4712  if (head + nxids > pArray->maxKnownAssignedXids)
4713  {
4714  /* must hold lock to compress */
4715  if (!exclusive_lock)
4716  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4717 
4719 
4720  head = pArray->headKnownAssignedXids;
4721  /* note: we no longer care about the tail pointer */
4722 
4723  if (!exclusive_lock)
4724  LWLockRelease(ProcArrayLock);
4725 
4726  /*
4727  * If it still won't fit then we're out of memory
4728  */
4729  if (head + nxids > pArray->maxKnownAssignedXids)
4730  elog(ERROR, "too many KnownAssignedXids");
4731  }
4732 
4733  /* Now we can insert the xids into the space starting at head */
4734  next_xid = from_xid;
4735  for (i = 0; i < nxids; i++)
4736  {
4737  KnownAssignedXids[head] = next_xid;
4738  KnownAssignedXidsValid[head] = true;
4739  TransactionIdAdvance(next_xid);
4740  head++;
4741  }
4742 
4743  /* Adjust count of number of valid entries */
4744  pArray->numKnownAssignedXids += nxids;
4745 
4746  /*
4747  * Now update the head pointer. We use a spinlock to protect this
4748  * pointer, not because the update is likely to be non-atomic, but to
4749  * ensure that other processors see the above array updates before they
4750  * see the head pointer change.
4751  *
4752  * If we're holding ProcArrayLock exclusively, there's no need to take the
4753  * spinlock.
4754  */
4755  if (exclusive_lock)
4756  pArray->headKnownAssignedXids = head;
4757  else
4758  {
4760  pArray->headKnownAssignedXids = head;
4762  }
4763 }
#define LOG
Definition: elog.h:25
#define elog(elevel,...)
Definition: elog.h:218
static void KnownAssignedXidsCompress(bool force)
Definition: procarray.c:4595
static void KnownAssignedXidsDisplay(int trace_level)
Definition: procarray.c:5114
#define SpinLockRelease(lock)
Definition: spin.h:64
#define SpinLockAcquire(lock)
Definition: spin.h:62
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:349

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

Referenced by ProcArrayApplyRecoveryInfo(), and RecordKnownAssignedTransactionIds().

◆ KnownAssignedXidsCompress()

static void KnownAssignedXidsCompress ( bool  force)
static

Definition at line 4595 of file procarray.c.

4596 {
4597  ProcArrayStruct *pArray = procArray;
4598  int head,
4599  tail;
4600  int compress_index;
4601  int i;
4602 
4603  /* no spinlock required since we hold ProcArrayLock exclusively */
4604  head = pArray->headKnownAssignedXids;
4605  tail = pArray->tailKnownAssignedXids;
4606 
4607  if (!force)
4608  {
4609  /*
4610  * If we can choose how much to compress, use a heuristic to avoid
4611  * compressing too often or not often enough.
4612  *
4613  * Heuristic is if we have a large enough current spread and less than
4614  * 50% of the elements are currently in use, then compress. This
4615  * should ensure we compress fairly infrequently. We could compress
4616  * less often though the virtual array would spread out more and
4617  * snapshots would become more expensive.
4618  */
4619  int nelements = head - tail;
4620 
4621  if (nelements < 4 * PROCARRAY_MAXPROCS ||
4622  nelements < 2 * pArray->numKnownAssignedXids)
4623  return;
4624  }
4625 
4626  /*
4627  * We compress the array by reading the valid values from tail to head,
4628  * re-aligning data to 0th element.
4629  */
4630  compress_index = 0;
4631  for (i = tail; i < head; i++)
4632  {
4634  {
4635  KnownAssignedXids[compress_index] = KnownAssignedXids[i];
4636  KnownAssignedXidsValid[compress_index] = true;
4637  compress_index++;
4638  }
4639  }
4640 
4641  pArray->tailKnownAssignedXids = 0;
4642  pArray->headKnownAssignedXids = compress_index;
4643 }

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

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

◆ KnownAssignedXidsDisplay()

static void KnownAssignedXidsDisplay ( int  trace_level)
static

Definition at line 5114 of file procarray.c.

5115 {
5116  ProcArrayStruct *pArray = procArray;
5118  int head,
5119  tail,
5120  i;
5121  int nxids = 0;
5122 
5123  tail = pArray->tailKnownAssignedXids;
5124  head = pArray->headKnownAssignedXids;
5125 
5126  initStringInfo(&buf);
5127 
5128  for (i = tail; i < head; i++)
5129  {
5131  {
5132  nxids++;
5133  appendStringInfo(&buf, "[%d]=%u ", i, KnownAssignedXids[i]);
5134  }
5135  }
5136 
5137  elog(trace_level, "%d KnownAssignedXids (num=%d tail=%d head=%d) %s",
5138  nxids,
5139  pArray->numKnownAssignedXids,
5140  pArray->tailKnownAssignedXids,
5141  pArray->headKnownAssignedXids,
5142  buf.data);
5143 
5144  pfree(buf.data);
5145 }
void pfree(void *pointer)
Definition: mcxt.c:1169
static char * buf
Definition: pg_test_fsync.c:70
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 5007 of file procarray.c.

5008 {
5010 
5011  return KnownAssignedXidsGetAndSetXmin(xarray, &xtmp, xmax);
5012 }

References InvalidTransactionId, and KnownAssignedXidsGetAndSetXmin().

Referenced by TransactionIdIsInProgress().

◆ KnownAssignedXidsGetAndSetXmin()

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

Definition at line 5021 of file procarray.c.

5023 {
5024  int count = 0;
5025  int head,
5026  tail;
5027  int i;
5028 
5029  /*
5030  * Fetch head just once, since it may change while we loop. We can stop
5031  * once we reach the initially seen head, since we are certain that an xid
5032  * cannot enter and then leave the array while we hold ProcArrayLock. We
5033  * might miss newly-added xids, but they should be >= xmax so irrelevant
5034  * anyway.
5035  *
5036  * Must take spinlock to ensure we see up-to-date array contents.
5037  */
5042 
5043  for (i = tail; i < head; i++)
5044  {
5045  /* Skip any gaps in the array */
5047  {
5048  TransactionId knownXid = KnownAssignedXids[i];
5049 
5050  /*
5051  * Update xmin if required. Only the first XID need be checked,
5052  * since the array is sorted.
5053  */
5054  if (count == 0 &&
5055  TransactionIdPrecedes(knownXid, *xmin))
5056  *xmin = knownXid;
5057 
5058  /*
5059  * Filter out anything >= xmax, again relying on sorted property
5060  * of array.
5061  */
5062  if (TransactionIdIsValid(xmax) &&
5063  TransactionIdFollowsOrEquals(knownXid, xmax))
5064  break;
5065 
5066  /* Add knownXid into output array */
5067  xarray[count++] = knownXid;
5068  }
5069  }
5070 
5071  return count;
5072 }

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

5080 {
5081  int head,
5082  tail;
5083  int i;
5084 
5085  /*
5086  * Fetch head just once, since it may change while we loop.
5087  */
5092 
5093  for (i = tail; i < head; i++)
5094  {
5095  /* Skip any gaps in the array */
5097  return KnownAssignedXids[i];
5098  }
5099 
5100  return InvalidTransactionId;
5101 }

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

4882 {
4884 
4885  elog(trace_recovery(DEBUG4), "remove KnownAssignedXid %u", xid);
4886 
4887  /*
4888  * Note: we cannot consider it an error to remove an XID that's not
4889  * present. We intentionally remove subxact IDs while processing
4890  * XLOG_XACT_ASSIGNMENT, to avoid array overflow. Then those XIDs will be
4891  * removed again when the top-level xact commits or aborts.
4892  *
4893  * It might be possible to track such XIDs to distinguish this case from
4894  * actual errors, but it would be complicated and probably not worth it.
4895  * So, just ignore the search result.
4896  */
4897  (void) KnownAssignedXidsSearch(xid, true);
4898 }
int trace_recovery(int trace_level)
Definition: elog.c:3425
#define DEBUG4
Definition: elog.h:21

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

Referenced by KnownAssignedXidsRemoveTree().

◆ KnownAssignedXidsRemovePreceding()

static void KnownAssignedXidsRemovePreceding ( TransactionId  xid)
static

Definition at line 4929 of file procarray.c.

4930 {
4931  ProcArrayStruct *pArray = procArray;
4932  int count = 0;
4933  int head,
4934  tail,
4935  i;
4936 
4937  if (!TransactionIdIsValid(removeXid))
4938  {
4939  elog(trace_recovery(DEBUG4), "removing all KnownAssignedXids");
4940  pArray->numKnownAssignedXids = 0;
4941  pArray->headKnownAssignedXids = pArray->tailKnownAssignedXids = 0;
4942  return;
4943  }
4944 
4945  elog(trace_recovery(DEBUG4), "prune KnownAssignedXids to %u", removeXid);
4946 
4947  /*
4948  * Mark entries invalid starting at the tail. Since array is sorted, we
4949  * can stop as soon as we reach an entry >= removeXid.
4950  */
4951  tail = pArray->tailKnownAssignedXids;
4952  head = pArray->headKnownAssignedXids;
4953 
4954  for (i = tail; i < head; i++)
4955  {
4957  {
4958  TransactionId knownXid = KnownAssignedXids[i];
4959 
4960  if (TransactionIdFollowsOrEquals(knownXid, removeXid))
4961  break;
4962 
4963  if (!StandbyTransactionIdIsPrepared(knownXid))
4964  {
4965  KnownAssignedXidsValid[i] = false;
4966  count++;
4967  }
4968  }
4969  }
4970 
4971  pArray->numKnownAssignedXids -= count;
4972  Assert(pArray->numKnownAssignedXids >= 0);
4973 
4974  /*
4975  * Advance the tail pointer if we've marked the tail item invalid.
4976  */
4977  for (i = tail; i < head; i++)
4978  {
4980  break;
4981  }
4982  if (i >= head)
4983  {
4984  /* Array is empty, so we can reset both pointers */
4985  pArray->headKnownAssignedXids = 0;
4986  pArray->tailKnownAssignedXids = 0;
4987  }
4988  else
4989  {
4990  pArray->tailKnownAssignedXids = i;
4991  }
4992 
4993  /* Opportunistically compress the array */
4995 }
bool StandbyTransactionIdIsPrepared(TransactionId xid)
Definition: twophase.c:1433

References Assert(), DEBUG4, elog, ProcArrayStruct::headKnownAssignedXids, i, 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 4907 of file procarray.c.

4909 {
4910  int i;
4911 
4912  if (TransactionIdIsValid(xid))
4914 
4915  for (i = 0; i < nsubxids; i++)
4916  KnownAssignedXidsRemove(subxids[i]);
4917 
4918  /* Opportunistically compress the array */
4920 }
static void KnownAssignedXidsRemove(TransactionId xid)
Definition: procarray.c:4881

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

Referenced by ExpireTreeKnownAssignedTransactionIds(), and ProcArrayApplyXidAssignment().

◆ KnownAssignedXidsReset()

static void KnownAssignedXidsReset ( void  )
static

Definition at line 5152 of file procarray.c.

5153 {
5154  ProcArrayStruct *pArray = procArray;
5155 
5156  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
5157 
5158  pArray->numKnownAssignedXids = 0;
5159  pArray->tailKnownAssignedXids = 0;
5160  pArray->headKnownAssignedXids = 0;
5161 
5162  LWLockRelease(ProcArrayLock);
5163 }

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

4776 {
4777  ProcArrayStruct *pArray = procArray;
4778  int first,
4779  last;
4780  int head;
4781  int tail;
4782  int result_index = -1;
4783 
4784  if (remove)
4785  {
4786  /* we hold ProcArrayLock exclusively, so no need for spinlock */
4787  tail = pArray->tailKnownAssignedXids;
4788  head = pArray->headKnownAssignedXids;
4789  }
4790  else
4791  {
4792  /* take spinlock to ensure we see up-to-date array contents */
4794  tail = pArray->tailKnownAssignedXids;
4795  head = pArray->headKnownAssignedXids;
4797  }
4798 
4799  /*
4800  * Standard binary search. Note we can ignore the KnownAssignedXidsValid
4801  * array here, since even invalid entries will contain sorted XIDs.
4802  */
4803  first = tail;
4804  last = head - 1;
4805  while (first <= last)
4806  {
4807  int mid_index;
4808  TransactionId mid_xid;
4809 
4810  mid_index = (first + last) / 2;
4811  mid_xid = KnownAssignedXids[mid_index];
4812 
4813  if (xid == mid_xid)
4814  {
4815  result_index = mid_index;
4816  break;
4817  }
4818  else if (TransactionIdPrecedes(xid, mid_xid))
4819  last = mid_index - 1;
4820  else
4821  first = mid_index + 1;
4822  }
4823 
4824  if (result_index < 0)
4825  return false; /* not in array */
4826 
4827  if (!KnownAssignedXidsValid[result_index])
4828  return false; /* in array, but invalid */
4829 
4830  if (remove)
4831  {
4832  KnownAssignedXidsValid[result_index] = false;
4833 
4834  pArray->numKnownAssignedXids--;
4835  Assert(pArray->numKnownAssignedXids >= 0);
4836 
4837  /*
4838  * If we're removing the tail element then advance tail pointer over
4839  * any invalid elements. This will speed future searches.
4840  */
4841  if (result_index == tail)
4842  {
4843  tail++;
4844  while (tail < head && !KnownAssignedXidsValid[tail])
4845  tail++;
4846  if (tail >= head)
4847  {
4848  /* Array is empty, so we can reset both pointers */
4849  pArray->headKnownAssignedXids = 0;
4850  pArray->tailKnownAssignedXids = 0;
4851  }
4852  else
4853  {
4854  pArray->tailKnownAssignedXids = tail;
4855  }
4856  }
4857  }
4858 
4859  return true;
4860 }

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

970 {
972  FullTransactionId rel;
973 
975  Assert(LWLockHeldByMe(ProcArrayLock));
976 
977  /*
978  * Need a FullTransactionId to compare latestXid with. Can't rely on
979  * latestCompletedXid to be initialized in recovery. But in recovery it's
980  * safe to access nextXid without a lock for the startup process.
981  */
984 
985  if (!FullTransactionIdIsValid(cur_latest) ||
986  TransactionIdPrecedes(XidFromFullTransactionId(cur_latest), latestXid))
987  {
989  FullXidRelativeTo(rel, latestXid);
990  }
991 
993 }
bool IsUnderPostmaster
Definition: globals.c:112
#define AmStartupProcess()
Definition: miscadmin.h:444

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

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

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

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

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

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

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

◆ ProcArrayApplyXidAssignment()

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

Definition at line 1275 of file procarray.c.

1277 {
1278  TransactionId max_xid;
1279  int i;
1280 
1282 
1283  max_xid = TransactionIdLatest(topxid, nsubxids, subxids);
1284 
1285  /*
1286  * Mark all the subtransactions as observed.
1287  *
1288  * NOTE: This will fail if the subxid contains too many previously
1289  * unobserved xids to fit into known-assigned-xids. That shouldn't happen
1290  * as the code stands, because xid-assignment records should never contain
1291  * more than PGPROC_MAX_CACHED_SUBXIDS entries.
1292  */
1294 
1295  /*
1296  * Notice that we update pg_subtrans with the top-level xid, rather than
1297  * the parent xid. This is a difference between normal processing and
1298  * recovery, yet is still correct in all cases. The reason is that
1299  * subtransaction commit is not marked in clog until commit processing, so
1300  * all aborted subtransactions have already been clearly marked in clog.
1301  * As a result we are able to refer directly to the top-level
1302  * transaction's state rather than skipping through all the intermediate
1303  * states in the subtransaction tree. This should be the first time we
1304  * have attempted to SubTransSetParent().
1305  */
1306  for (i = 0; i < nsubxids; i++)
1307  SubTransSetParent(subxids[i], topxid);
1308 
1309  /* KnownAssignedXids isn't maintained yet, so we're done for now */
1311  return;
1312 
1313  /*
1314  * Uses same locking as transaction commit
1315  */
1316  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
1317 
1318  /*
1319  * Remove subxids from known-assigned-xacts.
1320  */
1322 
1323  /*
1324  * Advance lastOverflowedXid to be at least the last of these subxids.
1325  */
1327  procArray->lastOverflowedXid = max_xid;
1328 
1329  LWLockRelease(ProcArrayLock);
1330 }
void RecordKnownAssignedTransactionIds(TransactionId xid)
Definition: procarray.c:4368
void SubTransSetParent(TransactionId xid, TransactionId parent)
Definition: subtrans.c:74
TransactionId TransactionIdLatest(TransactionId mainxid, int nxids, const TransactionId *xids)
Definition: transam.c:365

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

888 {
889  int pgxactoff;
890 
891  /*
892  * Currently we need to lock ProcArrayLock exclusively here, as we
893  * increment xactCompletionCount below. We also need it at least in shared
894  * mode for pgproc->pgxactoff to stay the same below.
895  *
896  * We could however, as this action does not actually change anyone's view
897  * of the set of running XIDs (our entry is duplicate with the gxact that
898  * has already been inserted into the ProcArray), lower the lock level to
899  * shared if we were to make xactCompletionCount an atomic variable. But
900  * that doesn't seem worth it currently, as a 2PC commit is heavyweight
901  * enough for this not to be the bottleneck. If it ever becomes a
902  * bottleneck it may also be worth considering to combine this with the
903  * subsequent ProcArrayRemove()
904  */
905  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
906 
907  pgxactoff = proc->pgxactoff;
908 
909  ProcGlobal->xids[pgxactoff] = InvalidTransactionId;
910  proc->xid = InvalidTransactionId;
911 
913  proc->xmin = InvalidTransactionId;
914  proc->recoveryConflictPending = false;
915 
917  Assert(!proc->delayChkpt);
918 
919  /*
920  * Need to increment completion count even though transaction hasn't
921  * really committed yet. The reason for that is that GetSnapshotData()
922  * omits the xid of the current transaction, thus without the increment we
923  * otherwise could end up reusing the snapshot later. Which would be bad,
924  * because it might not count the prepared transaction as running.
925  */
927 
928  /* Clear the subtransaction-XID cache too */
929  Assert(ProcGlobal->subxidStates[pgxactoff].count == proc->subxidStatus.count &&
931  if (proc->subxidStatus.count > 0 || proc->subxidStatus.overflowed)
932  {
933  ProcGlobal->subxidStates[pgxactoff].count = 0;
934  ProcGlobal->subxidStates[pgxactoff].overflowed = false;
935  proc->subxidStatus.count = 0;
936  proc->subxidStatus.overflowed = false;
937  }
938 
939  LWLockRelease(ProcArrayLock);
940 }
#define PROC_VACUUM_STATE_MASK
Definition: proc.h:61
LocalTransactionId lxid
Definition: proc.h:146

References Assert(), XidCacheStatus::count, PGPROC::delayChkpt, 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 654 of file procarray.c.

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

References Assert(), XidCacheStatus::count, PGPROC::delayChkpt, 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 715 of file procarray.c.

716 {
717  int pgxactoff = proc->pgxactoff;
718 
719  /*
720  * Note: we need exclusive lock here because we're going to change other
721  * processes' PGPROC entries.
722  */
723  Assert(LWLockHeldByMeInMode(ProcArrayLock, LW_EXCLUSIVE));
725  Assert(ProcGlobal->xids[pgxactoff] == proc->xid);
726 
727  ProcGlobal->xids[pgxactoff] = InvalidTransactionId;
728  proc->xid = InvalidTransactionId;
730  proc->xmin = InvalidTransactionId;
731  proc->delayChkpt = false; /* be sure this is cleared in abort */
732  proc->recoveryConflictPending = false;
733 
734  /* must be cleared with xid/xmin: */
735  /* avoid unnecessarily dirtying shared cachelines */
737  {
740  }
741 
742  /* Clear the subtransaction-XID cache too while holding the lock */
743  Assert(ProcGlobal->subxidStates[pgxactoff].count == proc->subxidStatus.count &&
745  if (proc->subxidStatus.count > 0 || proc->subxidStatus.overflowed)
746  {
747  ProcGlobal->subxidStates[pgxactoff].count = 0;
748  ProcGlobal->subxidStates[pgxactoff].overflowed = false;
749  proc->subxidStatus.count = 0;
750  proc->subxidStatus.overflowed = false;
751  }
752 
753  /* Also advance global latestCompletedXid while holding the lock */
754  MaintainLatestCompletedXid(latestXid);
755 
756  /* Same with xactCompletionCount */
758 }
bool LWLockHeldByMeInMode(LWLock *l, LWLockMode mode)
Definition: lwlock.c:1937
static void MaintainLatestCompletedXid(TransactionId latestXid)
Definition: procarray.c:947

References Assert(), XidCacheStatus::count, PGPROC::delayChkpt, 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 3903 of file procarray.c.

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

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

774 {
775  PROC_HDR *procglobal = ProcGlobal;
776  uint32 nextidx;
777  uint32 wakeidx;
778 
779  /* We should definitely have an XID to clear. */
781 
782  /* Add ourselves to the list of processes needing a group XID clear. */
783  proc->procArrayGroupMember = true;
784  proc->procArrayGroupMemberXid = latestXid;
785  nextidx = pg_atomic_read_u32(&procglobal->procArrayGroupFirst);
786  while (true)
787  {
788  pg_atomic_write_u32(&proc->procArrayGroupNext, nextidx);
789 
791  &nextidx,
792  (uint32) proc->pgprocno))
793  break;
794  }
795 
796  /*
797  * If the list was not empty, the leader will clear our XID. It is
798  * impossible to have followers without a leader because the first process
799  * that has added itself to the list will always have nextidx as
800  * INVALID_PGPROCNO.
801  */
802  if (nextidx != INVALID_PGPROCNO)
803  {
804  int extraWaits = 0;
805 
806  /* Sleep until the leader clears our XID. */
808  for (;;)
809  {
810  /* acts as a read barrier */
811  PGSemaphoreLock(proc->sem);
812  if (!proc->procArrayGroupMember)
813  break;
814  extraWaits++;
815  }
817 
819 
820  /* Fix semaphore count for any absorbed wakeups */
821  while (extraWaits-- > 0)
822  PGSemaphoreUnlock(proc->sem);
823  return;
824  }
825 
826  /* We are the leader. Acquire the lock on behalf of everyone. */
827  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
828 
829  /*
830  * Now that we've got the lock, clear the list of processes waiting for
831  * group XID clearing, saving a pointer to the head of the list. Trying
832  * to pop elements one at a time could lead to an ABA problem.
833  */
834  nextidx = pg_atomic_exchange_u32(&procglobal->procArrayGroupFirst,
836 
837  /* Remember head of list so we can perform wakeups after dropping lock. */
838  wakeidx = nextidx;
839 
840  /* Walk the list and clear all XIDs. */
841  while (nextidx != INVALID_PGPROCNO)
842  {
843  PGPROC *nextproc = &allProcs[nextidx];
844 
846 
847  /* Move to next proc in list. */
848  nextidx = pg_atomic_read_u32(&nextproc->procArrayGroupNext);
849  }
850 
851  /* We're done with the lock now. */
852  LWLockRelease(ProcArrayLock);
853 
854  /*
855  * Now that we've released the lock, go back and wake everybody up. We
856  * don't do this under the lock so as to keep lock hold times to a
857  * minimum. The system calls we need to perform to wake other processes
858  * up are probably much slower than the simple memory writes we did while
859  * holding the lock.
860  */
861  while (wakeidx != INVALID_PGPROCNO)
862  {
863  PGPROC *nextproc = &allProcs[wakeidx];
864 
865  wakeidx = pg_atomic_read_u32(&nextproc->procArrayGroupNext);
867 
868  /* ensure all previous writes are visible before follower continues. */
870 
871  nextproc->procArrayGroupMember = false;
872 
873  if (nextproc != MyProc)
874  PGSemaphoreUnlock(nextproc->sem);
875  }
876 }
static bool pg_atomic_compare_exchange_u32(volatile pg_atomic_uint32 *ptr, uint32 *expected, uint32 newval)
Definition: atomics.h:311
#define pg_write_barrier()
Definition: atomics.h:159
static void pg_atomic_write_u32(volatile pg_atomic_uint32 *ptr, uint32 val)
Definition: atomics.h:258
static uint32 pg_atomic_read_u32(volatile pg_atomic_uint32 *ptr)
Definition: atomics.h:241
static uint32 pg_atomic_exchange_u32(volatile pg_atomic_uint32 *ptr, uint32 newval)
Definition: atomics.h:292
unsigned int uint32
Definition: c.h:441
void PGSemaphoreUnlock(PGSemaphore sema)
Definition: posix_sema.c:340
void PGSemaphoreLock(PGSemaphore sema)
Definition: posix_sema.c:320
#define INVALID_PGPROCNO
Definition: proc.h:83
bool procArrayGroupMember
Definition: proc.h:219
pg_atomic_uint32 procArrayGroupNext
Definition: proc.h:221
TransactionId procArrayGroupMemberXid
Definition: proc.h:227
PGSemaphore sem
Definition: proc.h:130
Definition: proc.h:319
pg_atomic_uint32 procArrayGroupFirst
Definition: proc.h:349
@ WAIT_EVENT_PROCARRAY_GROUP_UPDATE
Definition: wait_event.h:118
static void pgstat_report_wait_start(uint32 wait_event_info)
Definition: wait_event.h:264
static void pgstat_report_wait_end(void)
Definition: wait_event.h:280

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

1004 {
1006  Assert(TransactionIdIsNormal(initializedUptoXID));
1007 
1008  /*
1009  * we set latestObservedXid to the xid SUBTRANS has been initialized up
1010  * to, so we can extend it from that point onwards in
1011  * RecordKnownAssignedTransactionIds, and when we get consistent in
1012  * ProcArrayApplyRecoveryInfo().
1013  */
1014  latestObservedXid = initializedUptoXID;
1016 }

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

Referenced by StartupXLOG().

◆ ProcArrayInstallImportedXmin()

bool ProcArrayInstallImportedXmin ( TransactionId  xmin,
VirtualTransactionId sourcevxid 
)

Definition at line 2569 of file procarray.c.

2571 {
2572  bool result = false;
2573  ProcArrayStruct *arrayP = procArray;
2574  int index;
2575 
2577  if (!sourcevxid)
2578  return false;
2579 
2580  /* Get lock so source xact can't end while we're doing this */
2581  LWLockAcquire(ProcArrayLock, LW_SHARED);
2582 
2583  for (index = 0; index < arrayP->numProcs; index++)
2584  {
2585  int pgprocno = arrayP->pgprocnos[index];
2586  PGPROC *proc = &allProcs[pgprocno];
2587  int statusFlags = ProcGlobal->statusFlags[index];
2588  TransactionId xid;
2589 
2590  /* Ignore procs running LAZY VACUUM */
2591  if (statusFlags & PROC_IN_VACUUM)
2592  continue;
2593 
2594  /* We are only interested in the specific virtual transaction. */
2595  if (proc->backendId != sourcevxid->backendId)
2596  continue;
2597  if (proc->lxid != sourcevxid->localTransactionId)
2598  continue;
2599 
2600  /*
2601  * We check the transaction's database ID for paranoia's sake: if it's
2602  * in another DB then its xmin does not cover us. Caller should have
2603  * detected this already, so we just treat any funny cases as
2604  * "transaction not found".
2605  */
2606  if (proc->databaseId != MyDatabaseId)
2607  continue;
2608 
2609  /*
2610  * Likewise, let's just make real sure its xmin does cover us.
2611  */
2612  xid = UINT32_ACCESS_ONCE(proc->xmin);
2613  if (!TransactionIdIsNormal(xid) ||
2614  !TransactionIdPrecedesOrEquals(xid, xmin))
2615  continue;
2616 
2617  /*
2618  * We're good. Install the new xmin. As in GetSnapshotData, set
2619  * TransactionXmin too. (Note that because snapmgr.c called
2620  * GetSnapshotData first, we'll be overwriting a valid xmin here, so
2621  * we don't check that.)
2622  */
2623  MyProc->xmin = TransactionXmin = xmin;
2624 
2625  result = true;
2626  break;
2627  }
2628 
2629  LWLockRelease(ProcArrayLock);
2630 
2631  return result;
2632 }
BackendId backendId
Definition: proc.h:156

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

2649 {
2650  bool result = false;
2651  TransactionId xid;
2652 
2654  Assert(proc != NULL);
2655 
2656  /*
2657  * Get an exclusive lock so that we can copy statusFlags from source proc.
2658  */
2659  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
2660 
2661  /*
2662  * Be certain that the referenced PGPROC has an advertised xmin which is
2663  * no later than the one we're installing, so that the system-wide xmin
2664  * can't go backwards. Also, make sure it's running in the same database,
2665  * so that the per-database xmin cannot go backwards.
2666  */
2667  xid = UINT32_ACCESS_ONCE(proc->xmin);
2668  if (proc->databaseId == MyDatabaseId &&
2669  TransactionIdIsNormal(xid) &&
2670  TransactionIdPrecedesOrEquals(xid, xmin))
2671  {
2672  /* Install xmin */
2673  MyProc->xmin = TransactionXmin = xmin;
2674 
2675  /* Flags being copied must be valid copy-able flags. */
2676  Assert((proc->statusFlags & (~PROC_COPYABLE_FLAGS)) == 0);
2677  MyProc->statusFlags = proc->statusFlags;
2679 
2680  result = true;
2681  }
2682 
2683  LWLockRelease(ProcArrayLock);
2684 
2685  return result;
2686 }
#define PROC_COPYABLE_FLAGS
Definition: proc.h:69

References Assert(), PGPROC::databaseId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MyDatabaseId, MyProc, PGPROC::pgxactoff, PROC_COPYABLE_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 552 of file procarray.c.

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

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

3883 {
3884  Assert(!already_locked || LWLockHeldByMe(ProcArrayLock));
3885 
3886  if (!already_locked)
3887  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3888 
3890  procArray->replication_slot_catalog_xmin = catalog_xmin;
3891 
3892  if (!already_locked)
3893  LWLockRelease(ProcArrayLock);
3894 }

References Assert(), 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 363 of file procarray.c.

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

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

Referenced by CalculateShmemSize().

◆ RecordKnownAssignedTransactionIds()

void RecordKnownAssignedTransactionIds ( TransactionId  xid)

Definition at line 4368 of file procarray.c.

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

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

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

◆ SignalVirtualTransaction()

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

Definition at line 3442 of file procarray.c.

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

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

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

References allProcs, BackendPidGetProc(), PGPROC::databaseId, ereport, errcode(), 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 1591 of file procarray.c.

1592 {
1593  bool result = false;
1594  ProcArrayStruct *arrayP = procArray;
1595  TransactionId *other_xids = ProcGlobal->xids;
1596  int i;
1597 
1598  /*
1599  * Don't bother checking a transaction older than RecentXmin; it could not
1600  * possibly still be running.
1601  */
1603  return false;
1604 
1605  LWLockAcquire(ProcArrayLock, LW_SHARED);
1606 
1607  for (i = 0; i < arrayP->numProcs; i++)
1608  {
1609  int pgprocno = arrayP->pgprocnos[i];
1610  PGPROC *proc = &allProcs[pgprocno];
1611  TransactionId pxid;
1612 
1613  /* Fetch xid just once - see GetNewTransactionId */
1614  pxid = UINT32_ACCESS_ONCE(other_xids[i]);
1615 
1616  if (!TransactionIdIsValid(pxid))
1617  continue;
1618 
1619  if (proc->pid == 0)
1620  continue; /* ignore prepared transactions */
1621 
1622  if (TransactionIdEquals(pxid, xid))
1623  {
1624  result = true;
1625  break;
1626  }
1627  }
1628 
1629  LWLockRelease(ProcArrayLock);
1630 
1631  return result;
1632 }

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

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

References allProcs, Assert(), XidCacheStatus::count, ereport, errcode(), errmsg(), ERROR, i, j, KnownAssignedXidExists(), KnownAssignedXidsGet(), ProcArrayStruct::lastOverflowedXid, VariableCacheData::latestCompletedXid, LW_SHARED, LWLockAcquire(), LWLockRelease(), malloc, ProcArrayStruct::maxProcs, MyProc, ProcArrayStruct::numProcs, 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(), TransactionIdIsKnownCompleted(), TransactionIdIsValid, TransactionIdPrecedes(), TransactionIdPrecedesOrEquals(), UINT32_ACCESS_ONCE, xc_by_child_xid_inc, xc_by_known_assigned_inc, xc_by_known_xact_inc, xc_by_latest_xid_inc, xc_by_main_xid_inc, xc_by_my_xact_inc, xc_by_recent_xmin_inc, xc_no_overflow_inc, xc_slow_answer_inc, XidFromFullTransactionId, XidCache::xids, and PROC_HDR::xids.

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

◆ XidCacheRemoveRunningXids()

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

Definition at line 3926 of file procarray.c.

3929 {
3930  int i,
3931  j;
3932  XidCacheStatus *mysubxidstat;
3933 
3935 
3936  /*
3937  * We must hold ProcArrayLock exclusively in order to remove transactions
3938  * from the PGPROC array. (See src/backend/access/transam/README.) It's
3939  * possible this could be relaxed since we know this routine is only used
3940  * to abort subtransactions, but pending closer analysis we'd best be
3941  * conservative.
3942  *
3943  * Note that we do not have to be careful about memory ordering of our own
3944  * reads wrt. GetNewTransactionId() here - only this process can modify
3945  * relevant fields of MyProc/ProcGlobal->xids[]. But we do have to be
3946  * careful about our own writes being well ordered.
3947  */
3948  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3949 
3950  mysubxidstat = &ProcGlobal->subxidStates[MyProc->pgxactoff];
3951 
3952  /*
3953  * Under normal circumstances xid and xids[] will be in increasing order,
3954  * as will be the entries in subxids. Scan backwards to avoid O(N^2)
3955  * behavior when removing a lot of xids.
3956  */
3957  for (i = nxids - 1; i >= 0; i--)
3958  {
3959  TransactionId anxid = xids[i];
3960 
3961  for (j = MyProc->subxidStatus.count - 1; j >= 0; j--)
3962  {
3963  if (TransactionIdEquals(MyProc->subxids.xids[j], anxid))
3964  {
3966  pg_write_barrier();
3967  mysubxidstat->count--;
3969  break;
3970  }
3971  }
3972 
3973  /*
3974  * Ordinarily we should have found it, unless the cache has
3975  * overflowed. However it's also possible for this routine to be
3976  * invoked multiple times for the same subtransaction, in case of an
3977  * error during AbortSubTransaction. So instead of Assert, emit a
3978  * debug warning.
3979  */
3980  if (j < 0 && !MyProc->subxidStatus.overflowed)
3981  elog(WARNING, "did not find subXID %u in MyProc", anxid);
3982  }
3983 
3984  for (j = MyProc->subxidStatus.count - 1; j >= 0; j--)
3985  {
3986  if (TransactionIdEquals(MyProc->subxids.xids[j], xid))
3987  {
3989  pg_write_barrier();
3990  mysubxidstat->count--;
3992  break;
3993  }
3994  }
3995  /* Ordinarily we should have found it, unless the cache has overflowed */
3996  if (j < 0 && !MyProc->subxidStatus.overflowed)
3997  elog(WARNING, "did not find subXID %u in MyProc", xid);
3998 
3999  /* Also advance global latestCompletedXid while holding the lock */
4000  MaintainLatestCompletedXid(latestXid);
4001 
4002  /* ... and xactCompletionCount */
4004 
4005  LWLockRelease(ProcArrayLock);
4006 }
#define WARNING
Definition: elog.h:30

References Assert(), XidCacheStatus::count, elog, i, j, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MaintainLatestCompletedXid(), MyProc, pg_write_barrier, PGPROC::pgxactoff, ProcGlobal,