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

Go to the source code of this file.

Data Structures

struct  ProcArrayStruct
 
struct  GlobalVisState
 
struct  ComputeXidHorizonsResult
 

Macros

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

Typedefs

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

Enumerations

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

Functions

static void KnownAssignedXidsCompress (KAXCompressReason reason, bool haveLock)
 
static void KnownAssignedXidsAdd (TransactionId from_xid, TransactionId to_xid, bool exclusive_lock)
 
static bool KnownAssignedXidsSearch (TransactionId xid, bool remove)
 
static bool KnownAssignedXidExists (TransactionId xid)
 
static void KnownAssignedXidsRemove (TransactionId xid)
 
static void KnownAssignedXidsRemoveTree (TransactionId xid, int nsubxids, TransactionId *subxids)
 
static void KnownAssignedXidsRemovePreceding (TransactionId removeXid)
 
static int KnownAssignedXidsGet (TransactionId *xarray, TransactionId xmax)
 
static int KnownAssignedXidsGetAndSetXmin (TransactionId *xarray, TransactionId *xmin, TransactionId xmax)
 
static TransactionId KnownAssignedXidsGetOldestXmin (void)
 
static void KnownAssignedXidsDisplay (int trace_level)
 
static void KnownAssignedXidsReset (void)
 
static void ProcArrayEndTransactionInternal (PGPROC *proc, TransactionId latestXid)
 
static void ProcArrayGroupClearXid (PGPROC *proc, TransactionId latestXid)
 
static void MaintainLatestCompletedXid (TransactionId latestXid)
 
static void MaintainLatestCompletedXidRecovery (TransactionId latestXid)
 
static FullTransactionId FullXidRelativeTo (FullTransactionId rel, TransactionId xid)
 
static void GlobalVisUpdateApply (ComputeXidHorizonsResult *horizons)
 
Size ProcArrayShmemSize (void)
 
void CreateSharedProcArray (void)
 
void ProcArrayAdd (PGPROC *proc)
 
void ProcArrayRemove (PGPROC *proc, TransactionId latestXid)
 
void ProcArrayEndTransaction (PGPROC *proc, TransactionId latestXid)
 
void ProcArrayClearTransaction (PGPROC *proc)
 
void ProcArrayInitRecovery (TransactionId initializedUptoXID)
 
void ProcArrayApplyRecoveryInfo (RunningTransactions running)
 
void ProcArrayApplyXidAssignment (TransactionId topxid, int nsubxids, TransactionId *subxids)
 
bool TransactionIdIsInProgress (TransactionId xid)
 
bool TransactionIdIsActive (TransactionId xid)
 
static void ComputeXidHorizons (ComputeXidHorizonsResult *h)
 
static GlobalVisHorizonKind GlobalVisHorizonKindForRel (Relation rel)
 
TransactionId GetOldestNonRemovableTransactionId (Relation rel)
 
TransactionId GetOldestTransactionIdConsideredRunning (void)
 
void GetReplicationHorizons (TransactionId *xmin, TransactionId *catalog_xmin)
 
int GetMaxSnapshotXidCount (void)
 
int GetMaxSnapshotSubxidCount (void)
 
static bool GetSnapshotDataReuse (Snapshot snapshot)
 
Snapshot GetSnapshotData (Snapshot snapshot)
 
bool ProcArrayInstallImportedXmin (TransactionId xmin, VirtualTransactionId *sourcevxid)
 
bool ProcArrayInstallRestoredXmin (TransactionId xmin, PGPROC *proc)
 
RunningTransactions GetRunningTransactionData (void)
 
TransactionId GetOldestActiveTransactionId (void)
 
TransactionId GetOldestSafeDecodingTransactionId (bool catalogOnly)
 
VirtualTransactionIdGetVirtualXIDsDelayingChkpt (int *nvxids, int type)
 
bool HaveVirtualXIDsDelayingChkpt (VirtualTransactionId *vxids, int nvxids, int type)
 
PGPROCProcNumberGetProc (ProcNumber procNumber)
 
void ProcNumberGetTransactionIds (ProcNumber procNumber, TransactionId *xid, TransactionId *xmin, int *nsubxid, bool *overflowed)
 
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)
 
bool GlobalVisCheckRemovableFullXid (Relation rel, FullTransactionId fxid)
 
bool GlobalVisCheckRemovableXid (Relation rel, TransactionId xid)
 
void RecordKnownAssignedTransactionIds (TransactionId xid)
 
void ExpireTreeKnownAssignedTransactionIds (TransactionId xid, int nsubxids, TransactionId *subxids, TransactionId max_xid)
 
void ExpireAllKnownAssignedTransactionIds (void)
 
void ExpireOldKnownAssignedTransactionIds (TransactionId xid)
 
void KnownAssignedTransactionIdsIdleMaintenance (void)
 

Variables

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

Macro Definition Documentation

◆ KAX_COMPRESS_FREQUENCY

#define KAX_COMPRESS_FREQUENCY   128 /* in transactions */

◆ KAX_COMPRESS_IDLE_INTERVAL

#define KAX_COMPRESS_IDLE_INTERVAL   1000 /* in ms */

◆ MAXAUTOVACPIDS

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

◆ PROCARRAY_MAXPROCS

#define PROCARRAY_MAXPROCS   (MaxBackends + max_prepared_xacts)

◆ TOTAL_MAX_CACHED_SUBXIDS

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

◆ UINT32_ACCESS_ONCE

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

Definition at line 68 of file procarray.c.

◆ xc_by_child_xid_inc

#define xc_by_child_xid_inc ( )    ((void) 0)

Definition at line 340 of file procarray.c.

◆ xc_by_known_assigned_inc

#define xc_by_known_assigned_inc ( )    ((void) 0)

Definition at line 341 of file procarray.c.

◆ xc_by_known_xact_inc

#define xc_by_known_xact_inc ( )    ((void) 0)

Definition at line 336 of file procarray.c.

◆ xc_by_latest_xid_inc

#define xc_by_latest_xid_inc ( )    ((void) 0)

Definition at line 338 of file procarray.c.

◆ xc_by_main_xid_inc

#define xc_by_main_xid_inc ( )    ((void) 0)

Definition at line 339 of file procarray.c.

◆ xc_by_my_xact_inc

#define xc_by_my_xact_inc ( )    ((void) 0)

Definition at line 337 of file procarray.c.

◆ xc_by_recent_xmin_inc

#define xc_by_recent_xmin_inc ( )    ((void) 0)

Definition at line 335 of file procarray.c.

◆ xc_no_overflow_inc

#define xc_no_overflow_inc ( )    ((void) 0)

Definition at line 342 of file procarray.c.

◆ xc_slow_answer_inc

#define xc_slow_answer_inc ( )    ((void) 0)

Definition at line 343 of file procarray.c.

Typedef Documentation

◆ ComputeXidHorizonsResult

◆ GlobalVisHorizonKind

◆ KAXCompressReason

◆ ProcArrayStruct

Enumeration Type Documentation

◆ GlobalVisHorizonKind

Enumerator
VISHORIZON_SHARED 
VISHORIZON_CATALOG 
VISHORIZON_DATA 
VISHORIZON_TEMP 

Definition at line 249 of file procarray.c.

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

◆ KAXCompressReason

Enumerator
KAX_NO_SPACE 
KAX_PRUNE 
KAX_TRANSACTION_END 
KAX_STARTUP_PROCESS_IDLE 

Definition at line 260 of file procarray.c.

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

Function Documentation

◆ BackendPidGetProc()

PGPROC* BackendPidGetProc ( int  pid)

Definition at line 3183 of file procarray.c.

3184 {
3185  PGPROC *result;
3186 
3187  if (pid == 0) /* never match dummy PGPROCs */
3188  return NULL;
3189 
3190  LWLockAcquire(ProcArrayLock, LW_SHARED);
3191 
3192  result = BackendPidGetProcWithLock(pid);
3193 
3194  LWLockRelease(ProcArrayLock);
3195 
3196  return result;
3197 }
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1170
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1783
@ LW_SHARED
Definition: lwlock.h:115
PGPROC * BackendPidGetProcWithLock(int pid)
Definition: procarray.c:3206
Definition: proc.h:157

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

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

◆ BackendPidGetProcWithLock()

PGPROC* BackendPidGetProcWithLock ( int  pid)

Definition at line 3206 of file procarray.c.

3207 {
3208  PGPROC *result = NULL;
3209  ProcArrayStruct *arrayP = procArray;
3210  int index;
3211 
3212  if (pid == 0) /* never match dummy PGPROCs */
3213  return NULL;
3214 
3215  for (index = 0; index < arrayP->numProcs; index++)
3216  {
3217  PGPROC *proc = &allProcs[arrayP->pgprocnos[index]];
3218 
3219  if (proc->pid == pid)
3220  {
3221  result = proc;
3222  break;
3223  }
3224  }
3225 
3226  return result;
3227 }
static PGPROC * allProcs
Definition: procarray.c:271
static ProcArrayStruct * procArray
Definition: procarray.c:269
int pid
Definition: proc.h:178
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:99
Definition: type.h:95

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

Referenced by BackendPidGetProc(), and GetBlockerStatusData().

◆ BackendXidGetPid()

int BackendXidGetPid ( TransactionId  xid)

Definition at line 3243 of file procarray.c.

3244 {
3245  int result = 0;
3246  ProcArrayStruct *arrayP = procArray;
3247  TransactionId *other_xids = ProcGlobal->xids;
3248  int index;
3249 
3250  if (xid == InvalidTransactionId) /* never match invalid xid */
3251  return 0;
3252 
3253  LWLockAcquire(ProcArrayLock, LW_SHARED);
3254 
3255  for (index = 0; index < arrayP->numProcs; index++)
3256  {
3257  if (other_xids[index] == xid)
3258  {
3259  int pgprocno = arrayP->pgprocnos[index];
3260  PGPROC *proc = &allProcs[pgprocno];
3261 
3262  result = proc->pid;
3263  break;
3264  }
3265  }
3266 
3267  LWLockRelease(ProcArrayLock);
3268 
3269  return result;
3270 }
uint32 TransactionId
Definition: c.h:652
PROC_HDR * ProcGlobal
Definition: proc.c:78
TransactionId * xids
Definition: proc.h:383
#define InvalidTransactionId
Definition: transam.h:31

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

Referenced by pgrowlocks().

◆ CancelDBBackends()

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

Definition at line 3647 of file procarray.c.

