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/xlog.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
 

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

Referenced by CountOtherDBBackends().

◆ PROCARRAY_MAXPROCS

◆ TOTAL_MAX_CACHED_SUBXIDS

◆ UINT32_ACCESS_ONCE

◆ xc_by_child_xid_inc

#define xc_by_child_xid_inc ( )    ((void) 0)

Definition at line 316 of file procarray.c.

Referenced by TransactionIdIsInProgress().

◆ xc_by_known_assigned_inc

#define xc_by_known_assigned_inc ( )    ((void) 0)

Definition at line 317 of file procarray.c.

Referenced by TransactionIdIsInProgress().

◆ xc_by_known_xact_inc

#define xc_by_known_xact_inc ( )    ((void) 0)

Definition at line 312 of file procarray.c.

Referenced by TransactionIdIsInProgress().

◆ xc_by_latest_xid_inc

#define xc_by_latest_xid_inc ( )    ((void) 0)

Definition at line 314 of file procarray.c.

Referenced by TransactionIdIsInProgress().

◆ xc_by_main_xid_inc

#define xc_by_main_xid_inc ( )    ((void) 0)

Definition at line 315 of file procarray.c.

Referenced by TransactionIdIsInProgress().

◆ xc_by_my_xact_inc

#define xc_by_my_xact_inc ( )    ((void) 0)

Definition at line 313 of file procarray.c.

Referenced by TransactionIdIsInProgress().

◆ xc_by_recent_xmin_inc

#define xc_by_recent_xmin_inc ( )    ((void) 0)

Definition at line 311 of file procarray.c.

Referenced by TransactionIdIsInProgress().

◆ xc_no_overflow_inc

#define xc_no_overflow_inc ( )    ((void) 0)

Definition at line 318 of file procarray.c.

Referenced by TransactionIdIsInProgress().

◆ xc_slow_answer_inc

#define xc_slow_answer_inc ( )    ((void) 0)

Definition at line 319 of file procarray.c.

Referenced by TransactionIdIsInProgress().

Typedef Documentation

◆ ComputeXidHorizonsResult

◆ ProcArrayStruct

Function Documentation

◆ BackendPidGetProc()

PGPROC* BackendPidGetProc ( int  pid)

Definition at line 3090 of file procarray.c.

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(), ProcSendSignal(), TerminateOtherDBBackends(), and test_shm_mq_main().

3091 {
3092  PGPROC *result;
3093 
3094  if (pid == 0) /* never match dummy PGPROCs */
3095  return NULL;
3096 
3097  LWLockAcquire(ProcArrayLock, LW_SHARED);
3098 
3099  result = BackendPidGetProcWithLock(pid);
3100 
3101  LWLockRelease(ProcArrayLock);
3102 
3103  return result;
3104 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
PGPROC * BackendPidGetProcWithLock(int pid)
Definition: procarray.c:3113
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203
Definition: proc.h:121

◆ BackendPidGetProcWithLock()

PGPROC* BackendPidGetProcWithLock ( int  pid)

Definition at line 3113 of file procarray.c.

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

Referenced by BackendPidGetProc(), and GetBlockerStatusData().

3114 {
3115  PGPROC *result = NULL;
3116  ProcArrayStruct *arrayP = procArray;
3117  int index;
3118 
3119  if (pid == 0) /* never match dummy PGPROCs */
3120  return NULL;
3121 
3122  for (index = 0; index < arrayP->numProcs; index++)
3123  {
3124  PGPROC *proc = &allProcs[arrayP->pgprocnos[index]];
3125 
3126  if (proc->pid == pid)
3127  {
3128  result = proc;
3129  break;
3130  }
3131  }
3132 
3133  return result;
3134 }
Definition: type.h:89
static PGPROC * allProcs
Definition: procarray.c:252
static ProcArrayStruct * procArray
Definition: procarray.c:250
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
Definition: proc.h:121
int pid
Definition: proc.h:146

◆ BackendXidGetPid()

int BackendXidGetPid ( TransactionId  xid)

Definition at line 3150 of file procarray.c.

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

Referenced by pgrowlocks().

3151 {
3152  int result = 0;
3153  ProcArrayStruct *arrayP = procArray;
3154  TransactionId *other_xids = ProcGlobal->xids;
3155  int index;
3156 
3157  if (xid == InvalidTransactionId) /* never match invalid xid */
3158  return 0;
3159 
3160  LWLockAcquire(ProcArrayLock, LW_SHARED);
3161 
3162  for (index = 0; index < arrayP->numProcs; index++)
3163  {
3164  int pgprocno = arrayP->pgprocnos[index];
3165  PGPROC *proc = &allProcs[pgprocno];
3166 
3167  if (other_xids[index] == xid)
3168  {
3169  result = proc->pid;
3170  break;
3171  }
3172  }
3173 
3174  LWLockRelease(ProcArrayLock);
3175 
3176  return result;
3177 }
uint32 TransactionId
Definition: c.h:587
PROC_HDR * ProcGlobal
Definition: proc.c:80
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
#define InvalidTransactionId
Definition: transam.h:31
TransactionId * xids
Definition: proc.h:321
static PGPROC * allProcs
Definition: procarray.c:252
static ProcArrayStruct * procArray
Definition: procarray.c:250
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203
Definition: proc.h:121
int pid
Definition: proc.h:146

◆ CancelDBBackends()

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

Definition at line 3549 of file procarray.c.

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

3550 {
3551  ProcArrayStruct *arrayP = procArray;
3552  int index;
3553 
3554  /* tell all backends to die */
3555  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3556 
3557  for (index = 0; index < arrayP->numProcs; index++)
3558  {
3559  int pgprocno = arrayP->pgprocnos[index];
3560  PGPROC *proc = &allProcs[pgprocno];
3561 
3562  if (databaseid == InvalidOid || proc->databaseId == databaseid)
3563  {
3564  VirtualTransactionId procvxid;
3565  pid_t pid;
3566 
3567  GET_VXID_FROM_PGPROC(procvxid, *proc);
3568 
3569  proc->recoveryConflictPending = conflictPending;
3570  pid = proc->pid;
3571  if (pid != 0)
3572  {
3573  /*
3574  * Kill the pid if it's still here. If not, that's what we
3575  * wanted so ignore any errors.
3576  */
3577  (void) SendProcSignal(pid, sigmode, procvxid.backendId);
3578  }
3579  }
3580  }
3581 
3582  LWLockRelease(ProcArrayLock);
3583 }
#define GET_VXID_FROM_PGPROC(vxid, proc)
Definition: lock.h:81
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
int SendProcSignal(pid_t pid, ProcSignalReason reason, BackendId backendId)
Definition: procsignal.c:261
bool recoveryConflictPending
Definition: proc.h:167
static PGPROC * allProcs
Definition: procarray.c:252
Oid databaseId
Definition: proc.h:154
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define InvalidOid
Definition: postgres_ext.h:36
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
BackendId backendId
Definition: lock.h:65
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203
Definition: proc.h:121
int pid
Definition: proc.h:146

◆ CancelVirtualTransaction()

pid_t CancelVirtualTransaction ( VirtualTransactionId  vxid,
ProcSignalReason  sigmode 
)

Definition at line 3380 of file procarray.c.

References SignalVirtualTransaction().

Referenced by ResolveRecoveryConflictWithVirtualXIDs().

3381 {
3382  return SignalVirtualTransaction(vxid, sigmode, true);
3383 }
pid_t SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode, bool conflictPending)
Definition: procarray.c:3386

◆ ComputeXidHorizons()

static void ComputeXidHorizons ( ComputeXidHorizonsResult h)
static

Definition at line 1690 of file procarray.c.

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

1691 {
1692  ProcArrayStruct *arrayP = procArray;
1693  TransactionId kaxmin;
1694  bool in_recovery = RecoveryInProgress();
1695  TransactionId *other_xids = ProcGlobal->xids;
1696 
1697  LWLockAcquire(ProcArrayLock, LW_SHARED);
1698 
1700 
1701  /*
1702  * We initialize the MIN() calculation with latestCompletedXid + 1. This
1703  * is a lower bound for the XIDs that might appear in the ProcArray later,
1704  * and so protects us against overestimating the result due to future
1705  * additions.
1706  */
1707  {
1708  TransactionId initial;
1709 
1711  Assert(TransactionIdIsValid(initial));
1712  TransactionIdAdvance(initial);
1713 
1714  h->oldest_considered_running = initial;
1715  h->shared_oldest_nonremovable = initial;
1716  h->catalog_oldest_nonremovable = initial;
1717  h->data_oldest_nonremovable = initial;
1718 
1719  /*
1720  * Only modifications made by this backend affect the horizon for
1721  * temporary relations. Instead of a check in each iteration of the
1722  * loop over all PGPROCs it is cheaper to just initialize to the
1723  * current top-level xid any.
1724  *
1725  * Without an assigned xid we could use a horizon as aggressive as
1726  * ReadNewTransactionid(), but we can get away with the much cheaper
1727  * latestCompletedXid + 1: If this backend has no xid there, by
1728  * definition, can't be any newer changes in the temp table than
1729  * latestCompletedXid.
1730  */
1733  else
1734  h->temp_oldest_nonremovable = initial;
1735  }
1736 
1737  /*
1738  * Fetch slot horizons while ProcArrayLock is held - the
1739  * LWLockAcquire/LWLockRelease are a barrier, ensuring this happens inside
1740  * the lock.
1741  */
1744 
1745  for (int index = 0; index < arrayP->numProcs; index++)
1746  {
1747  int pgprocno = arrayP->pgprocnos[index];
1748  PGPROC *proc = &allProcs[pgprocno];
1749  int8 statusFlags = ProcGlobal->statusFlags[index];
1750  TransactionId xid;
1751  TransactionId xmin;
1752 
1753  /* Fetch xid just once - see GetNewTransactionId */
1754  xid = UINT32_ACCESS_ONCE(other_xids[index]);
1755  xmin = UINT32_ACCESS_ONCE(proc->xmin);
1756 
1757  /*
1758  * Consider both the transaction's Xmin, and its Xid.
1759  *
1760  * We must check both because a transaction might have an Xmin but not
1761  * (yet) an Xid; conversely, if it has an Xid, that could determine
1762  * some not-yet-set Xmin.
1763  */
1764  xmin = TransactionIdOlder(xmin, xid);
1765 
1766  /* if neither is set, this proc doesn't influence the horizon */
1767  if (!TransactionIdIsValid(xmin))
1768  continue;
1769 
1770  /*
1771  * Don't ignore any procs when determining which transactions might be
1772  * considered running. While slots should ensure logical decoding
1773  * backends are protected even without this check, it can't hurt to
1774  * include them here as well..
1775  */
1778 
1779  /*
1780  * Skip over backends either vacuuming (which is ok with rows being
1781  * removed, as long as pg_subtrans is not truncated) or doing logical
1782  * decoding (which manages xmin separately, check below).
1783  */
1784  if (statusFlags & (PROC_IN_VACUUM | PROC_IN_LOGICAL_DECODING))
1785  continue;
1786 
1787  /* shared tables need to take backends in all databases into account */
1790 
1791  /*
1792  * Normally queries in other databases are ignored for anything but
1793  * the shared horizon. But in recovery we cannot compute an accurate
1794  * per-database horizon as all xids are managed via the
1795  * KnownAssignedXids machinery.
1796  *
1797  * Be careful to compute a pessimistic value when MyDatabaseId is not
1798  * set. If this is a backend in the process of starting up, we may not
1799  * use a "too aggressive" horizon (otherwise we could end up using it
1800  * to prune still needed data away). If the current backend never
1801  * connects to a database that is harmless, because
1802  * data_oldest_nonremovable will never be utilized.
1803  */
1804  if (in_recovery ||
1806  proc->databaseId == 0) /* always include WalSender */
1807  {
1808  /*
1809  * We can ignore this backend if it's running CREATE INDEX
1810  * CONCURRENTLY or REINDEX CONCURRENTLY on a "safe" index -- but
1811  * only on vacuums of user-defined tables.
1812  */
1813  if (!(statusFlags & PROC_IN_SAFE_IC))
1816 
1817  /* Catalog tables need to consider all backends in this db */
1820 
1821  }
1822  }
1823 
1824  /* catalog horizon should never be later than data */
1827 
1828  /*
1829  * If in recovery fetch oldest xid in KnownAssignedXids, will be applied
1830  * after lock is released.
1831  */
1832  if (in_recovery)
1833  kaxmin = KnownAssignedXidsGetOldestXmin();
1834 
1835  /*
1836  * No other information from shared state is needed, release the lock
1837  * immediately. The rest of the computations can be done without a lock.
1838  */
1839  LWLockRelease(ProcArrayLock);
1840 
1841  if (in_recovery)
1842  {
1851  /* temp relations cannot be accessed in recovery */
1852  }
1853  else
1854  {
1855  /*
1856  * Compute the cutoff XID by subtracting vacuum_defer_cleanup_age.
1857  *
1858  * vacuum_defer_cleanup_age provides some additional "slop" for the
1859  * benefit of hot standby queries on standby servers. This is quick
1860  * and dirty, and perhaps not all that useful unless the primary has a
1861  * predictable transaction rate, but it offers some protection when
1862  * there's no walsender connection. Note that we are assuming
1863  * vacuum_defer_cleanup_age isn't large enough to cause wraparound ---
1864  * so guc.c should limit it to no more than the xidStopLimit threshold
1865  * in varsup.c. Also note that we intentionally don't apply
1866  * vacuum_defer_cleanup_age on standby servers.
1867  */
1880  /* defer doesn't apply to temp relations */
1881  }
1882 
1883  /*
1884  * Check whether there are replication slots requiring an older xmin.
1885  */
1890 
1891  /*
1892  * The only difference between catalog / data horizons is that the slot's
1893  * catalog xmin is applied to the catalog one (so catalogs can be accessed
1894  * for logical decoding). Initialize with data horizon, and then back up
1895  * further if necessary. Have to back up the shared horizon as well, since
1896  * that also can contain catalogs.
1897  */
1901  h->slot_catalog_xmin);
1904  h->slot_xmin);
1907  h->slot_catalog_xmin);
1908 
1909  /*
1910  * It's possible that slots / vacuum_defer_cleanup_age backed up the
1911  * horizons further than oldest_considered_running. Fix.
1912  */
1922 
1923  /*
1924  * shared horizons have to be at least as old as the oldest visible in
1925  * current db
1926  */
1931 
1932  /*
1933  * Horizons need to ensure that pg_subtrans access is still possible for
1934  * the relevant backends.
1935  */
1946  h->slot_xmin));
1949  h->slot_catalog_xmin));
1950 
1951  /* update approximate horizons with the computed horizons */
1953 }
#define TransactionIdAdvance(dest)
Definition: transam.h:91
TransactionId oldest_considered_running
Definition: procarray.c:207
FullTransactionId latest_completed
Definition: procarray.c:187
TransactionId shared_oldest_nonremovable_raw
Definition: procarray.c:227
#define PROC_IN_LOGICAL_DECODING
Definition: proc.h:61
uint32 TransactionId
Definition: c.h:587
PGPROC * MyProc
Definition: proc.c:68
int vacuum_defer_cleanup_age
Definition: standby.c:39
#define UINT32_ACCESS_ONCE(var)
Definition: procarray.c:69
TransactionId replication_slot_catalog_xmin
Definition: procarray.c:98
PROC_HDR * ProcGlobal
Definition: proc.c:80
FullTransactionId latestCompletedXid
Definition: transam.h:233
bool RecoveryInProgress(void)
Definition: xlog.c:8210
TransactionId catalog_oldest_nonremovable
Definition: procarray.c:233
#define XidFromFullTransactionId(x)
Definition: transam.h:48
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
#define PROC_IN_VACUUM
Definition: proc.h:55
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:319
TransactionId slot_catalog_xmin
Definition: procarray.c:194
TransactionId xmin
Definition: proc.h:138
VariableCache ShmemVariableCache
Definition: varsup.c:34
TransactionId * xids
Definition: proc.h:321
static PGPROC * allProcs
Definition: procarray.c:252
Oid databaseId
Definition: proc.h:154
TransactionId shared_oldest_nonremovable
Definition: procarray.c:216
static ProcArrayStruct * procArray
Definition: procarray.c:250
signed char int8
Definition: c.h:427
TransactionId replication_slot_xmin
Definition: procarray.c:96
Oid MyDatabaseId
Definition: globals.c:88
static TransactionId KnownAssignedXidsGetOldestXmin(void)
Definition: procarray.c:5019
#define InvalidOid
Definition: postgres_ext.h:36
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
#define PROC_IN_SAFE_IC
Definition: proc.h:56
TransactionId temp_oldest_nonremovable
Definition: procarray.c:245
static TransactionId TransactionIdOlder(TransactionId a, TransactionId b)
Definition: transam.h:329
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203
static void GlobalVisUpdateApply(ComputeXidHorizonsResult *horizons)
Definition: procarray.c:4056
static TransactionId TransactionIdRetreatedBy(TransactionId xid, uint32 amount)
Definition: transam.h:317
TransactionId xid
Definition: proc.h:133
TransactionId data_oldest_nonremovable
Definition: procarray.c:239
uint8 * statusFlags
Definition: proc.h:333
#define TransactionIdIsValid(xid)
Definition: transam.h:41
TransactionId slot_xmin
Definition: procarray.c:193
Definition: proc.h:121

◆ CountDBBackends()

int CountDBBackends ( Oid  databaseid)

Definition at line 3488 of file procarray.c.

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

Referenced by ResolveRecoveryConflictWithDatabase().

3489 {
3490  ProcArrayStruct *arrayP = procArray;
3491  int count = 0;
3492  int index;
3493 
3494  LWLockAcquire(ProcArrayLock, LW_SHARED);
3495 
3496  for (index = 0; index < arrayP->numProcs; index++)
3497  {
3498  int pgprocno = arrayP->pgprocnos[index];
3499  PGPROC *proc = &allProcs[pgprocno];
3500 
3501  if (proc->pid == 0)
3502  continue; /* do not count prepared xacts */
3503  if (!OidIsValid(databaseid) ||
3504  proc->databaseId == databaseid)
3505  count++;
3506  }
3507 
3508  LWLockRelease(ProcArrayLock);
3509 
3510  return count;
3511 }
#define OidIsValid(objectId)
Definition: c.h:710
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
static PGPROC * allProcs
Definition: procarray.c:252
Oid databaseId
Definition: proc.h:154
static ProcArrayStruct * procArray
Definition: procarray.c:250
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203
Definition: proc.h:121
int pid
Definition: proc.h:146

◆ CountDBConnections()

int CountDBConnections ( Oid  databaseid)

Definition at line 3518 of file procarray.c.

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

Referenced by CheckMyDatabase().

3519 {
3520  ProcArrayStruct *arrayP = procArray;
3521  int count = 0;
3522  int index;
3523 
3524  LWLockAcquire(ProcArrayLock, LW_SHARED);
3525 
3526  for (index = 0; index < arrayP->numProcs; index++)
3527  {
3528  int pgprocno = arrayP->pgprocnos[index];
3529  PGPROC *proc = &allProcs[pgprocno];
3530 
3531  if (proc->pid == 0)
3532  continue; /* do not count prepared xacts */
3533  if (proc->isBackgroundWorker)
3534  continue; /* do not count background workers */
3535  if (!OidIsValid(databaseid) ||
3536  proc->databaseId == databaseid)
3537  count++;
3538  }
3539 
3540  LWLockRelease(ProcArrayLock);
3541 
3542  return count;
3543 }
#define OidIsValid(objectId)
Definition: c.h:710
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
bool isBackgroundWorker
Definition: proc.h:160
static PGPROC * allProcs
Definition: procarray.c:252
Oid databaseId
Definition: proc.h:154
static ProcArrayStruct * procArray
Definition: procarray.c:250
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203
Definition: proc.h:121
int pid
Definition: proc.h:146

◆ CountOtherDBBackends()

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

Definition at line 3639 of file procarray.c.

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

3640 {
3641  ProcArrayStruct *arrayP = procArray;
3642 
3643 #define MAXAUTOVACPIDS 10 /* max autovacs to SIGTERM per iteration */
3644  int autovac_pids[MAXAUTOVACPIDS];
3645  int tries;
3646 
3647  /* 50 tries with 100ms sleep between tries makes 5 sec total wait */
3648  for (tries = 0; tries < 50; tries++)
3649  {
3650  int nautovacs = 0;
3651  bool found = false;
3652  int index;
3653 
3655 
3656  *nbackends = *nprepared = 0;
3657 
3658  LWLockAcquire(ProcArrayLock, LW_SHARED);
3659 
3660  for (index = 0; index < arrayP->numProcs; index++)
3661  {
3662  int pgprocno = arrayP->pgprocnos[index];
3663  PGPROC *proc = &allProcs[pgprocno];
3664  uint8 statusFlags = ProcGlobal->statusFlags[index];
3665 
3666  if (proc->databaseId != databaseId)
3667  continue;
3668  if (proc == MyProc)
3669  continue;
3670 
3671  found = true;
3672 
3673  if (proc->pid == 0)
3674  (*nprepared)++;
3675  else
3676  {
3677  (*nbackends)++;
3678  if ((statusFlags & PROC_IS_AUTOVACUUM) &&
3679  nautovacs < MAXAUTOVACPIDS)
3680  autovac_pids[nautovacs++] = proc->pid;
3681  }
3682  }
3683 
3684  LWLockRelease(ProcArrayLock);
3685 
3686  if (!found)
3687  return false; /* no conflicting backends, so done */
3688 
3689  /*
3690  * Send SIGTERM to any conflicting autovacuums before sleeping. We
3691  * postpone this step until after the loop because we don't want to
3692  * hold ProcArrayLock while issuing kill(). We have no idea what might
3693  * block kill() inside the kernel...
3694  */
3695  for (index = 0; index < nautovacs; index++)
3696  (void) kill(autovac_pids[index], SIGTERM); /* ignore any error */
3697 
3698  /* sleep, then try again */
3699  pg_usleep(100 * 1000L); /* 100ms */
3700  }
3701 
3702  return true; /* timed out, still conflicts */
3703 }
PGPROC * MyProc
Definition: proc.c:68
unsigned char uint8
Definition: c.h:439
PROC_HDR * ProcGlobal
Definition: proc.c:80
#define kill(pid, sig)
Definition: win32_port.h:454
#define MAXAUTOVACPIDS
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
void pg_usleep(long microsec)
Definition: signal.c:53
static PGPROC * allProcs
Definition: procarray.c:252
Oid databaseId
Definition: proc.h:154
static ProcArrayStruct * procArray
Definition: procarray.c:250
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:120
uint8 * statusFlags
Definition: proc.h:333
Definition: proc.h:121
int pid
Definition: proc.h:146
#define PROC_IS_AUTOVACUUM
Definition: proc.h:54

◆ CountUserBackends()

int CountUserBackends ( Oid  roleid)

Definition at line 3589 of file procarray.c.

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

Referenced by InitializeSessionUserId().

3590 {
3591  ProcArrayStruct *arrayP = procArray;
3592  int count = 0;
3593  int index;
3594 
3595  LWLockAcquire(ProcArrayLock, LW_SHARED);
3596 
3597  for (index = 0; index < arrayP->numProcs; index++)
3598  {
3599  int pgprocno = arrayP->pgprocnos[index];
3600  PGPROC *proc = &allProcs[pgprocno];
3601 
3602  if (proc->pid == 0)
3603  continue; /* do not count prepared xacts */
3604  if (proc->isBackgroundWorker)
3605  continue; /* do not count background workers */
3606  if (proc->roleId == roleid)
3607  count++;
3608  }
3609 
3610  LWLockRelease(ProcArrayLock);
3611 
3612  return count;
3613 }
Oid roleId
Definition: proc.h:155
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
bool isBackgroundWorker
Definition: proc.h:160
static PGPROC * allProcs
Definition: procarray.c:252
static ProcArrayStruct * procArray
Definition: procarray.c:250
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203
Definition: proc.h:121
int pid
Definition: proc.h:146

◆ CreateSharedProcArray()

void CreateSharedProcArray ( void  )

Definition at line 394 of file procarray.c.

References add_size(), 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, ProcArrayStruct::pgprocnos, 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().