3648 {
3649  ProcArrayStruct *arrayP = procArray;
3650  int index;
3651 
3652  /* tell all backends to die */
3653  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3654 
3655  for (index = 0; index < arrayP->numProcs; index++)
3656  {
3657  int pgprocno = arrayP->pgprocnos[index];
3658  PGPROC *proc = &allProcs[pgprocno];
3659 
3660  if (databaseid == InvalidOid || proc->databaseId == databaseid)
3661  {
3662  VirtualTransactionId procvxid;
3663  pid_t pid;
3664 
3665  GET_VXID_FROM_PGPROC(procvxid, *proc);
3666 
3667  proc->recoveryConflictPending = conflictPending;
3668  pid = proc->pid;
3669  if (pid != 0)
3670  {
3671  /*
3672  * Kill the pid if it's still here. If not, that's what we
3673  * wanted so ignore any errors.
3674  */
3675  (void) SendProcSignal(pid, sigmode, procvxid.procNumber);
3676  }
3677  }
3678  }
3679 
3680  LWLockRelease(ProcArrayLock);
3681 }
#define GET_VXID_FROM_PGPROC(vxid_dst, proc)
Definition: lock.h:77
@ LW_EXCLUSIVE
Definition: lwlock.h:114
#define InvalidOid
Definition: postgres_ext.h:36
int SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
Definition: procsignal.c:257
bool recoveryConflictPending
Definition: proc.h:216
Oid databaseId
Definition: proc.h:203
ProcNumber procNumber
Definition: lock.h:61

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

Referenced by ResolveRecoveryConflictWithDatabase(), and SendRecoveryConflictWithBufferPin().

◆ CancelVirtualTransaction()

pid_t CancelVirtualTransaction ( VirtualTransactionId  vxid,
ProcSignalReason  sigmode 
)

Definition at line 3478 of file procarray.c.

3479 {
3480  return SignalVirtualTransaction(vxid, sigmode, true);
3481 }
pid_t SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode, bool conflictPending)
Definition: procarray.c:3484

References SignalVirtualTransaction().

Referenced by ResolveRecoveryConflictWithVirtualXIDs().

◆ ComputeXidHorizons()

static void ComputeXidHorizons ( ComputeXidHorizonsResult h)
static

Definition at line 1723 of file procarray.c.

1724 {
1725  ProcArrayStruct *arrayP = procArray;
1726  TransactionId kaxmin;
1727  bool in_recovery = RecoveryInProgress();
1728  TransactionId *other_xids = ProcGlobal->xids;
1729 
1730  /* inferred after ProcArrayLock is released */
1732 
1733  LWLockAcquire(ProcArrayLock, LW_SHARED);
1734 
1736 
1737  /*
1738  * We initialize the MIN() calculation with latestCompletedXid + 1. This
1739  * is a lower bound for the XIDs that might appear in the ProcArray later,
1740  * and so protects us against overestimating the result due to future
1741  * additions.
1742  */
1743  {
1744  TransactionId initial;
1745 
1747  Assert(TransactionIdIsValid(initial));
1748  TransactionIdAdvance(initial);
1749 
1750  h->oldest_considered_running = initial;
1751  h->shared_oldest_nonremovable = initial;
1752  h->data_oldest_nonremovable = initial;
1753 
1754  /*
1755  * Only modifications made by this backend affect the horizon for
1756  * temporary relations. Instead of a check in each iteration of the
1757  * loop over all PGPROCs it is cheaper to just initialize to the
1758  * current top-level xid any.
1759  *
1760  * Without an assigned xid we could use a horizon as aggressive as
1761  * GetNewTransactionId(), but we can get away with the much cheaper
1762  * latestCompletedXid + 1: If this backend has no xid there, by
1763  * definition, can't be any newer changes in the temp table than
1764  * latestCompletedXid.
1765  */
1768  else
1769  h->temp_oldest_nonremovable = initial;
1770  }
1771 
1772  /*
1773  * Fetch slot horizons while ProcArrayLock is held - the
1774  * LWLockAcquire/LWLockRelease are a barrier, ensuring this happens inside
1775  * the lock.
1776  */
1779 
1780  for (int index = 0; index < arrayP->numProcs; index++)
1781  {
1782  int pgprocno = arrayP->pgprocnos[index];
1783  PGPROC *proc = &allProcs[pgprocno];
1784  int8 statusFlags = ProcGlobal->statusFlags[index];
1785  TransactionId xid;
1786  TransactionId xmin;
1787 
1788  /* Fetch xid just once - see GetNewTransactionId */
1789  xid = UINT32_ACCESS_ONCE(other_xids[index]);
1790  xmin = UINT32_ACCESS_ONCE(proc->xmin);
1791 
1792  /*
1793  * Consider both the transaction's Xmin, and its Xid.
1794  *
1795  * We must check both because a transaction might have an Xmin but not
1796  * (yet) an Xid; conversely, if it has an Xid, that could determine
1797  * some not-yet-set Xmin.
1798  */
1799  xmin = TransactionIdOlder(xmin, xid);
1800 
1801  /* if neither is set, this proc doesn't influence the horizon */
1802  if (!TransactionIdIsValid(xmin))
1803  continue;
1804 
1805  /*
1806  * Don't ignore any procs when determining which transactions might be
1807  * considered running. While slots should ensure logical decoding
1808  * backends are protected even without this check, it can't hurt to
1809  * include them here as well..
1810  */
1813 
1814  /*
1815  * Skip over backends either vacuuming (which is ok with rows being
1816  * removed, as long as pg_subtrans is not truncated) or doing logical
1817  * decoding (which manages xmin separately, check below).
1818  */
1819  if (statusFlags & (PROC_IN_VACUUM | PROC_IN_LOGICAL_DECODING))
1820  continue;
1821 
1822  /* shared tables need to take backends in all databases into account */
1825 
1826  /*
1827  * Normally sessions in other databases are ignored for anything but
1828  * the shared horizon.
1829  *
1830  * However, include them when MyDatabaseId is not (yet) set. A
1831  * backend in the process of starting up must not compute a "too
1832  * aggressive" horizon, otherwise we could end up using it to prune
1833  * still-needed data away. If the current backend never connects to a
1834  * database this is harmless, because data_oldest_nonremovable will
1835  * never be utilized.
1836  *
1837  * Also, sessions marked with PROC_AFFECTS_ALL_HORIZONS should always
1838  * be included. (This flag is used for hot standby feedback, which
1839  * can't be tied to a specific database.)
1840  *
1841  * Also, while in recovery we cannot compute an accurate per-database
1842  * horizon, as all xids are managed via the KnownAssignedXids
1843  * machinery.
1844  */
1845  if (proc->databaseId == MyDatabaseId ||
1846  MyDatabaseId == InvalidOid ||
1847  (statusFlags & PROC_AFFECTS_ALL_HORIZONS) ||
1848  in_recovery)
1849  {
1852  }
1853  }
1854 
1855  /*
1856  * If in recovery fetch oldest xid in KnownAssignedXids, will be applied
1857  * after lock is released.
1858  */
1859  if (in_recovery)
1860  kaxmin = KnownAssignedXidsGetOldestXmin();
1861 
1862  /*
1863  * No other information from shared state is needed, release the lock
1864  * immediately. The rest of the computations can be done without a lock.
1865  */
1866  LWLockRelease(ProcArrayLock);
1867 
1868  if (in_recovery)
1869  {
1876  /* temp relations cannot be accessed in recovery */
1877  }
1878 
1883 
1884  /*
1885  * Check whether there are replication slots requiring an older xmin.
1886  */
1891 
1892  /*
1893  * The only difference between catalog / data horizons is that the slot's
1894  * catalog xmin is applied to the catalog one (so catalogs can be accessed
1895  * for logical decoding). Initialize with data horizon, and then back up
1896  * further if necessary. Have to back up the shared horizon as well, since
1897  * that also can contain catalogs.
1898  */
1902  h->slot_catalog_xmin);
1906  h->slot_catalog_xmin);
1907 
1908  /*
1909  * It's possible that slots backed up the horizons further than
1910  * oldest_considered_running. Fix.
1911  */
1921 
1922  /*
1923  * shared horizons have to be at least as old as the oldest visible in
1924  * current db
1925  */
1930 
1931  /*
1932  * Horizons need to ensure that pg_subtrans access is still possible for
1933  * the relevant backends.
1934  */
1945  h->slot_xmin));
1948  h->slot_catalog_xmin));
1949 
1950  /* update approximate horizons with the computed horizons */
1952 }
signed char int8
Definition: c.h:492
#define Assert(condition)
Definition: c.h:858
Oid MyDatabaseId
Definition: globals.c:91
#define PROC_IN_LOGICAL_DECODING
Definition: proc.h:61
#define PROC_AFFECTS_ALL_HORIZONS
Definition: proc.h:62
#define PROC_IN_VACUUM
Definition: proc.h:58
#define UINT32_ACCESS_ONCE(var)
Definition: procarray.c:68
static void GlobalVisUpdateApply(ComputeXidHorizonsResult *horizons)
Definition: procarray.c:4150
static TransactionId KnownAssignedXidsGetOldestXmin(void)
Definition: procarray.c:5143
PGPROC * MyProc
Definition: proc.c:66
TransactionId slot_catalog_xmin
Definition: procarray.c:192
TransactionId data_oldest_nonremovable
Definition: procarray.c:237
TransactionId temp_oldest_nonremovable
Definition: procarray.c:243
TransactionId shared_oldest_nonremovable
Definition: procarray.c:214
TransactionId oldest_considered_running
Definition: procarray.c:205
TransactionId slot_xmin
Definition: procarray.c:191
FullTransactionId latest_completed
Definition: procarray.c:185
TransactionId catalog_oldest_nonremovable
Definition: procarray.c:231
TransactionId shared_oldest_nonremovable_raw
Definition: procarray.c:225
TransactionId xmin
Definition: proc.h:173
TransactionId xid
Definition: proc.h:168
uint8 * statusFlags
Definition: proc.h:395
TransactionId replication_slot_xmin
Definition: procarray.c:94
TransactionId replication_slot_catalog_xmin
Definition: procarray.c:96
FullTransactionId latestCompletedXid
Definition: transam.h:238
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:299
#define XidFromFullTransactionId(x)
Definition: transam.h:48
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define TransactionIdAdvance(dest)
Definition: transam.h:91
static TransactionId TransactionIdOlder(TransactionId a, TransactionId b)
Definition: transam.h:334
TransamVariablesData * TransamVariables
Definition: varsup.c:34
bool RecoveryInProgress(void)
Definition: xlog.c:6290

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

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

◆ CountDBBackends()

int CountDBBackends ( Oid  databaseid)

Definition at line 3586 of file procarray.c.