395 {
396  bool found;
397 
398  /* Create or attach to the ProcArray shared structure */
400  ShmemInitStruct("Proc Array",
401  add_size(offsetof(ProcArrayStruct, pgprocnos),
402  mul_size(sizeof(int),
404  &found);
405 
406  if (!found)
407  {
408  /*
409  * We're the first - initialize.
410  */
411  procArray->numProcs = 0;
422  }
423 
425 
426  /* Create or attach to the KnownAssignedXids arrays too, if needed */
427  if (EnableHotStandby)
428  {
430  ShmemInitStruct("KnownAssignedXids",
431  mul_size(sizeof(TransactionId),
433  &found);
434  KnownAssignedXidsValid = (bool *)
435  ShmemInitStruct("KnownAssignedXidsValid",
436  mul_size(sizeof(bool), TOTAL_MAX_CACHED_SUBXIDS),
437  &found);
438  }
439 }
#define PROCARRAY_MAXPROCS
uint32 TransactionId
Definition: c.h:587
#define SpinLockInit(lock)
Definition: spin.h:60
TransactionId replication_slot_catalog_xmin
Definition: procarray.c:98
uint64 xactCompletionCount
Definition: transam.h:243
slock_t known_assigned_xids_lck
Definition: procarray.c:84
PROC_HDR * ProcGlobal
Definition: proc.c:80
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:396
VariableCache ShmemVariableCache
Definition: varsup.c:34
int maxKnownAssignedXids
Definition: procarray.c:80
#define InvalidTransactionId
Definition: transam.h:31
static PGPROC * allProcs
Definition: procarray.c:252
int numKnownAssignedXids
Definition: procarray.c:81
static bool * KnownAssignedXidsValid
Definition: procarray.c:258
TransactionId lastOverflowedXid
Definition: procarray.c:93
static ProcArrayStruct * procArray
Definition: procarray.c:250
TransactionId replication_slot_xmin
Definition: procarray.c:96
Size mul_size(Size s1, Size s2)
Definition: shmem.c:519
Size add_size(Size s1, Size s2)
Definition: shmem.c:502
#define TOTAL_MAX_CACHED_SUBXIDS
static TransactionId * KnownAssignedXids
Definition: procarray.c:257
bool EnableHotStandby
Definition: xlog.c:98
PGPROC * allProcs
Definition: proc.h:318
int tailKnownAssignedXids
Definition: procarray.c:82
#define offsetof(type, field)
Definition: c.h:727
int headKnownAssignedXids
Definition: procarray.c:83

◆ ExpireAllKnownAssignedTransactionIds()

void ExpireAllKnownAssignedTransactionIds ( void  )

Definition at line 4420 of file procarray.c.

References InvalidTransactionId, KnownAssignedXidsRemovePreceding(), LW_EXCLUSIVE, LWLockAcquire(), and LWLockRelease().

Referenced by ShutdownRecoveryTransactionEnvironment().

4421 {
4422  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4424  LWLockRelease(ProcArrayLock);
4425 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
static void KnownAssignedXidsRemovePreceding(TransactionId xid)
Definition: procarray.c:4869
#define InvalidTransactionId
Definition: transam.h:31
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203

◆ ExpireOldKnownAssignedTransactionIds()

void ExpireOldKnownAssignedTransactionIds ( TransactionId  xid)

Definition at line 4432 of file procarray.c.

References KnownAssignedXidsRemovePreceding(), LW_EXCLUSIVE, LWLockAcquire(), and LWLockRelease().

Referenced by ProcArrayApplyRecoveryInfo().

4433 {
4434  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4436  LWLockRelease(ProcArrayLock);
4437 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
static void KnownAssignedXidsRemovePreceding(TransactionId xid)
Definition: procarray.c:4869
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203

◆ ExpireTreeKnownAssignedTransactionIds()

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

Definition at line 4394 of file procarray.c.

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

Referenced by xact_redo_abort(), and xact_redo_commit().

4396 {
4398 
4399  /*
4400  * Uses same locking as transaction commit
4401  */
4402  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4403 
4404  KnownAssignedXidsRemoveTree(xid, nsubxids, subxids);
4405 
4406  /* As in ProcArrayEndTransaction, advance latestCompletedXid */
4408 
4409  /* ... and xactCompletionCount */
4411 
4412  LWLockRelease(ProcArrayLock);
4413 }
static void MaintainLatestCompletedXidRecovery(TransactionId latestXid)
Definition: procarray.c:958
uint64 xactCompletionCount
Definition: transam.h:243
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
VariableCache ShmemVariableCache
Definition: varsup.c:34
static void KnownAssignedXidsRemoveTree(TransactionId xid, int nsubxids, TransactionId *subxids)
Definition: procarray.c:4847
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203
HotStandbyState standbyState
Definition: xlog.c:210

◆ FullXidRelativeTo()

static FullTransactionId FullXidRelativeTo ( FullTransactionId  rel,
TransactionId  xid 
)
inlinestatic

Definition at line 4241 of file procarray.c.

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

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

4242 {
4243  TransactionId rel_xid = XidFromFullTransactionId(rel);
4244 
4246  Assert(TransactionIdIsValid(rel_xid));
4247 
4248  /* not guaranteed to find issues, but likely to catch mistakes */
4250 
4252  + (int32) (xid - rel_xid));
4253 }
uint32 TransactionId
Definition: c.h:587
static FullTransactionId FullTransactionIdFromU64(uint64 value)
Definition: transam.h:81
signed int int32
Definition: c.h:429
#define XidFromFullTransactionId(x)
Definition: transam.h:48
#define AssertTransactionIdInAllowableRange(xid)
Definition: transam.h:296
#define Assert(condition)
Definition: c.h:804
#define U64FromFullTransactionId(x)
Definition: transam.h:49
#define TransactionIdIsValid(xid)
Definition: transam.h:41

◆ GetConflictingVirtualXIDs()

VirtualTransactionId* GetConflictingVirtualXIDs ( TransactionId  limitXmin,
Oid  dbOid 
)

Definition at line 3306 of file procarray.c.

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

3307 {
3308  static VirtualTransactionId *vxids;
3309  ProcArrayStruct *arrayP = procArray;
3310  int count = 0;
3311  int index;
3312 
3313  /*
3314  * If first time through, get workspace to remember main XIDs in. We
3315  * malloc it permanently to avoid repeated palloc/pfree overhead. Allow
3316  * result space, remembering room for a terminator.
3317  */
3318  if (vxids == NULL)
3319  {
3320  vxids = (VirtualTransactionId *)
3321  malloc(sizeof(VirtualTransactionId) * (arrayP->maxProcs + 1));
3322  if (vxids == NULL)
3323  ereport(ERROR,
3324  (errcode(ERRCODE_OUT_OF_MEMORY),
3325  errmsg("out of memory")));
3326  }
3327 
3328  LWLockAcquire(ProcArrayLock, LW_SHARED);
3329 
3330  for (index = 0; index < arrayP->numProcs; index++)
3331  {
3332  int pgprocno = arrayP->pgprocnos[index];
3333  PGPROC *proc = &allProcs[pgprocno];
3334 
3335  /* Exclude prepared transactions */
3336  if (proc->pid == 0)
3337  continue;
3338 
3339  if (!OidIsValid(dbOid) ||
3340  proc->databaseId == dbOid)
3341  {
3342  /* Fetch xmin just once - can't change on us, but good coding */
3343  TransactionId pxmin = UINT32_ACCESS_ONCE(proc->xmin);
3344 
3345  /*
3346  * We ignore an invalid pxmin because this means that backend has
3347  * no snapshot currently. We hold a Share lock to avoid contention
3348  * with users taking snapshots. That is not a problem because the
3349  * current xmin is always at least one higher than the latest
3350  * removed xid, so any new snapshot would never conflict with the
3351  * test here.
3352  */
3353  if (!TransactionIdIsValid(limitXmin) ||
3354  (TransactionIdIsValid(pxmin) && !TransactionIdFollows(pxmin, limitXmin)))
3355  {
3356  VirtualTransactionId vxid;
3357 
3358  GET_VXID_FROM_PGPROC(vxid, *proc);
3359  if (VirtualTransactionIdIsValid(vxid))
3360  vxids[count++] = vxid;
3361  }
3362  }
3363  }
3364 
3365  LWLockRelease(ProcArrayLock);
3366 
3367  /* add the terminator */
3368  vxids[count].backendId = InvalidBackendId;
3370 
3371  return vxids;
3372 }
#define GET_VXID_FROM_PGPROC(vxid, proc)
Definition: lock.h:81
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
uint32 TransactionId
Definition: c.h:587
#define UINT32_ACCESS_ONCE(var)
Definition: procarray.c:69
int errcode(int sqlerrcode)
Definition: elog.c:698
LocalTransactionId localTransactionId
Definition: lock.h:66
#define OidIsValid(objectId)
Definition: c.h:710
Definition: type.h:89
#define malloc(a)
Definition: header.h:50
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
#define ERROR
Definition: elog.h:46
TransactionId xmin
Definition: proc.h:138
static PGPROC * allProcs
Definition: procarray.c:252
Oid databaseId
Definition: proc.h:154
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define VirtualTransactionIdIsValid(vxid)
Definition: lock.h:71
#define InvalidBackendId
Definition: backendid.h:23
#define ereport(elevel,...)
Definition: elog.h:157
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
BackendId backendId
Definition: lock.h:65
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define InvalidLocalTransactionId
Definition: lock.h:69
#define TransactionIdIsValid(xid)
Definition: transam.h:41
Definition: proc.h:121
int pid
Definition: proc.h:146

◆ GetCurrentVirtualXIDs()

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

Definition at line 3218 of file procarray.c.

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

3221 {
3222  VirtualTransactionId *vxids;
3223  ProcArrayStruct *arrayP = procArray;
3224  int count = 0;
3225  int index;
3226 
3227  /* allocate what's certainly enough result space */
3228  vxids = (VirtualTransactionId *)
3229  palloc(sizeof(VirtualTransactionId) * arrayP->maxProcs);
3230 
3231  LWLockAcquire(ProcArrayLock, LW_SHARED);
3232 
3233  for (index = 0; index < arrayP->numProcs; index++)
3234  {
3235  int pgprocno = arrayP->pgprocnos[index];
3236  PGPROC *proc = &allProcs[pgprocno];
3237  uint8 statusFlags = ProcGlobal->statusFlags[index];
3238 
3239  if (proc == MyProc)
3240  continue;
3241 
3242  if (excludeVacuum & statusFlags)
3243  continue;
3244 
3245  if (allDbs || proc->databaseId == MyDatabaseId)
3246  {
3247  /* Fetch xmin just once - might change on us */
3248  TransactionId pxmin = UINT32_ACCESS_ONCE(proc->xmin);
3249 
3250  if (excludeXmin0 && !TransactionIdIsValid(pxmin))
3251  continue;
3252 
3253  /*
3254  * InvalidTransactionId precedes all other XIDs, so a proc that
3255  * hasn't set xmin yet will not be rejected by this test.
3256  */
3257  if (!TransactionIdIsValid(limitXmin) ||
3258  TransactionIdPrecedesOrEquals(pxmin, limitXmin))
3259  {
3260  VirtualTransactionId vxid;
3261 
3262  GET_VXID_FROM_PGPROC(vxid, *proc);
3263  if (VirtualTransactionIdIsValid(vxid))
3264  vxids[count++] = vxid;
3265  }
3266  }
3267  }
3268 
3269  LWLockRelease(ProcArrayLock);
3270 
3271  *nvxids = count;
3272  return vxids;
3273 }
#define GET_VXID_FROM_PGPROC(vxid, proc)
Definition: lock.h:81
uint32 TransactionId
Definition: c.h:587
PGPROC * MyProc
Definition: proc.c:68
#define UINT32_ACCESS_ONCE(var)
Definition: procarray.c:69
unsigned char uint8
Definition: c.h:439
PROC_HDR * ProcGlobal
Definition: proc.c:80
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:319
TransactionId xmin
Definition: proc.h:138
static PGPROC * allProcs
Definition: procarray.c:252
Oid databaseId
Definition: proc.h:154
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define VirtualTransactionIdIsValid(vxid)
Definition: lock.h:71
Oid MyDatabaseId
Definition: globals.c:88
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203
void * palloc(Size size)
Definition: mcxt.c:1062
uint8 * statusFlags
Definition: proc.h:333
#define TransactionIdIsValid(xid)
Definition: transam.h:41
Definition: proc.h:121

◆ GetMaxSnapshotSubxidCount()

int GetMaxSnapshotSubxidCount ( void  )

Definition at line 2037 of file procarray.c.

References TOTAL_MAX_CACHED_SUBXIDS.

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

2038 {
2039  return TOTAL_MAX_CACHED_SUBXIDS;
2040 }
#define TOTAL_MAX_CACHED_SUBXIDS

◆ GetMaxSnapshotXidCount()

int GetMaxSnapshotXidCount ( void  )

Definition at line 2026 of file procarray.c.

References ProcArrayStruct::maxProcs.

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

2027 {
2028  return procArray->maxProcs;
2029 }
static ProcArrayStruct * procArray
Definition: procarray.c:250

◆ GetOldestActiveTransactionId()

TransactionId GetOldestActiveTransactionId ( void  )

Definition at line 2839 of file procarray.c.

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

2840 {
2841  ProcArrayStruct *arrayP = procArray;
2842  TransactionId *other_xids = ProcGlobal->xids;
2843  TransactionId oldestRunningXid;
2844  int index;
2845 
2847 
2848  /*
2849  * Read nextXid, as the upper bound of what's still active.
2850  *
2851  * Reading a TransactionId is atomic, but we must grab the lock to make
2852  * sure that all XIDs < nextXid are already present in the proc array (or
2853  * have already completed), when we spin over it.
2854  */
2855  LWLockAcquire(XidGenLock, LW_SHARED);
2857  LWLockRelease(XidGenLock);
2858 
2859  /*
2860  * Spin over procArray collecting all xids and subxids.
2861  */
2862  LWLockAcquire(ProcArrayLock, LW_SHARED);
2863  for (index = 0; index < arrayP->numProcs; index++)
2864  {
2865  TransactionId xid;
2866 
2867  /* Fetch xid just once - see GetNewTransactionId */
2868  xid = UINT32_ACCESS_ONCE(other_xids[index]);
2869 
2870  if (!TransactionIdIsNormal(xid))
2871  continue;
2872 
2873  if (TransactionIdPrecedes(xid, oldestRunningXid))
2874  oldestRunningXid = xid;
2875 
2876  /*
2877  * Top-level XID of a transaction is always less than any of its
2878  * subxids, so we don't need to check if any of the subxids are
2879  * smaller than oldestRunningXid
2880  */
2881  }
2882  LWLockRelease(ProcArrayLock);
2883 
2884  return oldestRunningXid;
2885 }
uint32 TransactionId
Definition: c.h:587
#define UINT32_ACCESS_ONCE(var)
Definition: procarray.c:69
PROC_HDR * ProcGlobal
Definition: proc.c:80
bool RecoveryInProgress(void)
Definition: xlog.c:8210
FullTransactionId nextXid
Definition: transam.h:215
#define XidFromFullTransactionId(x)
Definition: transam.h:48
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
VariableCache ShmemVariableCache
Definition: varsup.c:34
TransactionId * xids
Definition: proc.h:321
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203
#define TransactionIdIsNormal(xid)
Definition: transam.h:42

◆ GetOldestNonRemovableTransactionId()

TransactionId GetOldestNonRemovableTransactionId ( Relation  rel)

Definition at line 1967 of file procarray.c.

References ComputeXidHorizonsResult::catalog_oldest_nonremovable, ComputeXidHorizons(), ComputeXidHorizonsResult::data_oldest_nonremovable, RelationData::rd_rel, RELATION_IS_LOCAL, RelationIsAccessibleInLogicalDecoding, ComputeXidHorizonsResult::shared_oldest_nonremovable, and ComputeXidHorizonsResult::temp_oldest_nonremovable.

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

1968 {
1969  ComputeXidHorizonsResult horizons;
1970 
1971  ComputeXidHorizons(&horizons);
1972 
1973  /* select horizon appropriate for relation */
1974  if (rel == NULL || rel->rd_rel->relisshared)
1975  return horizons.shared_oldest_nonremovable;
1977  return horizons.catalog_oldest_nonremovable;
1978  else if (RELATION_IS_LOCAL(rel))
1979  return horizons.temp_oldest_nonremovable;
1980  else
1981  return horizons.data_oldest_nonremovable;
1982 }
static void ComputeXidHorizons(ComputeXidHorizonsResult *h)
Definition: procarray.c:1690
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:610
Form_pg_class rd_rel
Definition: rel.h:109
TransactionId catalog_oldest_nonremovable
Definition: procarray.c:233
TransactionId shared_oldest_nonremovable
Definition: procarray.c:216
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:646
TransactionId temp_oldest_nonremovable
Definition: procarray.c:245
TransactionId data_oldest_nonremovable
Definition: procarray.c:239

◆ GetOldestSafeDecodingTransactionId()

TransactionId GetOldestSafeDecodingTransactionId ( bool  catalogOnly)

Definition at line 2904 of file procarray.c.

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

2905 {
2906  ProcArrayStruct *arrayP = procArray;
2907  TransactionId oldestSafeXid;
2908  int index;
2909  bool recovery_in_progress = RecoveryInProgress();
2910 
2911  Assert(LWLockHeldByMe(ProcArrayLock));
2912 
2913  /*
2914  * Acquire XidGenLock, so no transactions can acquire an xid while we're
2915  * running. If no transaction with xid were running concurrently a new xid
2916  * could influence the RecentXmin et al.
2917  *
2918  * We initialize the computation to nextXid since that's guaranteed to be
2919  * a safe, albeit pessimal, value.
2920  */
2921  LWLockAcquire(XidGenLock, LW_SHARED);
2923 
2924  /*
2925  * If there's already a slot pegging the xmin horizon, we can start with
2926  * that value, it's guaranteed to be safe since it's computed by this
2927  * routine initially and has been enforced since. We can always use the
2928  * slot's general xmin horizon, but the catalog horizon is only usable
2929  * when only catalog data is going to be looked at.
2930  */
2933  oldestSafeXid))
2934  oldestSafeXid = procArray->replication_slot_xmin;
2935 
2936  if (catalogOnly &&
2939  oldestSafeXid))
2940  oldestSafeXid = procArray->replication_slot_catalog_xmin;
2941 
2942  /*
2943  * If we're not in recovery, we walk over the procarray and collect the
2944  * lowest xid. Since we're called with ProcArrayLock held and have
2945  * acquired XidGenLock, no entries can vanish concurrently, since
2946  * ProcGlobal->xids[i] is only set with XidGenLock held and only cleared
2947  * with ProcArrayLock held.
2948  *
2949  * In recovery we can't lower the safe value besides what we've computed
2950  * above, so we'll have to wait a bit longer there. We unfortunately can
2951  * *not* use KnownAssignedXidsGetOldestXmin() since the KnownAssignedXids
2952  * machinery can miss values and return an older value than is safe.
2953  */
2954  if (!recovery_in_progress)
2955  {
2956  TransactionId *other_xids = ProcGlobal->xids;
2957 
2958  /*
2959  * Spin over procArray collecting min(ProcGlobal->xids[i])
2960  */
2961  for (index = 0; index < arrayP->numProcs; index++)
2962  {
2963  TransactionId xid;
2964 
2965  /* Fetch xid just once - see GetNewTransactionId */
2966  xid = UINT32_ACCESS_ONCE(other_xids[index]);
2967 
2968  if (!TransactionIdIsNormal(xid))
2969  continue;
2970 
2971  if (TransactionIdPrecedes(xid, oldestSafeXid))
2972  oldestSafeXid = xid;
2973  }
2974  }
2975 
2976  LWLockRelease(XidGenLock);
2977 
2978  return oldestSafeXid;
2979 }
uint32 TransactionId
Definition: c.h:587
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1932
#define UINT32_ACCESS_ONCE(var)
Definition: procarray.c:69
TransactionId replication_slot_catalog_xmin
Definition: procarray.c:98
PROC_HDR * ProcGlobal
Definition: proc.c:80
bool RecoveryInProgress(void)
Definition: xlog.c:8210
FullTransactionId nextXid
Definition: transam.h:215
#define XidFromFullTransactionId(x)
Definition: transam.h:48
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
VariableCache ShmemVariableCache
Definition: varsup.c:34
TransactionId * xids
Definition: proc.h:321
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
static ProcArrayStruct * procArray
Definition: procarray.c:250
TransactionId replication_slot_xmin
Definition: procarray.c:96
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define TransactionIdIsNormal(xid)
Definition: transam.h:42

◆ GetOldestTransactionIdConsideredRunning()

TransactionId GetOldestTransactionIdConsideredRunning ( void  )

Definition at line 1991 of file procarray.c.

References ComputeXidHorizons(), and ComputeXidHorizonsResult::oldest_considered_running.

Referenced by CreateCheckPoint(), and CreateRestartPoint().

1992 {
1993  ComputeXidHorizonsResult horizons;
1994 
1995  ComputeXidHorizons(&horizons);
1996 
1997  return horizons.oldest_considered_running;
1998 }
TransactionId oldest_considered_running
Definition: procarray.c:207
static void ComputeXidHorizons(ComputeXidHorizonsResult *h)
Definition: procarray.c:1690

◆ GetReplicationHorizons()

void GetReplicationHorizons ( TransactionId xmin,
TransactionId catalog_xmin 
)

Definition at line 2004 of file procarray.c.

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

Referenced by XLogWalRcvSendHSFeedback().

2005 {
2006  ComputeXidHorizonsResult horizons;
2007 
2008  ComputeXidHorizons(&horizons);
2009 
2010  /*
2011  * Don't want to use shared_oldest_nonremovable here, as that contains the
2012  * effect of replication slot's catalog_xmin. We want to send a separate
2013  * feedback for the catalog horizon, so the primary can remove data table
2014  * contents more aggressively.
2015  */
2016  *xmin = horizons.shared_oldest_nonremovable_raw;
2017  *catalog_xmin = horizons.slot_catalog_xmin;
2018 }
static void ComputeXidHorizons(ComputeXidHorizonsResult *h)
Definition: procarray.c:1690
TransactionId shared_oldest_nonremovable_raw
Definition: procarray.c:227
TransactionId slot_catalog_xmin
Definition: procarray.c:194

◆ GetRunningTransactionData()

RunningTransactions GetRunningTransactionData ( void  )

Definition at line 2664 of file procarray.c.

References Assert, XidCacheStatus::count, ereport, errcode(), errmsg(), ERROR, RunningTransactionsData::latestCompletedXid, VariableCacheData::latestCompletedXid, LW_SHARED, LWLockAcquire(), malloc, RunningTransactionsData::nextXid, VariableCacheData::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, RunningTransactionsData::xids, and PROC_HDR::xids.

Referenced by LogStandbySnapshot().

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

◆ GetSnapshotData()

Snapshot GetSnapshotData ( Snapshot  snapshot)

Definition at line 2163 of file procarray.c.

References SnapshotData::active_count, Assert, SnapshotData::copied, XidCacheStatus::count, SnapshotData::curcid, GlobalVisState::definitely_needed, ereport, errcode(), errmsg(), ERROR, FullTransactionIdAdvance(), FullTransactionIdNewer(), FullXidRelativeTo(), GetCurrentCommandId(), GetMaxSnapshotSubxidCount(), GetMaxSnapshotXidCount(), GetSnapshotDataInitOldSnapshot(), GetSnapshotDataReuse(), 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().

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

◆ GetSnapshotDataInitOldSnapshot()

static void GetSnapshotDataInitOldSnapshot ( Snapshot  snapshot)
static

Definition at line 2046 of file procarray.c.

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

Referenced by GetSnapshotData(), and GetSnapshotDataReuse().

2047 {
2049  {
2050  /*
2051  * If not using "snapshot too old" feature, fill related fields with
2052  * dummy values that don't require any locking.
2053  */
2054  snapshot->lsn = InvalidXLogRecPtr;
2055  snapshot->whenTaken = 0;
2056  }
2057  else
2058  {
2059  /*
2060  * Capture the current time and WAL stream location in case this
2061  * snapshot becomes old enough to need to fall back on the special
2062  * "old snapshot" logic.
2063  */
2064  snapshot->lsn = GetXLogInsertRecPtr();
2065  snapshot->whenTaken = GetSnapshotCurrentTimestamp();
2066  MaintainOldSnapshotTimeMapping(snapshot->whenTaken, snapshot->xmin);
2067  }
2068 }
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28
static bool OldSnapshotThresholdActive(void)
Definition: snapmgr.h:101
XLogRecPtr lsn
Definition: snapshot.h:209
TimestampTz GetSnapshotCurrentTimestamp(void)
Definition: snapmgr.c:1635
XLogRecPtr GetXLogInsertRecPtr(void)
Definition: xlog.c:11720
TransactionId xmin
Definition: snapshot.h:157
TimestampTz whenTaken
Definition: snapshot.h:208
void MaintainOldSnapshotTimeMapping(TimestampTz whenTaken, TransactionId xmin)
Definition: snapmgr.c:1858

◆ GetSnapshotDataReuse()

static bool GetSnapshotDataReuse ( Snapshot  snapshot)
static

Definition at line 2080 of file procarray.c.

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

2081 {
2082  uint64 curXactCompletionCount;
2083 
2084  Assert(LWLockHeldByMe(ProcArrayLock));
2085 
2086  if (unlikely(snapshot->snapXactCompletionCount == 0))
2087  return false;
2088 
2089  curXactCompletionCount = ShmemVariableCache->xactCompletionCount;
2090  if (curXactCompletionCount != snapshot->snapXactCompletionCount)
2091  return false;
2092 
2093  /*
2094  * If the current xactCompletionCount is still the same as it was at the
2095  * time the snapshot was built, we can be sure that rebuilding the
2096  * contents of the snapshot the hard way would result in the same snapshot
2097  * contents:
2098  *
2099  * As explained in transam/README, the set of xids considered running by
2100  * GetSnapshotData() cannot change while ProcArrayLock is held. Snapshot
2101  * contents only depend on transactions with xids and xactCompletionCount
2102  * is incremented whenever a transaction with an xid finishes (while
2103  * holding ProcArrayLock) exclusively). Thus the xactCompletionCount check
2104  * ensures we would detect if the snapshot would have changed.
2105  *
2106  * As the snapshot contents are the same as it was before, it is safe to
2107  * re-enter the snapshot's xmin into the PGPROC array. None of the rows
2108  * visible under the snapshot could already have been removed (that'd
2109  * require the set of running transactions to change) and it fulfills the
2110  * requirement that concurrent GetSnapshotData() calls yield the same
2111  * xmin.
2112  */
2114  MyProc->xmin = TransactionXmin = snapshot->xmin;
2115 
2116  RecentXmin = snapshot->xmin;
2118 
2119  snapshot->curcid = GetCurrentCommandId(false);
2120  snapshot->active_count = 0;
2121  snapshot->regd_count = 0;
2122  snapshot->copied = false;
2123 
2125 
2126  return true;
2127 }
uint64 snapXactCompletionCount
Definition: snapshot.h:216
bool copied
Definition: snapshot.h:185
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1932
PGPROC * MyProc
Definition: proc.c:68
TransactionId RecentXmin
Definition: snapmgr.c:113
uint64 xactCompletionCount
Definition: transam.h:243
uint32 regd_count
Definition: snapshot.h:205
TransactionId TransactionXmin
Definition: snapmgr.c:112
static void GetSnapshotDataInitOldSnapshot(Snapshot snapshot)
Definition: procarray.c:2046
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:319
TransactionId xmin
Definition: proc.h:138
VariableCache ShmemVariableCache
Definition: varsup.c:34
TransactionId xmin
Definition: snapshot.h:157
CommandId curcid
Definition: snapshot.h:187
#define Assert(condition)
Definition: c.h:804
#define unlikely(x)
Definition: c.h:273
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:761
#define TransactionIdIsValid(xid)
Definition: transam.h:41
uint32 active_count
Definition: snapshot.h:204

◆ GetVirtualXIDsDelayingChkpt()

VirtualTransactionId* GetVirtualXIDsDelayingChkpt ( int *  nvxids)

Definition at line 3000 of file procarray.c.

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

Referenced by CreateCheckPoint().

3001 {
3002  VirtualTransactionId *vxids;
3003  ProcArrayStruct *arrayP = procArray;
3004  int count = 0;
3005  int index;
3006 
3007  /* allocate what's certainly enough result space */
3008  vxids = (VirtualTransactionId *)
3009  palloc(sizeof(VirtualTransactionId) * arrayP->maxProcs);
3010 
3011  LWLockAcquire(ProcArrayLock, LW_SHARED);
3012 
3013  for (index = 0; index < arrayP->numProcs; index++)
3014  {
3015  int pgprocno = arrayP->pgprocnos[index];
3016  PGPROC *proc = &allProcs[pgprocno];
3017 
3018  if (proc->delayChkpt)
3019  {
3020  VirtualTransactionId vxid;
3021 
3022  GET_VXID_FROM_PGPROC(vxid, *proc);
3023  if (VirtualTransactionIdIsValid(vxid))
3024  vxids[count++] = vxid;
3025  }
3026  }
3027 
3028  LWLockRelease(ProcArrayLock);
3029 
3030  *nvxids = count;
3031  return vxids;
3032 }
#define GET_VXID_FROM_PGPROC(vxid, proc)
Definition: lock.h:81
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
bool delayChkpt
Definition: proc.h:187
static PGPROC * allProcs
Definition: procarray.c:252
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define VirtualTransactionIdIsValid(vxid)
Definition: lock.h:71
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203
void * palloc(Size size)
Definition: mcxt.c:1062
Definition: proc.h:121

◆ GlobalVisCheckRemovableFullXid()

bool GlobalVisCheckRemovableFullXid ( Relation  rel,
FullTransactionId  fxid 
)

Definition at line 4206 of file procarray.c.

References GlobalVisTestFor(), and GlobalVisTestIsRemovableFullXid().

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

4207 {
4209 
4210  state = GlobalVisTestFor(rel);
4211 
4212  return GlobalVisTestIsRemovableFullXid(state, fxid);
4213 }
bool GlobalVisTestIsRemovableFullXid(GlobalVisState *state, FullTransactionId fxid)
Definition: procarray.c:4112
GlobalVisState * GlobalVisTestFor(Relation rel)
Definition: procarray.c:3986
Definition: regguts.h:317

◆ GlobalVisCheckRemovableXid()

bool GlobalVisCheckRemovableXid ( Relation  rel,
TransactionId  xid 
)

Definition at line 4220 of file procarray.c.

References GlobalVisTestFor(), and GlobalVisTestIsRemovableXid().

Referenced by GinPageIsRecyclable().

4221 {
4223 
4224  state = GlobalVisTestFor(rel);
4225 
4226  return GlobalVisTestIsRemovableXid(state, xid);
4227 }
bool GlobalVisTestIsRemovableXid(GlobalVisState *state, TransactionId xid)
Definition: procarray.c:4154
GlobalVisState * GlobalVisTestFor(Relation rel)
Definition: procarray.c:3986
Definition: regguts.h:317

◆ GlobalVisTestFor()

GlobalVisState* GlobalVisTestFor ( Relation  rel)

Definition at line 3986 of file procarray.c.

References Assert, GlobalVisState::definitely_needed, FullTransactionIdIsValid, GlobalVisCatalogRels, GlobalVisDataRels, GlobalVisSharedRels, GlobalVisTempRels, IsCatalogRelation(), GlobalVisState::maybe_needed, RelationData::rd_rel, RecentXmin, RecoveryInProgress(), RELATION_IS_LOCAL, and RelationIsAccessibleInLogicalDecoding.

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

3987 {
3988  bool need_shared;
3989  bool need_catalog;
3991 
3992  /* XXX: we should assert that a snapshot is pushed or registered */
3993  Assert(RecentXmin);
3994 
3995  if (!rel)
3996  need_shared = need_catalog = true;
3997  else
3998  {
3999  /*
4000  * Other kinds currently don't contain xids, nor always the necessary
4001  * logical decoding markers.
4002  */
4003  Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
4004  rel->rd_rel->relkind == RELKIND_MATVIEW ||
4005  rel->rd_rel->relkind == RELKIND_TOASTVALUE);
4006 
4007  need_shared = rel->rd_rel->relisshared || RecoveryInProgress();
4008  need_catalog = IsCatalogRelation(rel) || RelationIsAccessibleInLogicalDecoding(rel);
4009  }
4010 
4011  if (need_shared)
4012  state = &GlobalVisSharedRels;
4013  else if (need_catalog)
4014  state = &GlobalVisCatalogRels;
4015  else if (RELATION_IS_LOCAL(rel))
4016  state = &GlobalVisTempRels;
4017  else
4018  state = &GlobalVisDataRels;
4019 
4022 
4023  return state;
4024 }
bool IsCatalogRelation(Relation relation)
Definition: catalog.c:103
#define FullTransactionIdIsValid(x)
Definition: transam.h:55
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:610
TransactionId RecentXmin
Definition: snapmgr.c:113
Form_pg_class rd_rel
Definition: rel.h:109
bool RecoveryInProgress(void)
Definition: xlog.c:8210
FullTransactionId definitely_needed
Definition: procarray.c:172
static GlobalVisState GlobalVisSharedRels
Definition: procarray.c:273
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:646
#define Assert(condition)
Definition: c.h:804
Definition: regguts.h:317
FullTransactionId maybe_needed
Definition: procarray.c:175
static GlobalVisState GlobalVisTempRels
Definition: procarray.c:276
static GlobalVisState GlobalVisCatalogRels
Definition: procarray.c:274
static GlobalVisState GlobalVisDataRels
Definition: procarray.c:275

◆ GlobalVisTestIsRemovableFullXid()

bool GlobalVisTestIsRemovableFullXid ( GlobalVisState state,
FullTransactionId  fxid 
)

Definition at line 4112 of file procarray.c.

References Assert, GlobalVisState::definitely_needed, FullTransactionIdFollowsOrEquals, FullTransactionIdPrecedes, GlobalVisTestShouldUpdate(), GlobalVisUpdate(), and GlobalVisState::maybe_needed.

Referenced by GlobalVisCheckRemovableFullXid(), and GlobalVisTestIsRemovableXid().

4114 {
4115  /*
4116  * If fxid is older than maybe_needed bound, it definitely is visible to
4117  * everyone.
4118  */
4119  if (FullTransactionIdPrecedes(fxid, state->maybe_needed))
4120  return true;
4121 
4122  /*
4123  * If fxid is >= definitely_needed bound, it is very likely to still be
4124  * considered running.
4125  */
4127  return false;
4128 
4129  /*
4130  * fxid is between maybe_needed and definitely_needed, i.e. there might or
4131  * might not exist a snapshot considering fxid running. If it makes sense,
4132  * update boundaries and recheck.
4133  */
4134  if (GlobalVisTestShouldUpdate(state))
4135  {
4136  GlobalVisUpdate();
4137 
4139 
4140  return FullTransactionIdPrecedes(fxid, state->maybe_needed);
4141  }
4142  else
4143  return false;
4144 }
FullTransactionId definitely_needed
Definition: procarray.c:172
static bool GlobalVisTestShouldUpdate(GlobalVisState *state)
Definition: procarray.c:4037
#define Assert(condition)
Definition: c.h:804
#define FullTransactionIdFollowsOrEquals(a, b)
Definition: transam.h:54
FullTransactionId maybe_needed
Definition: procarray.c:175
#define FullTransactionIdPrecedes(a, b)
Definition: transam.h:51
static void GlobalVisUpdate(void)
Definition: procarray.c:4095

◆ GlobalVisTestIsRemovableXid()

bool GlobalVisTestIsRemovableXid ( GlobalVisState state,
TransactionId  xid 
)

Definition at line 4154 of file procarray.c.

References GlobalVisState::definitely_needed, FullXidRelativeTo(), and GlobalVisTestIsRemovableFullXid().

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

4155 {
4156  FullTransactionId fxid;
4157 
4158  /*
4159  * Convert 32 bit argument to FullTransactionId. We can do so safely
4160  * because we know the xid has to, at the very least, be between
4161  * [oldestXid, nextFullXid), i.e. within 2 billion of xid. To avoid taking
4162  * a lock to determine either, we can just compare with
4163  * state->definitely_needed, which was based on those value at the time
4164  * the current snapshot was built.
4165  */
4166  fxid = FullXidRelativeTo(state->definitely_needed, xid);
4167 
4168  return GlobalVisTestIsRemovableFullXid(state, fxid);
4169 }
static FullTransactionId FullXidRelativeTo(FullTransactionId rel, TransactionId xid)
Definition: procarray.c:4241
bool GlobalVisTestIsRemovableFullXid(GlobalVisState *state, FullTransactionId fxid)
Definition: procarray.c:4112
FullTransactionId definitely_needed
Definition: procarray.c:172

◆ GlobalVisTestNonRemovableFullHorizon()

FullTransactionId GlobalVisTestNonRemovableFullHorizon ( GlobalVisState state)

Definition at line 4181 of file procarray.c.

References GlobalVisTestShouldUpdate(), GlobalVisUpdate(), and GlobalVisState::maybe_needed.

Referenced by GlobalVisTestNonRemovableHorizon().

4182 {
4183  /* acquire accurate horizon if not already done */
4184  if (GlobalVisTestShouldUpdate(state))
4185  GlobalVisUpdate();
4186 
4187  return state->maybe_needed;
4188 }
static bool GlobalVisTestShouldUpdate(GlobalVisState *state)
Definition: procarray.c:4037
FullTransactionId maybe_needed
Definition: procarray.c:175
static void GlobalVisUpdate(void)
Definition: procarray.c:4095

◆ GlobalVisTestNonRemovableHorizon()

TransactionId GlobalVisTestNonRemovableHorizon ( GlobalVisState state)

Definition at line 4192 of file procarray.c.

References GlobalVisTestNonRemovableFullHorizon(), and XidFromFullTransactionId.

Referenced by heap_page_prune_opt(), and heap_prune_satisfies_vacuum().

4193 {
4194  FullTransactionId cutoff;
4195 
4196  cutoff = GlobalVisTestNonRemovableFullHorizon(state);
4197 
4198  return XidFromFullTransactionId(cutoff);
4199 }
#define XidFromFullTransactionId(x)
Definition: transam.h:48
FullTransactionId GlobalVisTestNonRemovableFullHorizon(GlobalVisState *state)
Definition: procarray.c:4181