3587 {
3588  ProcArrayStruct *arrayP = procArray;
3589  int count = 0;
3590  int index;
3591 
3592  LWLockAcquire(ProcArrayLock, LW_SHARED);
3593 
3594  for (index = 0; index < arrayP->numProcs; index++)
3595  {
3596  int pgprocno = arrayP->pgprocnos[index];
3597  PGPROC *proc = &allProcs[pgprocno];
3598 
3599  if (proc->pid == 0)
3600  continue; /* do not count prepared xacts */
3601  if (!OidIsValid(databaseid) ||
3602  proc->databaseId == databaseid)
3603  count++;
3604  }
3605 
3606  LWLockRelease(ProcArrayLock);
3607 
3608  return count;
3609 }
#define OidIsValid(objectId)
Definition: c.h:775

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

Referenced by ResolveRecoveryConflictWithDatabase().

◆ CountDBConnections()

int CountDBConnections ( Oid  databaseid)

Definition at line 3616 of file procarray.c.

3617 {
3618  ProcArrayStruct *arrayP = procArray;
3619  int count = 0;
3620  int index;
3621 
3622  LWLockAcquire(ProcArrayLock, LW_SHARED);
3623 
3624  for (index = 0; index < arrayP->numProcs; index++)
3625  {
3626  int pgprocno = arrayP->pgprocnos[index];
3627  PGPROC *proc = &allProcs[pgprocno];
3628 
3629  if (proc->pid == 0)
3630  continue; /* do not count prepared xacts */
3631  if (proc->isBackgroundWorker)
3632  continue; /* do not count background workers */
3633  if (!OidIsValid(databaseid) ||
3634  proc->databaseId == databaseid)
3635  count++;
3636  }
3637 
3638  LWLockRelease(ProcArrayLock);
3639 
3640  return count;
3641 }
bool isBackgroundWorker
Definition: proc.h:209

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

Referenced by CheckMyDatabase().

◆ CountOtherDBBackends()

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

Definition at line 3737 of file procarray.c.

3738 {
3739  ProcArrayStruct *arrayP = procArray;
3740 
3741 #define MAXAUTOVACPIDS 10 /* max autovacs to SIGTERM per iteration */
3742  int autovac_pids[MAXAUTOVACPIDS];
3743  int tries;
3744 
3745  /* 50 tries with 100ms sleep between tries makes 5 sec total wait */
3746  for (tries = 0; tries < 50; tries++)
3747  {
3748  int nautovacs = 0;
3749  bool found = false;
3750  int index;
3751 
3753 
3754  *nbackends = *nprepared = 0;
3755 
3756  LWLockAcquire(ProcArrayLock, LW_SHARED);
3757 
3758  for (index = 0; index < arrayP->numProcs; index++)
3759  {
3760  int pgprocno = arrayP->pgprocnos[index];
3761  PGPROC *proc = &allProcs[pgprocno];
3762  uint8 statusFlags = ProcGlobal->statusFlags[index];
3763 
3764  if (proc->databaseId != databaseId)
3765  continue;
3766  if (proc == MyProc)
3767  continue;
3768 
3769  found = true;
3770 
3771  if (proc->pid == 0)
3772  (*nprepared)++;
3773  else
3774  {
3775  (*nbackends)++;
3776  if ((statusFlags & PROC_IS_AUTOVACUUM) &&
3777  nautovacs < MAXAUTOVACPIDS)
3778  autovac_pids[nautovacs++] = proc->pid;
3779  }
3780  }
3781 
3782  LWLockRelease(ProcArrayLock);
3783 
3784  if (!found)
3785  return false; /* no conflicting backends, so done */
3786 
3787  /*
3788  * Send SIGTERM to any conflicting autovacuums before sleeping. We
3789  * postpone this step until after the loop because we don't want to
3790  * hold ProcArrayLock while issuing kill(). We have no idea what might
3791  * block kill() inside the kernel...
3792  */
3793  for (index = 0; index < nautovacs; index++)
3794  (void) kill(autovac_pids[index], SIGTERM); /* ignore any error */
3795 
3796  /* sleep, then try again */
3797  pg_usleep(100 * 1000L); /* 100ms */
3798  }
3799 
3800  return true; /* timed out, still conflicts */
3801 }
unsigned char uint8
Definition: c.h:504
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
#define PROC_IS_AUTOVACUUM
Definition: proc.h:57
#define MAXAUTOVACPIDS
void pg_usleep(long microsec)
Definition: signal.c:53
#define kill(pid, sig)
Definition: win32_port.h:485

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

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

◆ CountUserBackends()

int CountUserBackends ( Oid  roleid)

Definition at line 3687 of file procarray.c.

3688 {
3689  ProcArrayStruct *arrayP = procArray;
3690  int count = 0;
3691  int index;
3692 
3693  LWLockAcquire(ProcArrayLock, LW_SHARED);
3694 
3695  for (index = 0; index < arrayP->numProcs; index++)
3696  {
3697  int pgprocno = arrayP->pgprocnos[index];
3698  PGPROC *proc = &allProcs[pgprocno];
3699 
3700  if (proc->pid == 0)
3701  continue; /* do not count prepared xacts */
3702  if (proc->isBackgroundWorker)
3703  continue; /* do not count background workers */
3704  if (proc->roleId == roleid)
3705  count++;
3706  }
3707 
3708  LWLockRelease(ProcArrayLock);
3709 
3710  return count;
3711 }
Oid roleId
Definition: proc.h:204

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

Referenced by InitializeSessionUserId().

◆ CreateSharedProcArray()

void CreateSharedProcArray ( void  )

Definition at line 418 of file procarray.c.