◆ GlobalVisTestShouldUpdate()

static bool GlobalVisTestShouldUpdate ( GlobalVisState state)
static

Definition at line 4037 of file procarray.c.

References ComputeXidHorizonsResultLastXmin, GlobalVisState::definitely_needed, FullTransactionIdFollowsOrEquals, GlobalVisState::maybe_needed, RecentXmin, and TransactionIdIsValid.

Referenced by GlobalVisTestIsRemovableFullXid(), and GlobalVisTestNonRemovableFullHorizon().

4038 {
4039  /* hasn't been updated yet */
4041  return true;
4042 
4043  /*
4044  * If the maybe_needed/definitely_needed boundaries are the same, it's
4045  * unlikely to be beneficial to refresh boundaries.
4046  */
4048  state->definitely_needed))
4049  return false;
4050 
4051  /* does the last snapshot built have a different xmin? */
4053 }
TransactionId RecentXmin
Definition: snapmgr.c:113
FullTransactionId definitely_needed
Definition: procarray.c:172
static TransactionId ComputeXidHorizonsResultLastXmin
Definition: procarray.c:283
#define FullTransactionIdFollowsOrEquals(a, b)
Definition: transam.h:54
FullTransactionId maybe_needed
Definition: procarray.c:175
#define TransactionIdIsValid(xid)
Definition: transam.h:41

◆ GlobalVisUpdate()

static void GlobalVisUpdate ( void  )
static

Definition at line 4095 of file procarray.c.

References ComputeXidHorizons().

Referenced by GlobalVisTestIsRemovableFullXid(), and GlobalVisTestNonRemovableFullHorizon().

4096 {
4097  ComputeXidHorizonsResult horizons;
4098 
4099  /* updates the horizons as a side-effect */
4100  ComputeXidHorizons(&horizons);
4101 }
static void ComputeXidHorizons(ComputeXidHorizonsResult *h)
Definition: procarray.c:1690

◆ GlobalVisUpdateApply()

static void GlobalVisUpdateApply ( ComputeXidHorizonsResult horizons)
static

Definition at line 4056 of file procarray.c.

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

Referenced by ComputeXidHorizons().

4057 {
4060  horizons->shared_oldest_nonremovable);
4063  horizons->catalog_oldest_nonremovable);
4066  horizons->data_oldest_nonremovable);
4069  horizons->temp_oldest_nonremovable);
4070 
4071  /*
4072  * In longer running transactions it's possible that transactions we
4073  * previously needed to treat as running aren't around anymore. So update
4074  * definitely_needed to not be earlier than maybe_needed.
4075  */
4086 
4088 }
FullTransactionId latest_completed
Definition: procarray.c:187
static FullTransactionId FullXidRelativeTo(FullTransactionId rel, TransactionId xid)
Definition: procarray.c:4241
TransactionId RecentXmin
Definition: snapmgr.c:113
TransactionId catalog_oldest_nonremovable
Definition: procarray.c:233
FullTransactionId definitely_needed
Definition: procarray.c:172
static GlobalVisState GlobalVisSharedRels
Definition: procarray.c:273
TransactionId shared_oldest_nonremovable
Definition: procarray.c:216
static TransactionId ComputeXidHorizonsResultLastXmin
Definition: procarray.c:283
TransactionId temp_oldest_nonremovable
Definition: procarray.c:245
FullTransactionId maybe_needed
Definition: procarray.c:175
static FullTransactionId FullTransactionIdNewer(FullTransactionId a, FullTransactionId b)
Definition: transam.h:355
static GlobalVisState GlobalVisTempRels
Definition: procarray.c:276
TransactionId data_oldest_nonremovable
Definition: procarray.c:239
static GlobalVisState GlobalVisCatalogRels
Definition: procarray.c:274
static GlobalVisState GlobalVisDataRels
Definition: procarray.c:275

◆ HaveVirtualXIDsDelayingChkpt()

bool HaveVirtualXIDsDelayingChkpt ( VirtualTransactionId vxids,
int  nvxids 
)

Definition at line 3044 of file procarray.c.

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

Referenced by CreateCheckPoint().

3045 {
3046  bool result = false;
3047  ProcArrayStruct *arrayP = procArray;
3048  int index;
3049 
3050  LWLockAcquire(ProcArrayLock, LW_SHARED);
3051 
3052  for (index = 0; index < arrayP->numProcs; index++)
3053  {
3054  int pgprocno = arrayP->pgprocnos[index];
3055  PGPROC *proc = &allProcs[pgprocno];
3056  VirtualTransactionId vxid;
3057 
3058  GET_VXID_FROM_PGPROC(vxid, *proc);
3059 
3060  if (proc->delayChkpt && VirtualTransactionIdIsValid(vxid))
3061  {
3062  int i;
3063 
3064  for (i = 0; i < nvxids; i++)
3065  {
3066  if (VirtualTransactionIdEquals(vxid, vxids[i]))
3067  {
3068  result = true;
3069  break;
3070  }
3071  }
3072  if (result)
3073  break;
3074  }
3075  }
3076 
3077  LWLockRelease(ProcArrayLock);
3078 
3079  return result;
3080 }
#define GET_VXID_FROM_PGPROC(vxid, proc)
Definition: lock.h:81
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
#define VirtualTransactionIdEquals(vxid1, vxid2)
Definition: lock.h:75
bool delayChkpt
Definition: proc.h:187
static PGPROC * allProcs
Definition: procarray.c:252
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define VirtualTransactionIdIsValid(vxid)
Definition: lock.h:71
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203
int i
Definition: proc.h:121

◆ IsBackendPid()

bool IsBackendPid ( int  pid)

Definition at line 3185 of file procarray.c.

References BackendPidGetProc().

Referenced by pg_stat_get_subscription().

3186 {
3187  return (BackendPidGetProc(pid) != NULL);
3188 }
PGPROC * BackendPidGetProc(int pid)
Definition: procarray.c:3090

◆ KnownAssignedXidExists()

static bool KnownAssignedXidExists ( TransactionId  xid)
static

Definition at line 4808 of file procarray.c.

References Assert, KnownAssignedXidsSearch(), and TransactionIdIsValid.

Referenced by TransactionIdIsInProgress().

4809 {
4811 
4812  return KnownAssignedXidsSearch(xid, false);
4813 }
#define Assert(condition)
Definition: c.h:804
static bool KnownAssignedXidsSearch(TransactionId xid, bool remove)
Definition: procarray.c:4715
#define TransactionIdIsValid(xid)
Definition: transam.h:41

◆ KnownAssignedXidsAdd()

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

Definition at line 4597 of file procarray.c.

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

4599 {
4600  ProcArrayStruct *pArray = procArray;
4601  TransactionId next_xid;
4602  int head,
4603  tail;
4604  int nxids;
4605  int i;
4606 
4607  Assert(TransactionIdPrecedesOrEquals(from_xid, to_xid));
4608 
4609  /*
4610  * Calculate how many array slots we'll need. Normally this is cheap; in
4611  * the unusual case where the XIDs cross the wrap point, we do it the hard
4612  * way.
4613  */
4614  if (to_xid >= from_xid)
4615  nxids = to_xid - from_xid + 1;
4616  else
4617  {
4618  nxids = 1;
4619  next_xid = from_xid;
4620  while (TransactionIdPrecedes(next_xid, to_xid))
4621  {
4622  nxids++;
4623  TransactionIdAdvance(next_xid);
4624  }
4625  }
4626 
4627  /*
4628  * Since only the startup process modifies the head/tail pointers, we
4629  * don't need a lock to read them here.
4630  */
4631  head = pArray->headKnownAssignedXids;
4632  tail = pArray->tailKnownAssignedXids;
4633 
4634  Assert(head >= 0 && head <= pArray->maxKnownAssignedXids);
4635  Assert(tail >= 0 && tail < pArray->maxKnownAssignedXids);
4636 
4637  /*
4638  * Verify that insertions occur in TransactionId sequence. Note that even
4639  * if the last existing element is marked invalid, it must still have a
4640  * correctly sequenced XID value.
4641  */
4642  if (head > tail &&
4643  TransactionIdFollowsOrEquals(KnownAssignedXids[head - 1], from_xid))
4644  {
4646  elog(ERROR, "out-of-order XID insertion in KnownAssignedXids");
4647  }
4648 
4649  /*
4650  * If our xids won't fit in the remaining space, compress out free space
4651  */
4652  if (head + nxids > pArray->maxKnownAssignedXids)
4653  {
4654  /* must hold lock to compress */
4655  if (!exclusive_lock)
4656  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4657 
4659 
4660  head = pArray->headKnownAssignedXids;
4661  /* note: we no longer care about the tail pointer */
4662 
4663  if (!exclusive_lock)
4664  LWLockRelease(ProcArrayLock);
4665 
4666  /*
4667  * If it still won't fit then we're out of memory
4668  */
4669  if (head + nxids > pArray->maxKnownAssignedXids)
4670  elog(ERROR, "too many KnownAssignedXids");
4671  }
4672 
4673  /* Now we can insert the xids into the space starting at head */
4674  next_xid = from_xid;
4675  for (i = 0; i < nxids; i++)
4676  {
4677  KnownAssignedXids[head] = next_xid;
4678  KnownAssignedXidsValid[head] = true;
4679  TransactionIdAdvance(next_xid);
4680  head++;
4681  }
4682 
4683  /* Adjust count of number of valid entries */
4684  pArray->numKnownAssignedXids += nxids;
4685 
4686  /*
4687  * Now update the head pointer. We use a spinlock to protect this
4688  * pointer, not because the update is likely to be non-atomic, but to
4689  * ensure that other processors see the above array updates before they
4690  * see the head pointer change.
4691  *
4692  * If we're holding ProcArrayLock exclusively, there's no need to take the
4693  * spinlock.
4694  */
4695  if (exclusive_lock)
4696  pArray->headKnownAssignedXids = head;
4697  else
4698  {
4700  pArray->headKnownAssignedXids = head;
4702  }
4703 }
#define TransactionIdAdvance(dest)
Definition: transam.h:91
static void KnownAssignedXidsDisplay(int trace_level)
Definition: procarray.c:5054
uint32 TransactionId
Definition: c.h:587
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:349
slock_t known_assigned_xids_lck
Definition: procarray.c:84
#define LOG
Definition: elog.h:26
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
#define SpinLockAcquire(lock)
Definition: spin.h:62
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:319
#define ERROR
Definition: elog.h:46
int maxKnownAssignedXids
Definition: procarray.c:80
int numKnownAssignedXids
Definition: procarray.c:81
static bool * KnownAssignedXidsValid
Definition: procarray.c:258
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define SpinLockRelease(lock)
Definition: spin.h:64
#define Assert(condition)
Definition: c.h:804
static TransactionId * KnownAssignedXids
Definition: procarray.c:257
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203
static void KnownAssignedXidsCompress(bool force)
Definition: procarray.c:4535
#define elog(elevel,...)
Definition: elog.h:232
int i
int tailKnownAssignedXids
Definition: procarray.c:82
int headKnownAssignedXids
Definition: procarray.c:83

◆ KnownAssignedXidsCompress()

static void KnownAssignedXidsCompress ( bool  force)
static

Definition at line 4535 of file procarray.c.

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

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

4536 {
4537  ProcArrayStruct *pArray = procArray;
4538  int head,
4539  tail;
4540  int compress_index;
4541  int i;
4542 
4543  /* no spinlock required since we hold ProcArrayLock exclusively */
4544  head = pArray->headKnownAssignedXids;
4545  tail = pArray->tailKnownAssignedXids;
4546 
4547  if (!force)
4548  {
4549  /*
4550  * If we can choose how much to compress, use a heuristic to avoid
4551  * compressing too often or not often enough.
4552  *
4553  * Heuristic is if we have a large enough current spread and less than
4554  * 50% of the elements are currently in use, then compress. This
4555  * should ensure we compress fairly infrequently. We could compress
4556  * less often though the virtual array would spread out more and
4557  * snapshots would become more expensive.
4558  */
4559  int nelements = head - tail;
4560 
4561  if (nelements < 4 * PROCARRAY_MAXPROCS ||
4562  nelements < 2 * pArray->numKnownAssignedXids)
4563  return;
4564  }
4565 
4566  /*
4567  * We compress the array by reading the valid values from tail to head,
4568  * re-aligning data to 0th element.
4569  */
4570  compress_index = 0;
4571  for (i = tail; i < head; i++)
4572  {
4573  if (KnownAssignedXidsValid[i])
4574  {
4575  KnownAssignedXids[compress_index] = KnownAssignedXids[i];
4576  KnownAssignedXidsValid[compress_index] = true;
4577  compress_index++;
4578  }
4579  }
4580 
4581  pArray->tailKnownAssignedXids = 0;
4582  pArray->headKnownAssignedXids = compress_index;
4583 }
#define PROCARRAY_MAXPROCS
static bool * KnownAssignedXidsValid
Definition: procarray.c:258
static ProcArrayStruct * procArray
Definition: procarray.c:250
static TransactionId * KnownAssignedXids
Definition: procarray.c:257
int i
int tailKnownAssignedXids
Definition: procarray.c:82
int headKnownAssignedXids
Definition: procarray.c:83

◆ KnownAssignedXidsDisplay()

static void KnownAssignedXidsDisplay ( int  trace_level)
static

Definition at line 5054 of file procarray.c.

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

Referenced by KnownAssignedXidsAdd(), and ProcArrayApplyRecoveryInfo().

5055 {
5056  ProcArrayStruct *pArray = procArray;
5058  int head,
5059  tail,
5060  i;
5061  int nxids = 0;
5062 
5063  tail = pArray->tailKnownAssignedXids;
5064  head = pArray->headKnownAssignedXids;
5065 
5066  initStringInfo(&buf);
5067 
5068  for (i = tail; i < head; i++)
5069  {
5070  if (KnownAssignedXidsValid[i])
5071  {
5072  nxids++;
5073  appendStringInfo(&buf, "[%d]=%u ", i, KnownAssignedXids[i]);
5074  }
5075  }
5076 
5077  elog(trace_level, "%d KnownAssignedXids (num=%d tail=%d head=%d) %s",
5078  nxids,
5079  pArray->numKnownAssignedXids,
5080  pArray->tailKnownAssignedXids,
5081  pArray->headKnownAssignedXids,
5082  buf.data);
5083 
5084  pfree(buf.data);
5085 }
void pfree(void *pointer)
Definition: mcxt.c:1169
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
static char * buf
Definition: pg_test_fsync.c:68
int numKnownAssignedXids
Definition: procarray.c:81
static bool * KnownAssignedXidsValid
Definition: procarray.c:258
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
static ProcArrayStruct * procArray
Definition: procarray.c:250
static TransactionId * KnownAssignedXids
Definition: procarray.c:257
#define elog(elevel,...)
Definition: elog.h:232
int i
int tailKnownAssignedXids
Definition: procarray.c:82
int headKnownAssignedXids
Definition: procarray.c:83

◆ KnownAssignedXidsGet()

static int KnownAssignedXidsGet ( TransactionId xarray,
TransactionId  xmax 
)
static

Definition at line 4947 of file procarray.c.

References InvalidTransactionId, and KnownAssignedXidsGetAndSetXmin().

Referenced by TransactionIdIsInProgress().

4948 {
4950 
4951  return KnownAssignedXidsGetAndSetXmin(xarray, &xtmp, xmax);
4952 }
uint32 TransactionId
Definition: c.h:587
#define InvalidTransactionId
Definition: transam.h:31
static int KnownAssignedXidsGetAndSetXmin(TransactionId *xarray, TransactionId *xmin, TransactionId xmax)
Definition: procarray.c:4961

◆ KnownAssignedXidsGetAndSetXmin()

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

Definition at line 4961 of file procarray.c.

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

Referenced by GetSnapshotData(), and KnownAssignedXidsGet().

4963 {
4964  int count = 0;
4965  int head,
4966  tail;
4967  int i;
4968 
4969  /*
4970  * Fetch head just once, since it may change while we loop. We can stop
4971  * once we reach the initially seen head, since we are certain that an xid
4972  * cannot enter and then leave the array while we hold ProcArrayLock. We
4973  * might miss newly-added xids, but they should be >= xmax so irrelevant
4974  * anyway.
4975  *
4976  * Must take spinlock to ensure we see up-to-date array contents.
4977  */
4982 
4983  for (i = tail; i < head; i++)
4984  {
4985  /* Skip any gaps in the array */
4986  if (KnownAssignedXidsValid[i])
4987  {
4988  TransactionId knownXid = KnownAssignedXids[i];
4989 
4990  /*
4991  * Update xmin if required. Only the first XID need be checked,
4992  * since the array is sorted.
4993  */
4994  if (count == 0 &&
4995  TransactionIdPrecedes(knownXid, *xmin))
4996  *xmin = knownXid;
4997 
4998  /*
4999  * Filter out anything >= xmax, again relying on sorted property
5000  * of array.
5001  */
5002  if (TransactionIdIsValid(xmax) &&
5003  TransactionIdFollowsOrEquals(knownXid, xmax))
5004  break;
5005 
5006  /* Add knownXid into output array */
5007  xarray[count++] = knownXid;
5008  }
5009  }
5010 
5011  return count;
5012 }
uint32 TransactionId
Definition: c.h:587
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:349
slock_t known_assigned_xids_lck
Definition: procarray.c:84
#define SpinLockAcquire(lock)
Definition: spin.h:62
static bool * KnownAssignedXidsValid
Definition: procarray.c:258
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define SpinLockRelease(lock)
Definition: spin.h:64
static TransactionId * KnownAssignedXids
Definition: procarray.c:257
int i
#define TransactionIdIsValid(xid)
Definition: transam.h:41
int tailKnownAssignedXids
Definition: procarray.c:82
int headKnownAssignedXids
Definition: procarray.c:83

◆ KnownAssignedXidsGetOldestXmin()

static TransactionId KnownAssignedXidsGetOldestXmin ( void  )
static

Definition at line 5019 of file procarray.c.

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

Referenced by ComputeXidHorizons().

5020 {
5021  int head,
5022  tail;
5023  int i;
5024 
5025  /*
5026  * Fetch head just once, since it may change while we loop.
5027  */
5032 
5033  for (i = tail; i < head; i++)
5034  {
5035  /* Skip any gaps in the array */
5036  if (KnownAssignedXidsValid[i])
5037  return KnownAssignedXids[i];
5038  }
5039 
5040  return InvalidTransactionId;
5041 }
slock_t known_assigned_xids_lck
Definition: procarray.c:84
#define SpinLockAcquire(lock)
Definition: spin.h:62
#define InvalidTransactionId
Definition: transam.h:31
static bool * KnownAssignedXidsValid
Definition: procarray.c:258
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define SpinLockRelease(lock)
Definition: spin.h:64
static TransactionId * KnownAssignedXids
Definition: procarray.c:257
int i
int tailKnownAssignedXids
Definition: procarray.c:82
int headKnownAssignedXids
Definition: procarray.c:83

◆ KnownAssignedXidsRemove()

static void KnownAssignedXidsRemove ( TransactionId  xid)
static

Definition at line 4821 of file procarray.c.

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

Referenced by KnownAssignedXidsRemoveTree().

4822 {
4824 
4825  elog(trace_recovery(DEBUG4), "remove KnownAssignedXid %u", xid);
4826 
4827  /*
4828  * Note: we cannot consider it an error to remove an XID that's not
4829  * present. We intentionally remove subxact IDs while processing
4830  * XLOG_XACT_ASSIGNMENT, to avoid array overflow. Then those XIDs will be
4831  * removed again when the top-level xact commits or aborts.
4832  *
4833  * It might be possible to track such XIDs to distinguish this case from
4834  * actual errors, but it would be complicated and probably not worth it.
4835  * So, just ignore the search result.
4836  */
4837  (void) KnownAssignedXidsSearch(xid, true);
4838 }
#define DEBUG4
Definition: elog.h:22
int trace_recovery(int trace_level)
Definition: elog.c:3609
#define Assert(condition)
Definition: c.h:804
static bool KnownAssignedXidsSearch(TransactionId xid, bool remove)
Definition: procarray.c:4715
#define elog(elevel,...)
Definition: elog.h:232
#define TransactionIdIsValid(xid)
Definition: transam.h:41

◆ KnownAssignedXidsRemovePreceding()

static void KnownAssignedXidsRemovePreceding ( TransactionId  xid)
static

Definition at line 4869 of file procarray.c.

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

4870 {
4871  ProcArrayStruct *pArray = procArray;
4872  int count = 0;
4873  int head,
4874  tail,
4875  i;
4876 
4877  if (!TransactionIdIsValid(removeXid))
4878  {
4879  elog(trace_recovery(DEBUG4), "removing all KnownAssignedXids");
4880  pArray->numKnownAssignedXids = 0;
4881  pArray->headKnownAssignedXids = pArray->tailKnownAssignedXids = 0;
4882  return;
4883  }
4884 
4885  elog(trace_recovery(DEBUG4), "prune KnownAssignedXids to %u", removeXid);
4886 
4887  /*
4888  * Mark entries invalid starting at the tail. Since array is sorted, we
4889  * can stop as soon as we reach an entry >= removeXid.
4890  */
4891  tail = pArray->tailKnownAssignedXids;
4892  head = pArray->headKnownAssignedXids;
4893 
4894  for (i = tail; i < head; i++)
4895  {
4896  if (KnownAssignedXidsValid[i])
4897  {
4898  TransactionId knownXid = KnownAssignedXids[i];
4899 
4900  if (TransactionIdFollowsOrEquals(knownXid, removeXid))
4901  break;
4902 
4903  if (!StandbyTransactionIdIsPrepared(knownXid))
4904  {
4905  KnownAssignedXidsValid[i] = false;
4906  count++;
4907  }
4908  }
4909  }
4910 
4911  pArray->numKnownAssignedXids -= count;
4912  Assert(pArray->numKnownAssignedXids >= 0);
4913 
4914  /*
4915  * Advance the tail pointer if we've marked the tail item invalid.
4916  */
4917  for (i = tail; i < head; i++)
4918  {
4919  if (KnownAssignedXidsValid[i])
4920  break;
4921  }
4922  if (i >= head)
4923  {
4924  /* Array is empty, so we can reset both pointers */
4925  pArray->headKnownAssignedXids = 0;
4926  pArray->tailKnownAssignedXids = 0;
4927  }
4928  else
4929  {
4930  pArray->tailKnownAssignedXids = i;
4931  }
4932 
4933  /* Opportunistically compress the array */
4935 }
uint32 TransactionId
Definition: c.h:587
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:349
#define DEBUG4
Definition: elog.h:22
int trace_recovery(int trace_level)
Definition: elog.c:3609
bool StandbyTransactionIdIsPrepared(TransactionId xid)
Definition: twophase.c:1381
int numKnownAssignedXids
Definition: procarray.c:81
static bool * KnownAssignedXidsValid
Definition: procarray.c:258
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define Assert(condition)
Definition: c.h:804
static TransactionId * KnownAssignedXids
Definition: procarray.c:257
static void KnownAssignedXidsCompress(bool force)
Definition: procarray.c:4535
#define elog(elevel,...)
Definition: elog.h:232
int i
#define TransactionIdIsValid(xid)
Definition: transam.h:41
int tailKnownAssignedXids
Definition: procarray.c:82
int headKnownAssignedXids
Definition: procarray.c:83

◆ KnownAssignedXidsRemoveTree()

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

Definition at line 4847 of file procarray.c.

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

Referenced by ExpireTreeKnownAssignedTransactionIds(), and ProcArrayApplyXidAssignment().

4849 {
4850  int i;
4851 
4852  if (TransactionIdIsValid(xid))
4854 
4855  for (i = 0; i < nsubxids; i++)
4856  KnownAssignedXidsRemove(subxids[i]);
4857 
4858  /* Opportunistically compress the array */
4860 }
static void KnownAssignedXidsCompress(bool force)
Definition: procarray.c:4535
static void KnownAssignedXidsRemove(TransactionId xid)
Definition: procarray.c:4821
int i
#define TransactionIdIsValid(xid)
Definition: transam.h:41

◆ KnownAssignedXidsReset()

static void KnownAssignedXidsReset ( void  )
static

Definition at line 5092 of file procarray.c.

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

Referenced by ProcArrayApplyRecoveryInfo().