419 {
420  bool found;
421 
422  /* Create or attach to the ProcArray shared structure */
424  ShmemInitStruct("Proc Array",
425  add_size(offsetof(ProcArrayStruct, pgprocnos),
426  mul_size(sizeof(int),
428  &found);
429 
430  if (!found)
431  {
432  /*
433  * We're the first - initialize.
434  */
435  procArray->numProcs = 0;
445  }
446 
448 
449  /* Create or attach to the KnownAssignedXids arrays too, if needed */
450  if (EnableHotStandby)
451  {
453  ShmemInitStruct("KnownAssignedXids",
454  mul_size(sizeof(TransactionId),
456  &found);
457  KnownAssignedXidsValid = (bool *)
458  ShmemInitStruct("KnownAssignedXidsValid",
459  mul_size(sizeof(bool), TOTAL_MAX_CACHED_SUBXIDS),
460  &found);
461  }
462 }
#define TOTAL_MAX_CACHED_SUBXIDS
#define PROCARRAY_MAXPROCS
static TransactionId * KnownAssignedXids
Definition: procarray.c:281
static bool * KnownAssignedXidsValid
Definition: procarray.c:282
Size add_size(Size s1, Size s2)
Definition: shmem.c:493
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:387
Size mul_size(Size s1, Size s2)
Definition: shmem.c:510
PGPROC * allProcs
Definition: proc.h:380
int maxKnownAssignedXids
Definition: procarray.c:79
int numKnownAssignedXids
Definition: procarray.c:80
TransactionId lastOverflowedXid
Definition: procarray.c:91
int tailKnownAssignedXids
Definition: procarray.c:81
int headKnownAssignedXids
Definition: procarray.c:82
uint64 xactCompletionCount
Definition: transam.h:248
bool EnableHotStandby
Definition: xlog.c:121

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

Referenced by CreateOrAttachShmemStructs().

◆ ExpireAllKnownAssignedTransactionIds()

void ExpireAllKnownAssignedTransactionIds ( void  )

Definition at line 4482 of file procarray.c.

4483 {
4484  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4486 
4487  /*
4488  * Reset lastOverflowedXid. Currently, lastOverflowedXid has no use after
4489  * the call of this function. But do this for unification with what
4490  * ExpireOldKnownAssignedTransactionIds() do.
4491  */
4493  LWLockRelease(ProcArrayLock);
4494 }
static void KnownAssignedXidsRemovePreceding(TransactionId removeXid)
Definition: procarray.c:4995

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

Referenced by ShutdownRecoveryTransactionEnvironment().

◆ ExpireOldKnownAssignedTransactionIds()

void ExpireOldKnownAssignedTransactionIds ( TransactionId  xid)

Definition at line 4502 of file procarray.c.

4503 {
4504  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4505 
4506  /*
4507  * Reset lastOverflowedXid if we know all transactions that have been
4508  * possibly running are being gone. Not doing so could cause an incorrect
4509  * lastOverflowedXid value, which makes extra snapshots be marked as
4510  * suboverflowed.
4511  */
4515  LWLockRelease(ProcArrayLock);
4516 }
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:280

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

Referenced by ProcArrayApplyRecoveryInfo().

◆ ExpireTreeKnownAssignedTransactionIds()

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

Definition at line 4456 of file procarray.c.

4458 {
4460 
4461  /*
4462  * Uses same locking as transaction commit
4463  */
4464  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4465 
4466  KnownAssignedXidsRemoveTree(xid, nsubxids, subxids);
4467 
4468  /* As in ProcArrayEndTransaction, advance latestCompletedXid */
4470 
4471  /* ... and xactCompletionCount */
4473 
4474  LWLockRelease(ProcArrayLock);
4475 }
static void KnownAssignedXidsRemoveTree(TransactionId xid, int nsubxids, TransactionId *subxids)
Definition: procarray.c:4973
static void MaintainLatestCompletedXidRecovery(TransactionId latestXid)
Definition: procarray.c:989
HotStandbyState standbyState
Definition: xlogutils.c:53
@ STANDBY_INITIALIZED
Definition: xlogutils.h:50

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

Referenced by xact_redo_abort(), and xact_redo_commit().

◆ FullXidRelativeTo()

static FullTransactionId FullXidRelativeTo ( FullTransactionId  rel,
TransactionId  xid 
)
inlinestatic

Definition at line 4305 of file procarray.c.

4306 {
4307  TransactionId rel_xid = XidFromFullTransactionId(rel);
4308 
4310  Assert(TransactionIdIsValid(rel_xid));
4311 
4312  /* not guaranteed to find issues, but likely to catch mistakes */
4314 
4316  + (int32) (xid - rel_xid));
4317 }
signed int int32
Definition: c.h:494
#define U64FromFullTransactionId(x)
Definition: transam.h:49
static FullTransactionId FullTransactionIdFromU64(uint64 value)
Definition: transam.h:81
#define AssertTransactionIdInAllowableRange(xid)
Definition: transam.h:301

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

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

◆ GetConflictingVirtualXIDs()

VirtualTransactionId* GetConflictingVirtualXIDs ( TransactionId  limitXmin,
Oid  dbOid 
)

Definition at line 3404 of file procarray.c.

3405 {
3406  static VirtualTransactionId *vxids;
3407  ProcArrayStruct *arrayP = procArray;
3408  int count = 0;
3409  int index;
3410 
3411  /*
3412  * If first time through, get workspace to remember main XIDs in. We
3413  * malloc it permanently to avoid repeated palloc/pfree overhead. Allow
3414  * result space, remembering room for a terminator.
3415  */
3416  if (vxids == NULL)
3417  {
3418  vxids = (VirtualTransactionId *)
3419  malloc(sizeof(VirtualTransactionId) * (arrayP->maxProcs + 1));
3420  if (vxids == NULL)
3421  ereport(ERROR,
3422  (errcode(ERRCODE_OUT_OF_MEMORY),
3423  errmsg("out of memory")));
3424  }
3425 
3426  LWLockAcquire(ProcArrayLock, LW_SHARED);
3427 
3428  for (index = 0; index < arrayP->numProcs; index++)
3429  {
3430  int pgprocno = arrayP->pgprocnos[index];
3431  PGPROC *proc = &allProcs[pgprocno];
3432 
3433  /* Exclude prepared transactions */
3434  if (proc->pid == 0)
3435  continue;
3436 
3437  if (!OidIsValid(dbOid) ||
3438  proc->databaseId == dbOid)
3439  {
3440  /* Fetch xmin just once - can't change on us, but good coding */
3441  TransactionId pxmin = UINT32_ACCESS_ONCE(proc->xmin);
3442 
3443  /*
3444  * We ignore an invalid pxmin because this means that backend has
3445  * no snapshot currently. We hold a Share lock to avoid contention
3446  * with users taking snapshots. That is not a problem because the
3447  * current xmin is always at least one higher than the latest
3448  * removed xid, so any new snapshot would never conflict with the
3449  * test here.
3450  */
3451  if (!TransactionIdIsValid(limitXmin) ||
3452  (TransactionIdIsValid(pxmin) && !TransactionIdFollows(pxmin, limitXmin)))
3453  {
3454  VirtualTransactionId vxid;
3455 
3456  GET_VXID_FROM_PGPROC(vxid, *proc);
3457  if (VirtualTransactionIdIsValid(vxid))
3458  vxids[count++] = vxid;
3459  }
3460  }
3461  }
3462 
3463  LWLockRelease(ProcArrayLock);
3464 
3465  /* add the terminator */
3466  vxids[count].procNumber = INVALID_PROC_NUMBER;
3468 
3469  return vxids;
3470 }
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#define malloc(a)
Definition: header.h:50
#define VirtualTransactionIdIsValid(vxid)
Definition: lock.h:67
#define InvalidLocalTransactionId
Definition: lock.h:65
#define INVALID_PROC_NUMBER
Definition: procnumber.h:26
LocalTransactionId localTransactionId
Definition: lock.h:62
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:314

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

Referenced by ResolveRecoveryConflictWithSnapshot(), and ResolveRecoveryConflictWithTablespace().

◆ GetCurrentVirtualXIDs()

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

Definition at line 3311 of file procarray.c.

3314 {
3315  VirtualTransactionId *vxids;
3316  ProcArrayStruct *arrayP = procArray;
3317  int count = 0;
3318  int index;
3319 
3320  /* allocate what's certainly enough result space */
3321  vxids = (VirtualTransactionId *)
3322  palloc(sizeof(VirtualTransactionId) * arrayP->maxProcs);
3323 
3324  LWLockAcquire(ProcArrayLock, LW_SHARED);
3325 
3326  for (index = 0; index < arrayP->numProcs; index++)
3327  {
3328  int pgprocno = arrayP->pgprocnos[index];
3329  PGPROC *proc = &allProcs[pgprocno];
3330  uint8 statusFlags = ProcGlobal->statusFlags[index];
3331 
3332  if (proc == MyProc)
3333  continue;
3334 
3335  if (excludeVacuum & statusFlags)
3336  continue;
3337 
3338  if (allDbs || proc->databaseId == MyDatabaseId)
3339  {
3340  /* Fetch xmin just once - might change on us */
3341  TransactionId pxmin = UINT32_ACCESS_ONCE(proc->xmin);
3342 
3343  if (excludeXmin0 && !TransactionIdIsValid(pxmin))
3344  continue;
3345 
3346  /*
3347  * InvalidTransactionId precedes all other XIDs, so a proc that
3348  * hasn't set xmin yet will not be rejected by this test.
3349  */
3350  if (!TransactionIdIsValid(limitXmin) ||
3351  TransactionIdPrecedesOrEquals(pxmin, limitXmin))
3352  {
3353  VirtualTransactionId vxid;
3354 
3355  GET_VXID_FROM_PGPROC(vxid, *proc);
3356  if (VirtualTransactionIdIsValid(vxid))
3357  vxids[count++] = vxid;
3358  }
3359  }
3360  }
3361 
3362  LWLockRelease(ProcArrayLock);
3363 
3364  *nvxids = count;
3365  return vxids;
3366 }
void * palloc(Size size)
Definition: mcxt.c:1316

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

Referenced by WaitForOlderSnapshots().

◆ GetMaxSnapshotSubxidCount()

int GetMaxSnapshotSubxidCount ( void  )

Definition at line 2068 of file procarray.c.

2069 {
2070  return TOTAL_MAX_CACHED_SUBXIDS;
2071 }

References TOTAL_MAX_CACHED_SUBXIDS.

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

◆ GetMaxSnapshotXidCount()

int GetMaxSnapshotXidCount ( void  )

Definition at line 2057 of file procarray.c.

2058 {
2059  return procArray->maxProcs;
2060 }

References ProcArrayStruct::maxProcs, and procArray.

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

◆ GetOldestActiveTransactionId()

TransactionId GetOldestActiveTransactionId ( void  )

Definition at line 2867 of file procarray.c.

2868 {
2869  ProcArrayStruct *arrayP = procArray;
2870  TransactionId *other_xids = ProcGlobal->xids;
2871  TransactionId oldestRunningXid;
2872  int index;
2873 
2875 
2876  /*
2877  * Read nextXid, as the upper bound of what's still active.
2878  *
2879  * Reading a TransactionId is atomic, but we must grab the lock to make
2880  * sure that all XIDs < nextXid are already present in the proc array (or
2881  * have already completed), when we spin over it.
2882  */
2883  LWLockAcquire(XidGenLock, LW_SHARED);
2884  oldestRunningXid = XidFromFullTransactionId(TransamVariables->nextXid);
2885  LWLockRelease(XidGenLock);
2886 
2887  /*
2888  * Spin over procArray collecting all xids and subxids.
2889  */
2890  LWLockAcquire(ProcArrayLock, LW_SHARED);
2891  for (index = 0; index < arrayP->numProcs; index++)
2892  {
2893  TransactionId xid;
2894 
2895  /* Fetch xid just once - see GetNewTransactionId */
2896  xid = UINT32_ACCESS_ONCE(other_xids[index]);
2897 
2898  if (!TransactionIdIsNormal(xid))
2899  continue;
2900 
2901  if (TransactionIdPrecedes(xid, oldestRunningXid))
2902  oldestRunningXid = xid;
2903 
2904  /*
2905  * Top-level XID of a transaction is always less than any of its
2906  * subxids, so we don't need to check if any of the subxids are
2907  * smaller than oldestRunningXid
2908  */
2909  }
2910  LWLockRelease(ProcArrayLock);
2911 
2912  return oldestRunningXid;
2913 }
FullTransactionId nextXid
Definition: transam.h:220
#define TransactionIdIsNormal(xid)
Definition: transam.h:42

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

Referenced by CreateCheckPoint().

◆ GetOldestNonRemovableTransactionId()

TransactionId GetOldestNonRemovableTransactionId ( Relation  rel)

Definition at line 1993 of file procarray.c.

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

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

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

◆ GetOldestSafeDecodingTransactionId()

TransactionId GetOldestSafeDecodingTransactionId ( bool  catalogOnly)

Definition at line 2932 of file procarray.c.

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

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

Referenced by CreateInitDecodingContext(), SnapBuildInitialSnapshot(), and synchronize_one_slot().

◆ GetOldestTransactionIdConsideredRunning()

TransactionId GetOldestTransactionIdConsideredRunning ( void  )

Definition at line 2022 of file procarray.c.

2023 {
2024  ComputeXidHorizonsResult horizons;
2025 
2026  ComputeXidHorizons(&horizons);
2027 
2028  return horizons.oldest_considered_running;
2029 }

References ComputeXidHorizons(), and ComputeXidHorizonsResult::oldest_considered_running.

Referenced by CreateCheckPoint(), and CreateRestartPoint().

◆ GetReplicationHorizons()

void GetReplicationHorizons ( TransactionId xmin,
TransactionId catalog_xmin 
)

Definition at line 2035 of file procarray.c.

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

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

Referenced by XLogWalRcvSendHSFeedback().

◆ GetRunningTransactionData()

RunningTransactions GetRunningTransactionData ( void  )

Definition at line 2681 of file procarray.c.

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

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

Referenced by GetStrictOldestNonRemovableTransactionId(), and LogStandbySnapshot().

◆ GetSnapshotData()

Snapshot GetSnapshotData ( Snapshot  snapshot)

Definition at line 2165 of file procarray.c.

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

References SnapshotData::active_count, allProcs, Assert, SnapshotData::copied, XidCacheStatus::count, SnapshotData::curcid, GlobalVisState::definitely_needed, ereport, errcode(), errmsg(), ERROR, FullTransactionIdAdvance(), FullTransactionIdNewer(), FullXidRelativeTo(), GetCurrentCommandId(), GetMaxSnapshotSubxidCount(), GetMaxSnapshotXidCount(), GetSnapshotDataReuse(), GlobalVisCatalogRels, GlobalVisDataRels, GlobalVisSharedRels, GlobalVisTempRels, InvalidTransactionId, InvalidXLogRecPtr, KnownAssignedXidsGetAndSetXmin(), ProcArrayStruct::lastOverflowedXid, TransamVariablesData::latestCompletedXid, likely, SnapshotData::lsn, LW_SHARED, LWLockAcquire(), LWLockRelease(), malloc, GlobalVisState::maybe_needed, MyProc, NormalTransactionIdPrecedes, ProcArrayStruct::numProcs, TransamVariablesData::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, SnapshotData::snapXactCompletionCount, PROC_HDR::statusFlags, SnapshotData::suboverflowed, SnapshotData::subxcnt, PGPROC::subxids, PROC_HDR::subxidStates, SnapshotData::subxip, SnapshotData::takenDuringRecovery, TransactionIdAdvance, TransactionIdIsNormal, TransactionIdIsValid, TransactionIdOlder(), TransactionIdPrecedesOrEquals(), TransactionXmin, TransamVariables, UINT32_ACCESS_ONCE, SnapshotData::whenTaken, TransamVariablesData::xactCompletionCount, SnapshotData::xcnt, PGPROC::xid, XidFromFullTransactionId, XidCache::xids, PROC_HDR::xids, SnapshotData::xip, SnapshotData::xmax, PGPROC::xmin, and SnapshotData::xmin.

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

◆ GetSnapshotDataReuse()

static bool GetSnapshotDataReuse ( Snapshot  snapshot)
static

Definition at line 2083 of file procarray.c.

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

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

Referenced by GetSnapshotData().

◆ GetVirtualXIDsDelayingChkpt()

VirtualTransactionId* GetVirtualXIDsDelayingChkpt ( int *  nvxids,
int  type 
)

Definition at line 3030 of file procarray.c.

3031 {
3032  VirtualTransactionId *vxids;
3033  ProcArrayStruct *arrayP = procArray;
3034  int count = 0;
3035  int index;
3036 
3037  Assert(type != 0);
3038 
3039  /* allocate what's certainly enough result space */
3040  vxids = (VirtualTransactionId *)
3041  palloc(sizeof(VirtualTransactionId) * arrayP->maxProcs);
3042 
3043  LWLockAcquire(ProcArrayLock, LW_SHARED);
3044 
3045  for (index = 0; index < arrayP->numProcs; index++)
3046  {
3047  int pgprocno = arrayP->pgprocnos[index];
3048  PGPROC *proc = &allProcs[pgprocno];
3049 
3050  if ((proc->delayChkptFlags & type) != 0)
3051  {
3052  VirtualTransactionId vxid;
3053 
3054  GET_VXID_FROM_PGPROC(vxid, *proc);
3055  if (VirtualTransactionIdIsValid(vxid))
3056  vxids[count++] = vxid;
3057  }
3058  }
3059 
3060  LWLockRelease(ProcArrayLock);
3061 
3062  *nvxids = count;
3063  return vxids;
3064 }
int delayChkptFlags
Definition: proc.h:236
const char * type

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

Referenced by CreateCheckPoint().

◆ GlobalVisCheckRemovableFullXid()

bool GlobalVisCheckRemovableFullXid ( Relation  rel,
FullTransactionId  fxid 
)

Definition at line 4270 of file procarray.c.

4271 {
4273 
4274  state = GlobalVisTestFor(rel);
4275 
4276  return GlobalVisTestIsRemovableFullXid(state, fxid);
4277 }
bool GlobalVisTestIsRemovableFullXid(GlobalVisState *state, FullTransactionId fxid)
Definition: procarray.c:4206
GlobalVisState * GlobalVisTestFor(Relation rel)
Definition: procarray.c:4091
Definition: regguts.h:323

References GlobalVisTestFor(), and GlobalVisTestIsRemovableFullXid().

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

◆ GlobalVisCheckRemovableXid()

bool GlobalVisCheckRemovableXid ( Relation  rel,
TransactionId  xid 
)

Definition at line 4284 of file procarray.c.

4285 {
4287 
4288  state = GlobalVisTestFor(rel);
4289 
4290  return GlobalVisTestIsRemovableXid(state, xid);
4291 }
bool GlobalVisTestIsRemovableXid(GlobalVisState *state, TransactionId xid)
Definition: procarray.c:4248

References GlobalVisTestFor(), and GlobalVisTestIsRemovableXid().

Referenced by GinPageIsRecyclable().

◆ GlobalVisHorizonKindForRel()

static GlobalVisHorizonKind GlobalVisHorizonKindForRel ( Relation  rel)
inlinestatic

Definition at line 1959 of file procarray.c.

1960 {
1961  /*
1962  * Other relkinds currently don't contain xids, nor always the necessary
1963  * logical decoding markers.
1964  */
1965  Assert(!rel ||
1966  rel->rd_rel->relkind == RELKIND_RELATION ||
1967  rel->rd_rel->relkind == RELKIND_MATVIEW ||
1968  rel->rd_rel->relkind == RELKIND_TOASTVALUE);
1969 
1970  if (rel == NULL || rel->rd_rel->relisshared || RecoveryInProgress())
1971  return VISHORIZON_SHARED;
1972  else if (IsCatalogRelation(rel) ||
1974  return VISHORIZON_CATALOG;
1975  else if (!RELATION_IS_LOCAL(rel))
1976  return VISHORIZON_DATA;
1977  else
1978  return VISHORIZON_TEMP;
1979 }
bool IsCatalogRelation(Relation relation)
Definition: catalog.c:103
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:648
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:684
Form_pg_class rd_rel
Definition: rel.h:111

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

Referenced by GetOldestNonRemovableTransactionId(), and GlobalVisTestFor().

◆ GlobalVisTestFor()

GlobalVisState* GlobalVisTestFor ( Relation  rel)

Definition at line 4091 of file procarray.c.

4092 {
4093  GlobalVisState *state = NULL;
4094 
4095  /* XXX: we should assert that a snapshot is pushed or registered */
4096  Assert(RecentXmin);
4097 
4098  switch (GlobalVisHorizonKindForRel(rel))
4099  {
4100  case VISHORIZON_SHARED:
4102  break;
4103  case VISHORIZON_CATALOG:
4105  break;
4106  case VISHORIZON_DATA:
4108  break;
4109  case VISHORIZON_TEMP:
4111  break;
4112  }
4113 
4114  Assert(FullTransactionIdIsValid(state->definitely_needed) &&
4115  FullTransactionIdIsValid(state->maybe_needed));
4116 
4117  return state;
4118 }
#define FullTransactionIdIsValid(x)
Definition: transam.h:55

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

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

◆ GlobalVisTestIsRemovableFullXid()

bool GlobalVisTestIsRemovableFullXid ( GlobalVisState state,
FullTransactionId  fxid 
)

Definition at line 4206 of file procarray.c.

4208 {
4209  /*
4210  * If fxid is older than maybe_needed bound, it definitely is visible to
4211  * everyone.
4212  */
4213  if (FullTransactionIdPrecedes(fxid, state->maybe_needed))
4214  return true;
4215 
4216  /*
4217  * If fxid is >= definitely_needed bound, it is very likely to still be
4218  * considered running.
4219  */
4220  if (FullTransactionIdFollowsOrEquals(fxid, state->definitely_needed))
4221  return false;
4222 
4223  /*
4224  * fxid is between maybe_needed and definitely_needed, i.e. there might or
4225  * might not exist a snapshot considering fxid running. If it makes sense,
4226  * update boundaries and recheck.
4227  */
4229  {
4230  GlobalVisUpdate();
4231 
4232  Assert(FullTransactionIdPrecedes(fxid, state->definitely_needed));
4233 
4234  return FullTransactionIdPrecedes(fxid, state->maybe_needed);
4235  }
4236  else
4237  return false;
4238 }
static bool GlobalVisTestShouldUpdate(GlobalVisState *state)
Definition: procarray.c:4131
static void GlobalVisUpdate(void)
Definition: procarray.c:4189
#define FullTransactionIdFollowsOrEquals(a, b)
Definition: transam.h:54
#define FullTransactionIdPrecedes(a, b)
Definition: transam.h:51

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

Referenced by GlobalVisCheckRemovableFullXid(), and GlobalVisTestIsRemovableXid().

◆ GlobalVisTestIsRemovableXid()

bool GlobalVisTestIsRemovableXid ( GlobalVisState state,
TransactionId  xid 
)

Definition at line 4248 of file procarray.c.

4249 {
4250  FullTransactionId fxid;
4251 
4252  /*
4253  * Convert 32 bit argument to FullTransactionId. We can do so safely
4254  * because we know the xid has to, at the very least, be between
4255  * [oldestXid, nextXid), i.e. within 2 billion of xid. To avoid taking a
4256  * lock to determine either, we can just compare with
4257  * state->definitely_needed, which was based on those value at the time
4258  * the current snapshot was built.
4259  */
4260  fxid = FullXidRelativeTo(state->definitely_needed, xid);
4261 
4262  return GlobalVisTestIsRemovableFullXid(state, fxid);
4263 }

References FullXidRelativeTo(), and GlobalVisTestIsRemovableFullXid().

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

◆ GlobalVisTestShouldUpdate()

static bool GlobalVisTestShouldUpdate ( GlobalVisState state)
static

Definition at line 4131 of file procarray.c.

4132 {
4133  /* hasn't been updated yet */
4135  return true;
4136 
4137  /*
4138  * If the maybe_needed/definitely_needed boundaries are the same, it's
4139  * unlikely to be beneficial to refresh boundaries.
4140  */
4141  if (FullTransactionIdFollowsOrEquals(state->maybe_needed,
4142  state->definitely_needed))
4143  return false;
4144 
4145  /* does the last snapshot built have a different xmin? */
4147 }
static TransactionId ComputeXidHorizonsResultLastXmin
Definition: procarray.c:307

References ComputeXidHorizonsResultLastXmin, FullTransactionIdFollowsOrEquals, RecentXmin, and TransactionIdIsValid.

Referenced by GlobalVisTestIsRemovableFullXid().

◆ GlobalVisUpdate()

static void GlobalVisUpdate ( void  )
static

Definition at line 4189 of file procarray.c.

4190 {
4191  ComputeXidHorizonsResult horizons;
4192 
4193  /* updates the horizons as a side-effect */
4194  ComputeXidHorizons(&horizons);
4195 }

References ComputeXidHorizons().

Referenced by GlobalVisTestIsRemovableFullXid().

◆ GlobalVisUpdateApply()

static void GlobalVisUpdateApply ( ComputeXidHorizonsResult horizons)
static

Definition at line 4150 of file procarray.c.

4151 {
4154  horizons->shared_oldest_nonremovable);
4157  horizons->catalog_oldest_nonremovable);
4160  horizons->data_oldest_nonremovable);
4163  horizons->temp_oldest_nonremovable);
4164 
4165  /*
4166  * In longer running transactions it's possible that transactions we
4167  * previously needed to treat as running aren't around anymore. So update
4168  * definitely_needed to not be earlier than maybe_needed.
4169  */
4180 
4182 }

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

Referenced by ComputeXidHorizons().

◆ HaveVirtualXIDsDelayingChkpt()

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

Definition at line 3076 of file procarray.c.

3077 {
3078  bool result = false;
3079  ProcArrayStruct *arrayP = procArray;
3080  int index;
3081 
3082  Assert(type != 0);
3083 
3084  LWLockAcquire(ProcArrayLock, LW_SHARED);
3085 
3086  for (index = 0; index < arrayP->numProcs; index++)
3087  {
3088  int pgprocno = arrayP->pgprocnos[index];
3089  PGPROC *proc = &allProcs[pgprocno];
3090  VirtualTransactionId vxid;
3091 
3092  GET_VXID_FROM_PGPROC(vxid, *proc);
3093 
3094  if ((proc->delayChkptFlags & type) != 0 &&
3096  {
3097  int i;
3098 
3099  for (i = 0; i < nvxids; i++)
3100  {
3101  if (VirtualTransactionIdEquals(vxid, vxids[i]))
3102  {
3103  result = true;
3104  break;
3105  }
3106  }
3107  if (result)
3108  break;
3109  }
3110  }
3111 
3112  LWLockRelease(ProcArrayLock);
3113 
3114  return result;
3115 }
int i
Definition: isn.c:73
#define VirtualTransactionIdEquals(vxid1, vxid2)
Definition: lock.h:71

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

Referenced by CreateCheckPoint().

◆ IsBackendPid()

bool IsBackendPid ( int  pid)

Definition at line 3278 of file procarray.c.

3279 {
3280  return (BackendPidGetProc(pid) != NULL);
3281 }
PGPROC * BackendPidGetProc(int pid)
Definition: procarray.c:3183

References BackendPidGetProc().

Referenced by pg_stat_get_subscription().

◆ KnownAssignedTransactionIdsIdleMaintenance()

void KnownAssignedTransactionIdsIdleMaintenance ( void  )

Definition at line 4524 of file procarray.c.

4525 {
4527 }
static void KnownAssignedXidsCompress(KAXCompressReason reason, bool haveLock)
Definition: procarray.c:4625

References KAX_STARTUP_PROCESS_IDLE, and KnownAssignedXidsCompress().

Referenced by WaitForWALToBecomeAvailable().

◆ KnownAssignedXidExists()

static bool KnownAssignedXidExists ( TransactionId  xid)
static

Definition at line 4934 of file procarray.c.

4935 {
4937 
4938  return KnownAssignedXidsSearch(xid, false);
4939 }
static bool KnownAssignedXidsSearch(TransactionId xid, bool remove)
Definition: procarray.c:4846

References Assert, KnownAssignedXidsSearch(), and TransactionIdIsValid.

Referenced by TransactionIdIsInProgress().

◆ KnownAssignedXidsAdd()

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

Definition at line 4742 of file procarray.c.

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

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

Referenced by ProcArrayApplyRecoveryInfo(), and RecordKnownAssignedTransactionIds().

◆ KnownAssignedXidsCompress()

static void KnownAssignedXidsCompress ( KAXCompressReason  reason,
bool  haveLock 
)
static

Definition at line 4625 of file procarray.c.

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

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

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

◆ KnownAssignedXidsDisplay()

static void KnownAssignedXidsDisplay ( int  trace_level)
static

Definition at line 5178 of file procarray.c.

5179 {
5180  ProcArrayStruct *pArray = procArray;
5182  int head,
5183  tail,
5184  i;
5185  int nxids = 0;
5186 
5187  tail = pArray->tailKnownAssignedXids;
5188  head = pArray->headKnownAssignedXids;
5189 
5190  initStringInfo(&buf);
5191 
5192  for (i = tail; i < head; i++)
5193  {
5195  {
5196  nxids++;
5197  appendStringInfo(&buf, "[%d]=%u ", i, KnownAssignedXids[i]);
5198  }
5199  }
5200 
5201  elog(trace_level, "%d KnownAssignedXids (num=%d tail=%d head=%d) %s",
5202  nxids,
5203  pArray->numKnownAssignedXids,
5204  pArray->tailKnownAssignedXids,
5205  pArray->headKnownAssignedXids,
5206  buf.data);
5207 
5208  pfree(buf.data);
5209 }
void pfree(void *pointer)
Definition: mcxt.c:1520
static char * buf
Definition: pg_test_fsync.c:73
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59

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

Referenced by KnownAssignedXidsAdd(), and ProcArrayApplyRecoveryInfo().

◆ KnownAssignedXidsGet()

static int KnownAssignedXidsGet ( TransactionId xarray,
TransactionId  xmax 
)
static

Definition at line 5073 of file procarray.c.

5074 {
5076 
5077  return KnownAssignedXidsGetAndSetXmin(xarray, &xtmp, xmax);
5078 }

References InvalidTransactionId, and KnownAssignedXidsGetAndSetXmin().

Referenced by TransactionIdIsInProgress().

◆ KnownAssignedXidsGetAndSetXmin()

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

Definition at line 5087 of file procarray.c.

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

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

Referenced by GetSnapshotData(), and KnownAssignedXidsGet().

◆ KnownAssignedXidsGetOldestXmin()

static TransactionId KnownAssignedXidsGetOldestXmin ( void  )
static

Definition at line 5143 of file procarray.c.

5144 {
5145  int head,
5146  tail;
5147  int i;
5148 
5149  /*
5150  * Fetch head just once, since it may change while we loop.
5151  */
5154 
5155  pg_read_barrier(); /* pairs with KnownAssignedXidsAdd */
5156 
5157  for (i = tail; i < head; i++)
5158  {
5159  /* Skip any gaps in the array */
5161  return KnownAssignedXids[i];
5162  }
5163 
5164  return InvalidTransactionId;
5165 }

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

Referenced by ComputeXidHorizons().

◆ KnownAssignedXidsRemove()

static void KnownAssignedXidsRemove ( TransactionId  xid)
static

Definition at line 4947 of file procarray.c.

4948 {
4950 
4951  elog(DEBUG4, "remove KnownAssignedXid %u", xid);
4952 
4953  /*
4954  * Note: we cannot consider it an error to remove an XID that's not
4955  * present. We intentionally remove subxact IDs while processing
4956  * XLOG_XACT_ASSIGNMENT, to avoid array overflow. Then those XIDs will be
4957  * removed again when the top-level xact commits or aborts.
4958  *
4959  * It might be possible to track such XIDs to distinguish this case from
4960  * actual errors, but it would be complicated and probably not worth it.
4961  * So, just ignore the search result.
4962  */
4963  (void) KnownAssignedXidsSearch(xid, true);
4964 }
#define DEBUG4
Definition: elog.h:27

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

Referenced by KnownAssignedXidsRemoveTree().

◆ KnownAssignedXidsRemovePreceding()

static void KnownAssignedXidsRemovePreceding ( TransactionId  removeXid)
static

Definition at line 4995 of file procarray.c.

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

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

Referenced by ExpireAllKnownAssignedTransactionIds(), and ExpireOldKnownAssignedTransactionIds().

◆ KnownAssignedXidsRemoveTree()

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

Definition at line 4973 of file procarray.c.

4975 {
4976  int i;
4977 
4978  if (TransactionIdIsValid(xid))
4980 
4981  for (i = 0; i < nsubxids; i++)
4982  KnownAssignedXidsRemove(subxids[i]);
4983 
4984  /* Opportunistically compress the array */
4986 }
static void KnownAssignedXidsRemove(TransactionId xid)
Definition: procarray.c:4947

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

Referenced by ExpireTreeKnownAssignedTransactionIds(), and ProcArrayApplyXidAssignment().

◆ KnownAssignedXidsReset()

static void KnownAssignedXidsReset ( void  )
static

Definition at line 5216 of file procarray.c.

5217 {
5218  ProcArrayStruct *pArray = procArray;
5219 
5220  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
5221 
5222  pArray->numKnownAssignedXids = 0;
5223  pArray->tailKnownAssignedXids = 0;
5224  pArray->headKnownAssignedXids = 0;
5225 
5226  LWLockRelease(ProcArrayLock);
5227 }

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

Referenced by ProcArrayApplyRecoveryInfo().

◆ KnownAssignedXidsSearch()

static bool KnownAssignedXidsSearch ( TransactionId  xid,
bool  remove 
)
static

Definition at line 4846 of file procarray.c.

4847 {
4848  ProcArrayStruct *pArray = procArray;
4849  int first,
4850  last;
4851  int head;
4852  int tail;
4853  int result_index = -1;
4854 
4855  tail = pArray->tailKnownAssignedXids;
4856  head = pArray->headKnownAssignedXids;
4857 
4858  /*
4859  * Only the startup process removes entries, so we don't need the read
4860  * barrier in that case.
4861  */
4862  if (!remove)
4863  pg_read_barrier(); /* pairs with KnownAssignedXidsAdd */
4864 
4865  /*
4866  * Standard binary search. Note we can ignore the KnownAssignedXidsValid
4867  * array here, since even invalid entries will contain sorted XIDs.
4868  */
4869  first = tail;
4870  last = head - 1;
4871  while (first <= last)
4872  {
4873  int mid_index;
4874  TransactionId mid_xid;
4875 
4876  mid_index = (first + last) / 2;
4877  mid_xid = KnownAssignedXids[mid_index];
4878 
4879  if (xid == mid_xid)
4880  {
4881  result_index = mid_index;
4882  break;
4883  }
4884  else if (TransactionIdPrecedes(xid, mid_xid))
4885  last = mid_index - 1;
4886  else
4887  first = mid_index + 1;
4888  }
4889 
4890  if (result_index < 0)
4891  return false; /* not in array */
4892 
4893  if (!KnownAssignedXidsValid[result_index])
4894  return false; /* in array, but invalid */
4895 
4896  if (remove)
4897  {
4898  KnownAssignedXidsValid[result_index] = false;
4899 
4900  pArray->numKnownAssignedXids--;
4901  Assert(pArray->numKnownAssignedXids >= 0);
4902 
4903  /*
4904  * If we're removing the tail element then advance tail pointer over
4905  * any invalid elements. This will speed future searches.
4906  */
4907  if (result_index == tail)
4908  {
4909  tail++;
4910  while (tail < head && !KnownAssignedXidsValid[tail])
4911  tail++;
4912  if (tail >= head)
4913  {
4914  /* Array is empty, so we can reset both pointers */
4915  pArray->headKnownAssignedXids = 0;
4916  pArray->tailKnownAssignedXids = 0;
4917  }
4918  else
4919  {
4920  pArray->tailKnownAssignedXids = tail;
4921  }
4922  }
4923  }
4924 
4925  return true;
4926 }

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

Referenced by KnownAssignedXidExists(), and KnownAssignedXidsRemove().

◆ MaintainLatestCompletedXid()

static void MaintainLatestCompletedXid ( TransactionId  latestXid)
static

◆ MaintainLatestCompletedXidRecovery()

static void MaintainLatestCompletedXidRecovery ( TransactionId  latestXid)
static

Definition at line 989 of file procarray.c.

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

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

Referenced by ExpireTreeKnownAssignedTransactionIds(), and ProcArrayApplyRecoveryInfo().

◆ MinimumActiveBackends()

bool MinimumActiveBackends ( int  min)

Definition at line 3533 of file procarray.c.

3534 {
3535  ProcArrayStruct *arrayP = procArray;
3536  int count = 0;
3537  int index;
3538 
3539  /* Quick short-circuit if no minimum is specified */
3540  if (min == 0)
3541  return true;
3542 
3543  /*
3544  * Note: for speed, we don't acquire ProcArrayLock. This is a little bit
3545  * bogus, but since we are only testing fields for zero or nonzero, it
3546  * should be OK. The result is only used for heuristic purposes anyway...
3547  */
3548  for (index = 0; index < arrayP->numProcs; index++)
3549  {
3550  int pgprocno = arrayP->pgprocnos[index];
3551  PGPROC *proc = &allProcs[pgprocno];
3552 
3553  /*
3554  * Since we're not holding a lock, need to be prepared to deal with
3555  * garbage, as someone could have incremented numProcs but not yet
3556  * filled the structure.
3557  *
3558  * If someone just decremented numProcs, 'proc' could also point to a
3559  * PGPROC entry that's no longer in the array. It still points to a
3560  * PGPROC struct, though, because freed PGPROC entries just go to the
3561  * free list and are recycled. Its contents are nonsense in that case,
3562  * but that's acceptable for this function.
3563  */
3564  if (pgprocno == -1)
3565  continue; /* do not count deleted entries */
3566  if (proc == MyProc)
3567  continue; /* do not count myself */
3568  if (proc->xid == InvalidTransactionId)
3569  continue; /* do not count if no XID assigned */
3570  if (proc->pid == 0)
3571  continue; /* do not count prepared xacts */
3572  if (proc->waitLock != NULL)
3573  continue; /* do not count if blocked on a lock */
3574  count++;
3575  if (count >= min)
3576  break;
3577  }
3578 
3579  return count >= min;
3580 }
LOCK * waitLock
Definition: proc.h:228

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

Referenced by XLogFlush().

◆ ProcArrayAdd()

void ProcArrayAdd ( PGPROC proc)

Definition at line 468 of file procarray.c.

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

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

Referenced by InitProcessPhase2(), and MarkAsPrepared().

◆ ProcArrayApplyRecoveryInfo()

void ProcArrayApplyRecoveryInfo ( RunningTransactions  running)

Definition at line 1054 of file procarray.c.

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

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

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

◆ ProcArrayApplyXidAssignment()

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

Definition at line 1306 of file procarray.c.

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

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

Referenced by xact_redo().

◆ ProcArrayClearTransaction()

void ProcArrayClearTransaction ( PGPROC proc)

Definition at line 907 of file procarray.c.

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

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

Referenced by PrepareTransaction().

◆ ProcArrayEndTransaction()

void ProcArrayEndTransaction ( PGPROC proc,
TransactionId  latestXid 
)

Definition at line 667 of file procarray.c.

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

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

Referenced by AbortTransaction(), and CommitTransaction().

◆ ProcArrayEndTransactionInternal()

static void ProcArrayEndTransactionInternal ( PGPROC proc,
TransactionId  latestXid 
)
inlinestatic

Definition at line 731 of file procarray.c.

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

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

Referenced by ProcArrayEndTransaction(), and ProcArrayGroupClearXid().

◆ ProcArrayGetReplicationSlotXmin()

void ProcArrayGetReplicationSlotXmin ( TransactionId xmin,
TransactionId catalog_xmin 
)

Definition at line 3952 of file procarray.c.

3954 {
3955  LWLockAcquire(ProcArrayLock, LW_SHARED);
3956 
3957  if (xmin != NULL)
3959 
3960  if (catalog_xmin != NULL)
3961  *catalog_xmin = procArray->replication_slot_catalog_xmin;
3962 
3963  LWLockRelease(ProcArrayLock);
3964 }

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

Referenced by logical_begin_heap_rewrite().

◆ ProcArrayGroupClearXid()

static void ProcArrayGroupClearXid ( PGPROC proc,
TransactionId  latestXid 
)
static

Definition at line 792 of file procarray.c.

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

References allProcs, Assert, GetNumberFromPGProc, INVALID_PROC_NUMBER, 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, PGSemaphoreLock(), PGSemaphoreUnlock(), pgstat_report_wait_end(), pgstat_report_wait_start(), ProcArrayEndTransactionInternal(), PROC_HDR::procArrayGroupFirst, PGPROC::procArrayGroupMember, PGPROC::procArrayGroupMemberXid, PGPROC::procArrayGroupNext, ProcGlobal, PGPROC::sem, TransactionIdIsValid, and PGPROC::xid.

Referenced by ProcArrayEndTransaction().

◆ ProcArrayInitRecovery()

void ProcArrayInitRecovery ( TransactionId  initializedUptoXID)

Definition at line 1023 of file procarray.c.

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

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

Referenced by StartupXLOG().

◆ ProcArrayInstallImportedXmin()

bool ProcArrayInstallImportedXmin ( TransactionId  xmin,
VirtualTransactionId sourcevxid 
)

Definition at line 2524 of file procarray.c.

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

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

Referenced by GetSerializableTransactionSnapshotInt(), and SetTransactionSnapshot().

◆ ProcArrayInstallRestoredXmin()

bool ProcArrayInstallRestoredXmin ( TransactionId  xmin,
PGPROC proc 
)

Definition at line 2608 of file procarray.c.

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

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

Referenced by SetTransactionSnapshot().

◆ ProcArrayRemove()

void ProcArrayRemove ( PGPROC proc,
TransactionId  latestXid 
)

Definition at line 565 of file procarray.c.

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

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

Referenced by FinishPreparedTransaction(), and RemoveProcFromArray().

◆ ProcArraySetReplicationSlotXmin()

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

Definition at line 3927 of file procarray.c.

3929 {
3930  Assert(!already_locked || LWLockHeldByMe(ProcArrayLock));
3931 
3932  if (!already_locked)
3933  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3934 
3936  procArray->replication_slot_catalog_xmin = catalog_xmin;
3937 
3938  if (!already_locked)
3939  LWLockRelease(ProcArrayLock);
3940 
3941  elog(DEBUG1, "xmin required by slots: data %u, catalog %u",
3942  xmin, catalog_xmin);
3943 }

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

Referenced by ReplicationSlotsComputeRequiredXmin().

◆ ProcArrayShmemSize()

Size ProcArrayShmemSize ( void  )

Definition at line 376 of file procarray.c.

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

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

Referenced by CalculateShmemSize().

◆ ProcNumberGetProc()

PGPROC* ProcNumberGetProc ( ProcNumber  procNumber)

Definition at line 3125 of file procarray.c.

3126 {
3127  PGPROC *result;
3128 
3129  if (procNumber < 0 || procNumber >= ProcGlobal->allProcCount)
3130  return NULL;
3131  result = GetPGProcByNumber(procNumber);
3132 
3133  if (result->pid == 0)
3134  return NULL;
3135 
3136  return result;
3137 }
#define GetPGProcByNumber(n)
Definition: proc.h:428
uint32 allProcCount
Definition: proc.h:398

References PROC_HDR::allProcCount, GetPGProcByNumber, PGPROC::pid, and ProcGlobal.

Referenced by checkTempNamespaceStatus(), LogRecoveryConflict(), VirtualXactLock(), WaitForLockersMultiple(), and WaitForOlderSnapshots().

◆ ProcNumberGetTransactionIds()

void ProcNumberGetTransactionIds ( ProcNumber  procNumber,
TransactionId xid,
TransactionId xmin,
int *  nsubxid,
bool overflowed 
)

Definition at line 3147 of file procarray.c.

3149 {
3150  PGPROC *proc;
3151 
3152  *xid = InvalidTransactionId;
3153  *xmin = InvalidTransactionId;
3154  *nsubxid = 0;
3155  *overflowed = false;
3156 
3157  if (procNumber < 0 || procNumber >= ProcGlobal->allProcCount)
3158  return;
3159  proc = GetPGProcByNumber(procNumber);
3160 
3161  /* Need to lock out additions/removals of backends */
3162  LWLockAcquire(ProcArrayLock, LW_SHARED);
3163 
3164  if (proc->pid != 0)
3165  {
3166  *xid = proc->xid;
3167  *xmin = proc->xmin;
3168  *nsubxid = proc->subxidStatus.count;
3169  *overflowed = proc->subxidStatus.overflowed;
3170  }
3171 
3172  LWLockRelease(ProcArrayLock);
3173 }

References PROC_HDR::allProcCount, XidCacheStatus::count, GetPGProcByNumber, InvalidTransactionId, LW_SHARED, LWLockAcquire(), LWLockRelease(), XidCacheStatus::overflowed, PGPROC::pid, ProcGlobal, PGPROC::subxidStatus, PGPROC::xid, and PGPROC::xmin.

Referenced by pgstat_read_current_status().

◆ RecordKnownAssignedTransactionIds()

void RecordKnownAssignedTransactionIds ( TransactionId  xid)

Definition at line 4387 of file procarray.c.

4388 {
4392 
4393  elog(DEBUG4, "record known xact %u latestObservedXid %u",
4394  xid, latestObservedXid);
4395 
4396  /*
4397  * When a newly observed xid arrives, it is frequently the case that it is
4398  * *not* the next xid in sequence. When this occurs, we must treat the
4399  * intervening xids as running also.
4400  */
4402  {
4403  TransactionId next_expected_xid;
4404 
4405  /*
4406  * Extend subtrans like we do in GetNewTransactionId() during normal
4407  * operation using individual extend steps. Note that we do not need
4408  * to extend clog since its extensions are WAL logged.
4409  *
4410  * This part has to be done regardless of standbyState since we
4411  * immediately start assigning subtransactions to their toplevel
4412  * transactions.
4413  */
4414  next_expected_xid = latestObservedXid;
4415  while (TransactionIdPrecedes(next_expected_xid, xid))
4416  {
4417  TransactionIdAdvance(next_expected_xid);
4418  ExtendSUBTRANS(next_expected_xid);
4419  }
4420  Assert(next_expected_xid == xid);
4421 
4422  /*
4423  * If the KnownAssignedXids machinery isn't up yet, there's nothing
4424  * more to do since we don't track assigned xids yet.
4425  */
4427  {
4428  latestObservedXid = xid;
4429  return;
4430  }
4431 
4432  /*
4433  * Add (latestObservedXid, xid] onto the KnownAssignedXids array.
4434  */
4435  next_expected_xid = latestObservedXid;
4436  TransactionIdAdvance(next_expected_xid);
4437  KnownAssignedXidsAdd(next_expected_xid, xid, false);
4438 
4439  /*
4440  * Now we can advance latestObservedXid
4441  */
4442  latestObservedXid = xid;
4443 
4444  /* TransamVariables->nextXid must be beyond any observed xid */
4446  }
4447 }

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

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

◆ SignalVirtualTransaction()

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

Definition at line 3484 of file procarray.c.

3486 {
3487  ProcArrayStruct *arrayP = procArray;
3488  int index;
3489  pid_t pid = 0;
3490 
3491  LWLockAcquire(ProcArrayLock, LW_SHARED);
3492 
3493  for (index = 0; index < arrayP->numProcs; index++)
3494  {
3495  int pgprocno = arrayP->pgprocnos[index];
3496  PGPROC *proc = &allProcs[pgprocno];
3497  VirtualTransactionId procvxid;
3498 
3499  GET_VXID_FROM_PGPROC(procvxid, *proc);
3500 
3501  if (procvxid.procNumber == vxid.procNumber &&
3502  procvxid.localTransactionId == vxid.localTransactionId)
3503  {
3504  proc->recoveryConflictPending = conflictPending;
3505  pid = proc->pid;
3506  if (pid != 0)
3507  {
3508  /*
3509  * Kill the pid if it's still here. If not, that's what we
3510  * wanted so ignore any errors.
3511  */
3512  (void) SendProcSignal(pid, sigmode, vxid.procNumber);
3513  }
3514  break;
3515  }
3516  }
3517 
3518  LWLockRelease(ProcArrayLock);
3519 
3520  return pid;
3521 }

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

Referenced by CancelVirtualTransaction(), and ResolveRecoveryConflictWithLock().

◆ TerminateOtherDBBackends()

void TerminateOtherDBBackends ( Oid  databaseId)

Definition at line 3815 of file procarray.c.

3816 {
3817  ProcArrayStruct *arrayP = procArray;
3818  List *pids = NIL;
3819  int nprepared = 0;
3820  int i;
3821 
3822  LWLockAcquire(ProcArrayLock, LW_SHARED);
3823 
3824  for (i = 0; i < procArray->numProcs; i++)
3825  {
3826  int pgprocno = arrayP->pgprocnos[i];
3827  PGPROC *proc = &allProcs[pgprocno];
3828 
3829  if (proc->databaseId != databaseId)
3830  continue;
3831  if (proc == MyProc)
3832  continue;
3833 
3834  if (proc->pid != 0)
3835  pids = lappend_int(pids, proc->pid);
3836  else
3837  nprepared++;
3838  }
3839 
3840  LWLockRelease(ProcArrayLock);
3841 
3842  if (nprepared > 0)
3843  ereport(ERROR,
3844  (errcode(ERRCODE_OBJECT_IN_USE),
3845  errmsg("database \"%s\" is being used by prepared transactions",
3846  get_database_name(databaseId)),
3847  errdetail_plural("There is %d prepared transaction using the database.",
3848  "There are %d prepared transactions using the database.",
3849  nprepared,
3850  nprepared)));
3851 
3852  if (pids)
3853  {
3854  ListCell *lc;
3855 
3856  /*
3857  * Check whether we have the necessary rights to terminate other
3858  * sessions. We don't terminate any session until we ensure that we
3859  * have rights on all the sessions to be terminated. These checks are
3860  * the same as we do in pg_terminate_backend.
3861  *
3862  * In this case we don't raise some warnings - like "PID %d is not a
3863  * PostgreSQL server process", because for us already finished session
3864  * is not a problem.
3865  */
3866  foreach(lc, pids)
3867  {
3868  int pid = lfirst_int(lc);
3869  PGPROC *proc = BackendPidGetProc(pid);
3870 
3871  if (proc != NULL)
3872  {
3873  /* Only allow superusers to signal superuser-owned backends. */
3874  if (superuser_arg(proc->roleId) && !superuser())
3875  ereport(ERROR,
3876  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3877  errmsg("permission denied to terminate process"),
3878  errdetail("Only roles with the %s attribute may terminate processes of roles with the %s attribute.",
3879  "SUPERUSER", "SUPERUSER")));
3880 
3881  /* Users can signal backends they have role membership in. */
3882  if (!has_privs_of_role(GetUserId(), proc->roleId) &&
3883  !has_privs_of_role(GetUserId(), ROLE_PG_SIGNAL_BACKEND))
3884  ereport(ERROR,
3885  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3886  errmsg("permission denied to terminate process"),
3887  errdetail("Only roles with privileges of the role whose process is being terminated or with privileges of the \"%s\" role may terminate this process.",
3888  "pg_signal_backend")));
3889  }
3890  }
3891 
3892  /*
3893  * There's a race condition here: once we release the ProcArrayLock,
3894  * it's possible for the session to exit before we issue kill. That
3895  * race condition possibility seems too unlikely to worry about. See
3896  * pg_signal_backend.
3897  */
3898  foreach(lc, pids)
3899  {
3900  int pid = lfirst_int(lc);
3901  PGPROC *proc = BackendPidGetProc(pid);
3902 
3903  if (proc != NULL)
3904  {
3905  /*
3906  * If we have setsid(), signal the backend's whole process
3907  * group
3908  */
3909 #ifdef HAVE_SETSID
3910  (void) kill(-pid, SIGTERM);
3911 #else
3912  (void) kill(pid, SIGTERM);
3913 #endif
3914  }
3915  }
3916  }
3917 }
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:5128
char * get_database_name(Oid dbid)
Definition: dbcommands.c:3153
int errdetail(const char *fmt,...)
Definition: elog.c:1205
int errdetail_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1297
List * lappend_int(List *list, int datum)
Definition: list.c:357
Oid GetUserId(void)
Definition: miscinit.c:514
#define NIL
Definition: pg_list.h:68
#define lfirst_int(lc)
Definition: pg_list.h:173
Definition: pg_list.h:54
bool superuser_arg(Oid roleid)
Definition: superuser.c:56
bool superuser(void)
Definition: superuser.c:46

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