5093 {
5094  ProcArrayStruct *pArray = procArray;
5095 
5096  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
5097 
5098  pArray->numKnownAssignedXids = 0;
5099  pArray->tailKnownAssignedXids = 0;
5100  pArray->headKnownAssignedXids = 0;
5101 
5102  LWLockRelease(ProcArrayLock);
5103 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
int numKnownAssignedXids
Definition: procarray.c:81
static ProcArrayStruct * procArray
Definition: procarray.c:250
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203
int tailKnownAssignedXids
Definition: procarray.c:82
int headKnownAssignedXids
Definition: procarray.c:83

◆ KnownAssignedXidsSearch()

static bool KnownAssignedXidsSearch ( TransactionId  xid,
bool  remove 
)
static

Definition at line 4715 of file procarray.c.

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

4716 {
4717  ProcArrayStruct *pArray = procArray;
4718  int first,
4719  last;
4720  int head;
4721  int tail;
4722  int result_index = -1;
4723 
4724  if (remove)
4725  {
4726  /* we hold ProcArrayLock exclusively, so no need for spinlock */
4727  tail = pArray->tailKnownAssignedXids;
4728  head = pArray->headKnownAssignedXids;
4729  }
4730  else
4731  {
4732  /* take spinlock to ensure we see up-to-date array contents */
4734  tail = pArray->tailKnownAssignedXids;
4735  head = pArray->headKnownAssignedXids;
4737  }
4738 
4739  /*
4740  * Standard binary search. Note we can ignore the KnownAssignedXidsValid
4741  * array here, since even invalid entries will contain sorted XIDs.
4742  */
4743  first = tail;
4744  last = head - 1;
4745  while (first <= last)
4746  {
4747  int mid_index;
4748  TransactionId mid_xid;
4749 
4750  mid_index = (first + last) / 2;
4751  mid_xid = KnownAssignedXids[mid_index];
4752 
4753  if (xid == mid_xid)
4754  {
4755  result_index = mid_index;
4756  break;
4757  }
4758  else if (TransactionIdPrecedes(xid, mid_xid))
4759  last = mid_index - 1;
4760  else
4761  first = mid_index + 1;
4762  }
4763 
4764  if (result_index < 0)
4765  return false; /* not in array */
4766 
4767  if (!KnownAssignedXidsValid[result_index])
4768  return false; /* in array, but invalid */
4769 
4770  if (remove)
4771  {
4772  KnownAssignedXidsValid[result_index] = false;
4773 
4774  pArray->numKnownAssignedXids--;
4775  Assert(pArray->numKnownAssignedXids >= 0);
4776 
4777  /*
4778  * If we're removing the tail element then advance tail pointer over
4779  * any invalid elements. This will speed future searches.
4780  */
4781  if (result_index == tail)
4782  {
4783  tail++;
4784  while (tail < head && !KnownAssignedXidsValid[tail])
4785  tail++;
4786  if (tail >= head)
4787  {
4788  /* Array is empty, so we can reset both pointers */
4789  pArray->headKnownAssignedXids = 0;
4790  pArray->tailKnownAssignedXids = 0;
4791  }
4792  else
4793  {
4794  pArray->tailKnownAssignedXids = tail;
4795  }
4796  }
4797  }
4798 
4799  return true;
4800 }
uint32 TransactionId
Definition: c.h:587
slock_t known_assigned_xids_lck
Definition: procarray.c:84
#define SpinLockAcquire(lock)
Definition: spin.h:62
int numKnownAssignedXids
Definition: procarray.c:81
static bool * KnownAssignedXidsValid
Definition: procarray.c:258
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define SpinLockRelease(lock)
Definition: spin.h:64
#define Assert(condition)
Definition: c.h:804
static TransactionId * KnownAssignedXids
Definition: procarray.c:257
int tailKnownAssignedXids
Definition: procarray.c:82
int headKnownAssignedXids
Definition: procarray.c:83

◆ MaintainLatestCompletedXid()

static void MaintainLatestCompletedXid ( TransactionId  latestXid)
static

Definition at line 936 of file procarray.c.

References Assert, FullTransactionIdIsNormal, FullTransactionIdIsValid, FullXidRelativeTo(), IsBootstrapProcessingMode, VariableCacheData::latestCompletedXid, LWLockHeldByMe(), RecoveryInProgress(), ShmemVariableCache, TransactionIdPrecedes(), and XidFromFullTransactionId.

Referenced by ProcArrayEndTransactionInternal(), ProcArrayRemove(), and XidCacheRemoveRunningXids().

937 {
939 
940  Assert(FullTransactionIdIsValid(cur_latest));
942  Assert(LWLockHeldByMe(ProcArrayLock));
943 
944  if (TransactionIdPrecedes(XidFromFullTransactionId(cur_latest), latestXid))
945  {
947  FullXidRelativeTo(cur_latest, latestXid);
948  }
949 
952 }
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1932
#define FullTransactionIdIsValid(x)
Definition: transam.h:55
static FullTransactionId FullXidRelativeTo(FullTransactionId rel, TransactionId xid)
Definition: procarray.c:4241
FullTransactionId latestCompletedXid
Definition: transam.h:233
bool RecoveryInProgress(void)
Definition: xlog.c:8210
#define XidFromFullTransactionId(x)
Definition: transam.h:48
#define FullTransactionIdIsNormal(x)
Definition: transam.h:58
VariableCache ShmemVariableCache
Definition: varsup.c:34
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define Assert(condition)
Definition: c.h:804
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:406

◆ MaintainLatestCompletedXidRecovery()

static void MaintainLatestCompletedXidRecovery ( TransactionId  latestXid)
static

Definition at line 958 of file procarray.c.

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

Referenced by ExpireTreeKnownAssignedTransactionIds(), and ProcArrayApplyRecoveryInfo().

959 {
961  FullTransactionId rel;
962 
964  Assert(LWLockHeldByMe(ProcArrayLock));
965 
966  /*
967  * Need a FullTransactionId to compare latestXid with. Can't rely on
968  * latestCompletedXid to be initialized in recovery. But in recovery it's
969  * safe to access nextXid without a lock for the startup process.
970  */
973 
974  if (!FullTransactionIdIsValid(cur_latest) ||
975  TransactionIdPrecedes(XidFromFullTransactionId(cur_latest), latestXid))
976  {
978  FullXidRelativeTo(rel, latestXid);
979  }
980 
982 }
#define AmStartupProcess()
Definition: miscadmin.h:445
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1932
#define FullTransactionIdIsValid(x)
Definition: transam.h:55
static FullTransactionId FullXidRelativeTo(FullTransactionId rel, TransactionId xid)
Definition: procarray.c:4241
FullTransactionId latestCompletedXid
Definition: transam.h:233
FullTransactionId nextXid
Definition: transam.h:215
#define XidFromFullTransactionId(x)
Definition: transam.h:48
#define FullTransactionIdIsNormal(x)
Definition: transam.h:58
bool IsUnderPostmaster
Definition: globals.c:112
VariableCache ShmemVariableCache
Definition: varsup.c:34
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define Assert(condition)
Definition: c.h:804

◆ MinimumActiveBackends()

bool MinimumActiveBackends ( int  min)

Definition at line 3435 of file procarray.c.

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

Referenced by XLogFlush().

3436 {
3437  ProcArrayStruct *arrayP = procArray;
3438  int count = 0;
3439  int index;
3440 
3441  /* Quick short-circuit if no minimum is specified */
3442  if (min == 0)
3443  return true;
3444 
3445  /*
3446  * Note: for speed, we don't acquire ProcArrayLock. This is a little bit
3447  * bogus, but since we are only testing fields for zero or nonzero, it
3448  * should be OK. The result is only used for heuristic purposes anyway...
3449  */
3450  for (index = 0; index < arrayP->numProcs; index++)
3451  {
3452  int pgprocno = arrayP->pgprocnos[index];
3453  PGPROC *proc = &allProcs[pgprocno];
3454 
3455  /*
3456  * Since we're not holding a lock, need to be prepared to deal with
3457  * garbage, as someone could have incremented numProcs but not yet
3458  * filled the structure.
3459  *
3460  * If someone just decremented numProcs, 'proc' could also point to a
3461  * PGPROC entry that's no longer in the array. It still points to a
3462  * PGPROC struct, though, because freed PGPROC entries just go to the
3463  * free list and are recycled. Its contents are nonsense in that case,
3464  * but that's acceptable for this function.
3465  */
3466  if (pgprocno == -1)
3467  continue; /* do not count deleted entries */
3468  if (proc == MyProc)
3469  continue; /* do not count myself */
3470  if (proc->xid == InvalidTransactionId)
3471  continue; /* do not count if no XID assigned */
3472  if (proc->pid == 0)
3473  continue; /* do not count prepared xacts */
3474  if (proc->waitLock != NULL)
3475  continue; /* do not count if blocked on a lock */
3476  count++;
3477  if (count >= min)
3478  break;
3479  }
3480 
3481  return count >= min;
3482 }
PGPROC * MyProc
Definition: proc.c:68
Definition: type.h:89
#define InvalidTransactionId
Definition: transam.h:31
static PGPROC * allProcs
Definition: procarray.c:252
LOCK * waitLock
Definition: proc.h:179
static ProcArrayStruct * procArray
Definition: procarray.c:250
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
TransactionId xid
Definition: proc.h:133
Definition: proc.h:121
int pid
Definition: proc.h:146

◆ ProcArrayAdd()

void ProcArrayAdd ( PGPROC proc)

Definition at line 445 of file procarray.c.

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

446 {
447  ProcArrayStruct *arrayP = procArray;
448  int index;
449  int movecount;
450 
451  /* See ProcGlobal comment explaining why both locks are held */
452  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
453  LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
454 
455  if (arrayP->numProcs >= arrayP->maxProcs)
456  {
457  /*
458  * Oops, no room. (This really shouldn't happen, since there is a
459  * fixed supply of PGPROC structs too, and so we should have failed
460  * earlier.)
461  */
462  ereport(FATAL,
463  (errcode(ERRCODE_TOO_MANY_CONNECTIONS),
464  errmsg("sorry, too many clients already")));
465  }
466 
467  /*
468  * Keep the procs array sorted by (PGPROC *) so that we can utilize
469  * locality of references much better. This is useful while traversing the
470  * ProcArray because there is an increased likelihood of finding the next
471  * PGPROC structure in the cache.
472  *
473  * Since the occurrence of adding/removing a proc is much lower than the
474  * access to the ProcArray itself, the overhead should be marginal
475  */
476  for (index = 0; index < arrayP->numProcs; index++)
477  {
478  int procno PG_USED_FOR_ASSERTS_ONLY = arrayP->pgprocnos[index];
479 
480  Assert(procno >= 0 && procno < (arrayP->maxProcs + NUM_AUXILIARY_PROCS));
481  Assert(allProcs[procno].pgxactoff == index);
482 
483  /* If we have found our right position in the array, break */
484  if (arrayP->pgprocnos[index] > proc->pgprocno)
485  break;
486  }
487 
488  movecount = arrayP->numProcs - index;
489  memmove(&arrayP->pgprocnos[index + 1],
490  &arrayP->pgprocnos[index],
491  movecount * sizeof(*arrayP->pgprocnos));
492  memmove(&ProcGlobal->xids[index + 1],
493  &ProcGlobal->xids[index],
494  movecount * sizeof(*ProcGlobal->xids));
495  memmove(&ProcGlobal->subxidStates[index + 1],
496  &ProcGlobal->subxidStates[index],
497  movecount * sizeof(*ProcGlobal->subxidStates));
498  memmove(&ProcGlobal->statusFlags[index + 1],
499  &ProcGlobal->statusFlags[index],
500  movecount * sizeof(*ProcGlobal->statusFlags));
501 
502  arrayP->pgprocnos[index] = proc->pgprocno;
503  proc->pgxactoff = index;
504  ProcGlobal->xids[index] = proc->xid;
505  ProcGlobal->subxidStates[index] = proc->subxidStatus;
506  ProcGlobal->statusFlags[index] = proc->statusFlags;
507 
508  arrayP->numProcs++;
509 
510  /* adjust pgxactoff for all following PGPROCs */
511  index++;
512  for (; index < arrayP->numProcs; index++)
513  {
514  int procno = arrayP->pgprocnos[index];
515 
516  Assert(procno >= 0 && procno < (arrayP->maxProcs + NUM_AUXILIARY_PROCS));
517  Assert(allProcs[procno].pgxactoff == index - 1);
518 
519  allProcs[procno].pgxactoff = index;
520  }
521 
522  /*
523  * Release in reversed acquisition order, to reduce frequency of having to
524  * wait for XidGenLock while holding ProcArrayLock.
525  */
526  LWLockRelease(XidGenLock);
527  LWLockRelease(ProcArrayLock);
528 }
XidCacheStatus * subxidStates
Definition: proc.h:327
int errcode(int sqlerrcode)
Definition: elog.c:698
PROC_HDR * ProcGlobal
Definition: proc.c:80
uint8 statusFlags
Definition: proc.h:189
XidCacheStatus subxidStatus
Definition: proc.h:210
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
#define FATAL
Definition: elog.h:49
TransactionId * xids
Definition: proc.h:321
static PGPROC * allProcs
Definition: procarray.c:252
#define NUM_AUXILIARY_PROCS
Definition: proc.h:377
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define ereport(elevel,...)
Definition: elog.h:157
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203
TransactionId xid
Definition: proc.h:133
int pgprocno
Definition: proc.h:150
int errmsg(const char *fmt,...)
Definition: elog.c:909
int pgxactoff
Definition: proc.h:148
uint8 * statusFlags
Definition: proc.h:333
#define PG_USED_FOR_ASSERTS_ONLY
Definition: c.h:155

◆ ProcArrayApplyRecoveryInfo()

void ProcArrayApplyRecoveryInfo ( RunningTransactions  running)

Definition at line 1023 of file procarray.c.

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(), RunningTransactionsData::nextXid, VariableCacheData::nextXid, ProcArrayStruct::numKnownAssignedXids, RunningTransactionsData::oldestRunningXid, palloc(), pfree(), 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().

1024 {
1025  TransactionId *xids;
1026  int nxids;
1027  int i;
1028 
1030  Assert(TransactionIdIsValid(running->nextXid));
1033 
1034  /*
1035  * Remove stale transactions, if any.
1036  */
1038 
1039  /*
1040  * Remove stale locks, if any.
1041  */
1043 
1044  /*
1045  * If our snapshot is already valid, nothing else to do...
1046  */
1048  return;
1049 
1050  /*
1051  * If our initial RunningTransactionsData had an overflowed snapshot then
1052  * we knew we were missing some subxids from our snapshot. If we continue
1053  * to see overflowed snapshots then we might never be able to start up, so
1054  * we make another test to see if our snapshot is now valid. We know that
1055  * the missing subxids are equal to or earlier than nextXid. After we
1056  * initialise we continue to apply changes during recovery, so once the
1057  * oldestRunningXid is later than the nextXid from the initial snapshot we
1058  * know that we no longer have missing information and can mark the
1059  * snapshot as valid.
1060  */
1062  {
1063  /*
1064  * If the snapshot isn't overflowed or if its empty we can reset our
1065  * pending state and use this snapshot instead.
1066  */
1067  if (!running->subxid_overflow || running->xcnt == 0)
1068  {
1069  /*
1070  * If we have already collected known assigned xids, we need to
1071  * throw them away before we apply the recovery snapshot.
1072  */
1075  }
1076  else
1077  {
1079  running->oldestRunningXid))
1080  {
1083  "recovery snapshots are now enabled");
1084  }
1085  else
1087  "recovery snapshot waiting for non-overflowed snapshot or "
1088  "until oldest active xid on standby is at least %u (now %u)",
1090  running->oldestRunningXid);
1091  return;
1092  }
1093  }
1094 
1096 
1097  /*
1098  * NB: this can be reached at least twice, so make sure new code can deal
1099  * with that.
1100  */
1101 
1102  /*
1103  * Nobody else is running yet, but take locks anyhow
1104  */
1105  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
1106 
1107  /*
1108  * KnownAssignedXids is sorted so we cannot just add the xids, we have to
1109  * sort them first.
1110  *
1111  * Some of the new xids are top-level xids and some are subtransactions.
1112  * We don't call SubTransSetParent because it doesn't matter yet. If we
1113  * aren't overflowed then all xids will fit in snapshot and so we don't
1114  * need subtrans. If we later overflow, an xid assignment record will add
1115  * xids to subtrans. If RunningTransactionsData is overflowed then we
1116  * don't have enough information to correctly update subtrans anyway.
1117  */
1118 
1119  /*
1120  * Allocate a temporary array to avoid modifying the array passed as
1121  * argument.
1122  */
1123  xids = palloc(sizeof(TransactionId) * (running->xcnt + running->subxcnt));
1124 
1125  /*
1126  * Add to the temp array any xids which have not already completed.
1127  */
1128  nxids = 0;
1129  for (i = 0; i < running->xcnt + running->subxcnt; i++)
1130  {
1131  TransactionId xid = running->xids[i];
1132 
1133  /*
1134  * The running-xacts snapshot can contain xids that were still visible
1135  * in the procarray when the snapshot was taken, but were already
1136  * WAL-logged as completed. They're not running anymore, so ignore
1137  * them.
1138  */
1140  continue;
1141 
1142  xids[nxids++] = xid;
1143  }
1144 
1145  if (nxids > 0)
1146  {
1147  if (procArray->numKnownAssignedXids != 0)
1148  {
1149  LWLockRelease(ProcArrayLock);
1150  elog(ERROR, "KnownAssignedXids is not empty");
1151  }
1152 
1153  /*
1154  * Sort the array so that we can add them safely into
1155  * KnownAssignedXids.
1156  */
1157  qsort(xids, nxids, sizeof(TransactionId), xidComparator);
1158 
1159  /*
1160  * Add the sorted snapshot into KnownAssignedXids. The running-xacts
1161  * snapshot may include duplicated xids because of prepared
1162  * transactions, so ignore them.
1163  */
1164  for (i = 0; i < nxids; i++)
1165  {
1166  if (i > 0 && TransactionIdEquals(xids[i - 1], xids[i]))
1167  {
1168  elog(DEBUG1,
1169  "found duplicated transaction %u for KnownAssignedXids insertion",
1170  xids[i]);
1171  continue;
1172  }
1173  KnownAssignedXidsAdd(xids[i], xids[i], true);
1174  }
1175 
1177  }
1178 
1179  pfree(xids);
1180 
1181  /*
1182  * latestObservedXid is at least set to the point where SUBTRANS was
1183  * started up to (cf. ProcArrayInitRecovery()) or to the biggest xid
1184  * RecordKnownAssignedTransactionIds() was called for. Initialize
1185  * subtrans from thereon, up to nextXid - 1.
1186  *
1187  * We need to duplicate parts of RecordKnownAssignedTransactionId() here,
1188  * because we've just added xids to the known assigned xids machinery that
1189  * haven't gone through RecordKnownAssignedTransactionId().
1190  */
1194  {
1197  }
1198  TransactionIdRetreat(latestObservedXid); /* = running->nextXid - 1 */
1199 
1200  /* ----------
1201  * Now we've got the running xids we need to set the global values that
1202  * are used to track snapshots as they evolve further.
1203  *
1204  * - latestCompletedXid which will be the xmax for snapshots
1205  * - lastOverflowedXid which shows whether snapshots overflow
1206  * - nextXid
1207  *
1208  * If the snapshot overflowed, then we still initialise with what we know,
1209  * but the recovery snapshot isn't fully valid yet because we know there
1210  * are some subxids missing. We don't know the specific subxids that are
1211  * missing, so conservatively assume the last one is latestObservedXid.
1212  * ----------
1213  */
1214  if (running->subxid_overflow)
1215  {
1217 
1220  }
1221  else
1222  {
1224 
1226  }
1227 
1228  /*
1229  * If a transaction wrote a commit record in the gap between taking and
1230  * logging the snapshot then latestCompletedXid may already be higher than
1231  * the value from the snapshot, so check before we use the incoming value.
1232  * It also might not yet be set at all.
1233  */
1235 
1236  /*
1237  * NB: No need to increment ShmemVariableCache->xactCompletionCount here,
1238  * nobody can see it yet.
1239  */
1240 
1241  LWLockRelease(ProcArrayLock);
1242 
1243  /* ShmemVariableCache->nextXid must be beyond any observed xid. */
1245 
1247 
1250  elog(trace_recovery(DEBUG1), "recovery snapshots are now enabled");
1251  else
1253  "recovery snapshot waiting for non-overflowed snapshot or "
1254  "until oldest active xid on standby is at least %u (now %u)",
1256  running->oldestRunningXid);
1257 }
#define TransactionIdAdvance(dest)
Definition: transam.h:91
static TransactionId latestObservedXid
Definition: procarray.c:259
TransactionId oldestRunningXid
Definition: standby.h:83
#define DEBUG1
Definition: elog.h:25
static void KnownAssignedXidsDisplay(int trace_level)
Definition: procarray.c:5054
#define TransactionIdEquals(id1, id2)
Definition: transam.h:43
uint32 TransactionId
Definition: c.h:587
void AdvanceNextFullTransactionIdPastXid(TransactionId xid)
Definition: varsup.c:277
#define DEBUG3
Definition: elog.h:23
#define FullTransactionIdIsValid(x)
Definition: transam.h:55
static void MaintainLatestCompletedXidRecovery(TransactionId latestXid)
Definition: procarray.c:958
TransactionId * xids
Definition: standby.h:86
bool TransactionIdDidCommit(TransactionId transactionId)
Definition: transam.c:125
#define TransactionIdRetreat(dest)
Definition: transam.h:141
FullTransactionId nextXid
Definition: transam.h:215
int trace_recovery(int trace_level)
Definition: elog.c:3609
TransactionId latestCompletedXid
Definition: standby.h:84
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
void pfree(void *pointer)
Definition: mcxt.c:1169
#define ERROR
Definition: elog.h:46
void ExtendSUBTRANS(TransactionId newestXact)
Definition: subtrans.c:308
VariableCache ShmemVariableCache
Definition: varsup.c:34
#define InvalidTransactionId
Definition: transam.h:31
static void KnownAssignedXidsReset(void)
Definition: procarray.c:5092
int numKnownAssignedXids
Definition: procarray.c:81
TransactionId lastOverflowedXid
Definition: procarray.c:93
bool TransactionIdDidAbort(TransactionId transactionId)
Definition: transam.c:181
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203
static void KnownAssignedXidsAdd(TransactionId from_xid, TransactionId to_xid, bool exclusive_lock)
Definition: procarray.c:4597
TransactionId nextXid
Definition: standby.h:82
void * palloc(Size size)
Definition: mcxt.c:1062
#define elog(elevel,...)
Definition: elog.h:232
int i
void ExpireOldKnownAssignedTransactionIds(TransactionId xid)
Definition: procarray.c:4432
#define qsort(a, b, c, d)
Definition: port.h:504
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define TransactionIdIsNormal(xid)
Definition: transam.h:42
static TransactionId standbySnapshotPendingXmin
Definition: procarray.c:266
HotStandbyState standbyState
Definition: xlog.c:210
void StandbyReleaseOldLocks(TransactionId oldxid)
Definition: standby.c:1070
int xidComparator(const void *arg1, const void *arg2)
Definition: xid.c:136