Referenced by dropdb().

◆ TransactionIdIsActive()

bool TransactionIdIsActive ( TransactionId  xid)

Definition at line 1622 of file procarray.c.

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

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

◆ TransactionIdIsInProgress()

bool TransactionIdIsInProgress ( TransactionId  xid)

Definition at line 1390 of file procarray.c.

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

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

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

◆ XidCacheRemoveRunningXids()

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

Definition at line 3975 of file procarray.c.

3978 {
3979  int i,
3980  j;
3981  XidCacheStatus *mysubxidstat;
3982 
3984 
3985  /*
3986  * We must hold ProcArrayLock exclusively in order to remove transactions
3987  * from the PGPROC array. (See src/backend/access/transam/README.) It's
3988  * possible this could be relaxed since we know this routine is only used
3989  * to abort subtransactions, but pending closer analysis we'd best be
3990  * conservative.
3991  *
3992  * Note that we do not have to be careful about memory ordering of our own
3993  * reads wrt. GetNewTransactionId() here - only this process can modify
3994  * relevant fields of MyProc/ProcGlobal->xids[]. But we do have to be
3995  * careful about our own writes being well ordered.
3996  */
3997  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3998 
3999  mysubxidstat = &ProcGlobal->subxidStates[MyProc->pgxactoff];
4000 
4001  /*
4002  * Under normal circumstances xid and xids[] will be in increasing order,
4003  * as will be the entries in subxids. Scan backwards to avoid O(N^2)
4004  * behavior when removing a lot of xids.
4005  */
4006  for (i = nxids - 1; i >= 0; i--)
4007  {
4008  TransactionId anxid = xids[i];
4009 
4010  for (j = MyProc->subxidStatus.count - 1; j >= 0; j--)
4011  {
4012  if (TransactionIdEquals(MyProc->subxids.xids[j], anxid))
4013  {
4015  pg_write_barrier();
4016  mysubxidstat->count--;
4018  break;
4019  }
4020  }
4021 
4022  /*
4023  * Ordinarily we should have found it, unless the cache has
4024  * overflowed. However it's also possible for this routine to be
4025  * invoked multiple times for the same subtransaction, in case of an
4026  * error during AbortSubTransaction. So instead of Assert, emit a
4027  * debug warning.
4028  */
4029  if (j < 0 && !MyProc->subxidStatus.overflowed)
4030  elog(WARNING, "did not find subXID %u in MyProc", anxid);
4031  }
4032 
4033  for (j = MyProc->subxidStatus.count - 1; j >= 0; j--)
4034  {
4035  if (TransactionIdEquals(MyProc->subxids.xids[j], xid))
4036  {
4038  pg_write_barrier();
4039  mysubxidstat->count--;
4041  break;
4042  }
4043  }
4044  /* Ordinarily we should have found it, unless the cache has overflowed */
4045  if (j < 0 && !MyProc->subxidStatus.overflowed)
4046  elog(WARNING, "did not find subXID %u in MyProc", xid);
4047 
4048  /* Also advance global latestCompletedXid while holding the lock */
4049  MaintainLatestCompletedXid(latestXid);
4050 
4051  /* ... and xactCompletionCount */
4053 
4054  LWLockRelease(ProcArrayLock);
4055 }
#define WARNING
Definition: elog.h:36