◆ ProcArrayApplyXidAssignment()

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

Definition at line 1264 of file procarray.c.

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

Referenced by xact_redo().

1266 {
1267  TransactionId max_xid;
1268  int i;
1269 
1271 
1272  max_xid = TransactionIdLatest(topxid, nsubxids, subxids);
1273 
1274  /*
1275  * Mark all the subtransactions as observed.
1276  *
1277  * NOTE: This will fail if the subxid contains too many previously
1278  * unobserved xids to fit into known-assigned-xids. That shouldn't happen
1279  * as the code stands, because xid-assignment records should never contain
1280  * more than PGPROC_MAX_CACHED_SUBXIDS entries.
1281  */
1283 
1284  /*
1285  * Notice that we update pg_subtrans with the top-level xid, rather than
1286  * the parent xid. This is a difference between normal processing and
1287  * recovery, yet is still correct in all cases. The reason is that
1288  * subtransaction commit is not marked in clog until commit processing, so
1289  * all aborted subtransactions have already been clearly marked in clog.
1290  * As a result we are able to refer directly to the top-level
1291  * transaction's state rather than skipping through all the intermediate
1292  * states in the subtransaction tree. This should be the first time we
1293  * have attempted to SubTransSetParent().
1294  */
1295  for (i = 0; i < nsubxids; i++)
1296  SubTransSetParent(subxids[i], topxid);
1297 
1298  /* KnownAssignedXids isn't maintained yet, so we're done for now */
1300  return;
1301 
1302  /*
1303  * Uses same locking as transaction commit
1304  */
1305  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
1306 
1307  /*
1308  * Remove subxids from known-assigned-xacts.
1309  */
1311 
1312  /*
1313  * Advance lastOverflowedXid to be at least the last of these subxids.
1314  */
1316  procArray->lastOverflowedXid = max_xid;
1317 
1318  LWLockRelease(ProcArrayLock);
1319 }
uint32 TransactionId
Definition: c.h:587
TransactionId TransactionIdLatest(TransactionId mainxid, int nxids, const TransactionId *xids)
Definition: transam.c:365
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
#define InvalidTransactionId
Definition: transam.h:31
TransactionId lastOverflowedXid
Definition: procarray.c:93
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
static void KnownAssignedXidsRemoveTree(TransactionId xid, int nsubxids, TransactionId *subxids)
Definition: procarray.c:4847
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203
int i
void RecordKnownAssignedTransactionIds(TransactionId xid)
Definition: procarray.c:4323
void SubTransSetParent(TransactionId xid, TransactionId parent)
Definition: subtrans.c:74
HotStandbyState standbyState
Definition: xlog.c:210

◆ ProcArrayClearTransaction()

void ProcArrayClearTransaction ( PGPROC proc)

Definition at line 876 of file procarray.c.

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

877 {
878  size_t pgxactoff;
879 
880  /*
881  * Currently we need to lock ProcArrayLock exclusively here, as we
882  * increment xactCompletionCount below. We also need it at least in shared
883  * mode for pgproc->pgxactoff to stay the same below.
884  *
885  * We could however, as this action does not actually change anyone's view
886  * of the set of running XIDs (our entry is duplicate with the gxact that
887  * has already been inserted into the ProcArray), lower the lock level to
888  * shared if we were to make xactCompletionCount an atomic variable. But
889  * that doesn't seem worth it currently, as a 2PC commit is heavyweight
890  * enough for this not to be the bottleneck. If it ever becomes a
891  * bottleneck it may also be worth considering to combine this with the
892  * subsequent ProcArrayRemove()
893  */
894  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
895 
896  pgxactoff = proc->pgxactoff;
897 
898  ProcGlobal->xids[pgxactoff] = InvalidTransactionId;
899  proc->xid = InvalidTransactionId;
900 
902  proc->xmin = InvalidTransactionId;
903  proc->recoveryConflictPending = false;
904 
906  Assert(!proc->delayChkpt);
907 
908  /*
909  * Need to increment completion count even though transaction hasn't
910  * really committed yet. The reason for that is that GetSnapshotData()
911  * omits the xid of the current transaction, thus without the increment we
912  * otherwise could end up reusing the snapshot later. Which would be bad,
913  * because it might not count the prepared transaction as running.
914  */
916 
917  /* Clear the subtransaction-XID cache too */
918  Assert(ProcGlobal->subxidStates[pgxactoff].count == proc->subxidStatus.count &&
920  if (proc->subxidStatus.count > 0 || proc->subxidStatus.overflowed)
921  {
922  ProcGlobal->subxidStates[pgxactoff].count = 0;
923  ProcGlobal->subxidStates[pgxactoff].overflowed = false;
924  proc->subxidStatus.count = 0;
925  proc->subxidStatus.overflowed = false;
926  }
927 
928  LWLockRelease(ProcArrayLock);
929 }
XidCacheStatus * subxidStates
Definition: proc.h:327
uint64 xactCompletionCount
Definition: transam.h:243
PROC_HDR * ProcGlobal
Definition: proc.c:80
uint8 statusFlags
Definition: proc.h:189
XidCacheStatus subxidStatus
Definition: proc.h:210
#define PROC_VACUUM_STATE_MASK
Definition: proc.h:65
bool overflowed
Definition: proc.h:43
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
bool delayChkpt
Definition: proc.h:187
TransactionId xmin
Definition: proc.h:138
bool recoveryConflictPending
Definition: proc.h:167
VariableCache ShmemVariableCache
Definition: varsup.c:34
#define InvalidTransactionId
Definition: transam.h:31
TransactionId * xids
Definition: proc.h:321
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203
uint8 count
Definition: proc.h:41
TransactionId xid
Definition: proc.h:133
#define InvalidLocalTransactionId
Definition: lock.h:69
int pgxactoff
Definition: proc.h:148
LocalTransactionId lxid
Definition: proc.h:143

◆ ProcArrayEndTransaction()

void ProcArrayEndTransaction ( PGPROC proc,
TransactionId  latestXid 
)

Definition at line 643 of file procarray.c.

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

644 {
645  if (TransactionIdIsValid(latestXid))
646  {
647  /*
648  * We must lock ProcArrayLock while clearing our advertised XID, so
649  * that we do not exit the set of "running" transactions while someone
650  * else is taking a snapshot. See discussion in
651  * src/backend/access/transam/README.
652  */
654 
655  /*
656  * If we can immediately acquire ProcArrayLock, we clear our own XID
657  * and release the lock. If not, use group XID clearing to improve
658  * efficiency.
659  */
660  if (LWLockConditionalAcquire(ProcArrayLock, LW_EXCLUSIVE))
661  {
662  ProcArrayEndTransactionInternal(proc, latestXid);
663  LWLockRelease(ProcArrayLock);
664  }
665  else
666  ProcArrayGroupClearXid(proc, latestXid);
667  }
668  else
669  {
670  /*
671  * If we have no XID, we don't need to lock, since we won't affect
672  * anyone else's calculation of a snapshot. We might change their
673  * estimate of global xmin, but that's OK.
674  */
676  Assert(proc->subxidStatus.count == 0);
678 
680  proc->xmin = InvalidTransactionId;
681  proc->delayChkpt = false; /* be sure this is cleared in abort */
682  proc->recoveryConflictPending = false;
683 
684  /* must be cleared with xid/xmin: */
685  /* avoid unnecessarily dirtying shared cachelines */
687  {
688  Assert(!LWLockHeldByMe(ProcArrayLock));
689  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
693  LWLockRelease(ProcArrayLock);
694  }
695  }
696 }
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1932
static void ProcArrayEndTransactionInternal(PGPROC *proc, TransactionId latestXid)
Definition: procarray.c:704
static void ProcArrayGroupClearXid(PGPROC *proc, TransactionId latestXid)
Definition: procarray.c:762
PROC_HDR * ProcGlobal
Definition: proc.c:80
uint8 statusFlags
Definition: proc.h:189
XidCacheStatus subxidStatus
Definition: proc.h:210
#define PROC_VACUUM_STATE_MASK
Definition: proc.h:65
bool overflowed
Definition: proc.h:43
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
bool delayChkpt
Definition: proc.h:187
TransactionId xmin
Definition: proc.h:138
bool LWLockConditionalAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1378
bool recoveryConflictPending
Definition: proc.h:167
#define InvalidTransactionId
Definition: transam.h:31
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203
uint8 count
Definition: proc.h:41
TransactionId xid
Definition: proc.h:133
#define InvalidLocalTransactionId
Definition: lock.h:69
int pgxactoff
Definition: proc.h:148
uint8 * statusFlags
Definition: proc.h:333
#define TransactionIdIsValid(xid)
Definition: transam.h:41
LocalTransactionId lxid
Definition: proc.h:143

◆ ProcArrayEndTransactionInternal()

static void ProcArrayEndTransactionInternal ( PGPROC proc,
TransactionId  latestXid 
)
inlinestatic

Definition at line 704 of file procarray.c.

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

705 {
706  size_t pgxactoff = proc->pgxactoff;
707 
708  /*
709  * Note: we need exclusive lock here because we're going to change other
710  * processes' PGPROC entries.
711  */
712  Assert(LWLockHeldByMeInMode(ProcArrayLock, LW_EXCLUSIVE));
714  Assert(ProcGlobal->xids[pgxactoff] == proc->xid);
715 
716  ProcGlobal->xids[pgxactoff] = InvalidTransactionId;
717  proc->xid = InvalidTransactionId;
719  proc->xmin = InvalidTransactionId;
720  proc->delayChkpt = false; /* be sure this is cleared in abort */
721  proc->recoveryConflictPending = false;
722 
723  /* must be cleared with xid/xmin: */
724  /* avoid unnecessarily dirtying shared cachelines */
726  {
729  }
730 
731  /* Clear the subtransaction-XID cache too while holding the lock */
732  Assert(ProcGlobal->subxidStates[pgxactoff].count == proc->subxidStatus.count &&
734  if (proc->subxidStatus.count > 0 || proc->subxidStatus.overflowed)
735  {
736  ProcGlobal->subxidStates[pgxactoff].count = 0;
737  ProcGlobal->subxidStates[pgxactoff].overflowed = false;
738  proc->subxidStatus.count = 0;
739  proc->subxidStatus.overflowed = false;
740  }
741 
742  /* Also advance global latestCompletedXid while holding the lock */
743  MaintainLatestCompletedXid(latestXid);
744 
745  /* Same with xactCompletionCount */
747 }
bool LWLockHeldByMeInMode(LWLock *l, LWLockMode mode)
Definition: lwlock.c:1950
XidCacheStatus * subxidStates
Definition: proc.h:327
uint64 xactCompletionCount
Definition: transam.h:243
PROC_HDR * ProcGlobal
Definition: proc.c:80
uint8 statusFlags
Definition: proc.h:189
XidCacheStatus subxidStatus
Definition: proc.h:210
#define PROC_VACUUM_STATE_MASK
Definition: proc.h:65
bool overflowed
Definition: proc.h:43
bool delayChkpt
Definition: proc.h:187
TransactionId xmin
Definition: proc.h:138
bool recoveryConflictPending
Definition: proc.h:167
VariableCache ShmemVariableCache
Definition: varsup.c:34
#define InvalidTransactionId
Definition: transam.h:31
TransactionId * xids
Definition: proc.h:321
static void MaintainLatestCompletedXid(TransactionId latestXid)
Definition: procarray.c:936
#define Assert(condition)
Definition: c.h:804
uint8 count
Definition: proc.h:41
TransactionId xid
Definition: proc.h:133
#define InvalidLocalTransactionId
Definition: lock.h:69
int pgxactoff
Definition: proc.h:148
uint8 * statusFlags
Definition: proc.h:333
#define TransactionIdIsValid(xid)
Definition: transam.h:41
LocalTransactionId lxid
Definition: proc.h:143

◆ ProcArrayGetReplicationSlotXmin()

void ProcArrayGetReplicationSlotXmin ( TransactionId xmin,
TransactionId catalog_xmin 
)

Definition at line 3847 of file procarray.c.

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

Referenced by logical_begin_heap_rewrite().

3849 {
3850  LWLockAcquire(ProcArrayLock, LW_SHARED);
3851 
3852  if (xmin != NULL)
3854 
3855  if (catalog_xmin != NULL)
3856  *catalog_xmin = procArray->replication_slot_catalog_xmin;
3857 
3858  LWLockRelease(ProcArrayLock);
3859 }
TransactionId replication_slot_catalog_xmin
Definition: procarray.c:98
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1816
static ProcArrayStruct * procArray
Definition: procarray.c:250
TransactionId replication_slot_xmin
Definition: procarray.c:96
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1203

◆ ProcArrayGroupClearXid()

static void ProcArrayGroupClearXid ( PGPROC proc,
TransactionId  latestXid 
)
static

Definition at line 762 of file procarray.c.

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

763 {
764  PROC_HDR *procglobal = ProcGlobal;
765  uint32 nextidx;
766  uint32 wakeidx;
767 
768  /* We should definitely have an XID to clear. */
770 
771  /* Add ourselves to the list of processes needing a group XID clear. */
772  proc->procArrayGroupMember = true;
773  proc->procArrayGroupMemberXid = latestXid;
774  nextidx = pg_atomic_read_u32(&procglobal->procArrayGroupFirst);
775  while (true)
776  {
777  pg_atomic_write_u32(&proc->procArrayGroupNext, nextidx);
778 
780  &nextidx,
781  (uint32) proc->pgprocno))
782  break;
783  }
784 
785  /*
786  * If the list was not empty, the leader will clear our XID. It is
787  * impossible to have followers without a leader because the first process
788  * that has added itself to the list will always have nextidx as
789  * INVALID_PGPROCNO.
790  */
791  if (nextidx != INVALID_PGPROCNO)
792  {
793  int extraWaits = 0;
794 
795  /* Sleep until the leader clears our XID. */
797  for (;;)
798  {
799  /* acts as a read barrier */
800  PGSemaphoreLock(proc->sem);
801  if (!proc->procArrayGroupMember)
802  break;
803  extraWaits++;
804  }
806 
808 
809  /* Fix semaphore count for any absorbed wakeups */
810  while (extraWaits-- > 0)
811  PGSemaphoreUnlock(proc->sem);
812  return;
813  }
814 
815  /* We are the leader. Acquire the lock on behalf of everyone. */
816  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
817 
818  /*
819  * Now that we've got the lock, clear the list of processes waiting for
820  * group XID clearing, saving a pointer to the head of the list. Trying
821  * to pop elements one at a time could lead to an ABA problem.
822  */
823  nextidx = pg_atomic_exchange_u32(&procglobal->procArrayGroupFirst,
825 
826  /* Remember head of list so we can perform wakeups after dropping lock. */
827  wakeidx = nextidx;
828 
829  /* Walk the list and clear all XIDs. */
830  while (nextidx != INVALID_PGPROCNO)
831  {
832  PGPROC *proc = &allProcs[nextidx];
833 
835 
836  /* Move to next proc in list. */
837  nextidx = pg_atomic_read_u32(&proc->procArrayGroupNext);
838  }
839 
840  /* We're done with the lock now. */
841