References Assert, XidCacheStatus::count, elog, i, j, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MaintainLatestCompletedXid(), MyProc, pg_write_barrier, PGPROC::pgxactoff, ProcGlobal, PGPROC::subxids, PROC_HDR::subxidStates, PGPROC::subxidStatus, TransactionIdEquals, TransactionIdIsValid, TransamVariables, WARNING, TransamVariablesData::xactCompletionCount, and XidCache::xids.

Referenced by RecordTransactionAbort().

Variable Documentation

◆ allProcs

◆ cachedXidIsNotInProgress

TransactionId cachedXidIsNotInProgress = InvalidTransactionId
static

Definition at line 276 of file procarray.c.

Referenced by TransactionIdIsInProgress().

◆ ComputeXidHorizonsResultLastXmin

TransactionId ComputeXidHorizonsResultLastXmin
static

Definition at line 307 of file procarray.c.

Referenced by GlobalVisTestShouldUpdate(), and GlobalVisUpdateApply().

◆ GlobalVisCatalogRels

GlobalVisState GlobalVisCatalogRels
static

Definition at line 298 of file procarray.c.

Referenced by GetSnapshotData(), GlobalVisTestFor(), and GlobalVisUpdateApply().

◆ GlobalVisDataRels

GlobalVisState GlobalVisDataRels
static

Definition at line 299 of file procarray.c.

Referenced by GetSnapshotData(), GlobalVisTestFor(), and GlobalVisUpdateApply().

◆ GlobalVisSharedRels

GlobalVisState GlobalVisSharedRels
static

Definition at line 297 of file procarray.c.

Referenced by GetSnapshotData(), GlobalVisTestFor(), and GlobalVisUpdateApply().

◆ GlobalVisTempRels

GlobalVisState GlobalVisTempRels
static

Definition at line 300 of file procarray.c.

Referenced by GetSnapshotData(), GlobalVisTestFor(), and GlobalVisUpdateApply().

◆ KnownAssignedXids

◆ KnownAssignedXidsValid

◆ latestObservedXid

◆ procArray

◆ standbySnapshotPendingXmin

TransactionId standbySnapshotPendingXmin
static

Definition at line 290 of file procarray.c.

Referenced by ProcArrayApplyRecoveryInfo().