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

Go to the source code of this file.

Data Structures

struct  ProcArrayStruct
 
struct  GlobalVisState
 
struct  ComputeXidHorizonsResult
 

Macros

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

Typedefs

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

Enumerations

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

Functions

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

Variables

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

Macro Definition Documentation

◆ KAX_COMPRESS_FREQUENCY

#define KAX_COMPRESS_FREQUENCY   128 /* in transactions */

◆ KAX_COMPRESS_IDLE_INTERVAL

#define KAX_COMPRESS_IDLE_INTERVAL   1000 /* in ms */

◆ MAXAUTOVACPIDS

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

◆ PROCARRAY_MAXPROCS

#define PROCARRAY_MAXPROCS   (MaxBackends + max_prepared_xacts)

◆ TOTAL_MAX_CACHED_SUBXIDS

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

◆ UINT32_ACCESS_ONCE

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

Definition at line 69 of file procarray.c.

◆ xc_by_child_xid_inc

#define xc_by_child_xid_inc ( )    ((void) 0)

Definition at line 341 of file procarray.c.

◆ xc_by_known_assigned_inc

#define xc_by_known_assigned_inc ( )    ((void) 0)

Definition at line 342 of file procarray.c.

◆ xc_by_known_xact_inc

#define xc_by_known_xact_inc ( )    ((void) 0)

Definition at line 337 of file procarray.c.

◆ xc_by_latest_xid_inc

#define xc_by_latest_xid_inc ( )    ((void) 0)

Definition at line 339 of file procarray.c.

◆ xc_by_main_xid_inc

#define xc_by_main_xid_inc ( )    ((void) 0)

Definition at line 340 of file procarray.c.

◆ xc_by_my_xact_inc

#define xc_by_my_xact_inc ( )    ((void) 0)

Definition at line 338 of file procarray.c.

◆ xc_by_recent_xmin_inc

#define xc_by_recent_xmin_inc ( )    ((void) 0)

Definition at line 336 of file procarray.c.

◆ xc_no_overflow_inc

#define xc_no_overflow_inc ( )    ((void) 0)

Definition at line 343 of file procarray.c.

◆ xc_slow_answer_inc

#define xc_slow_answer_inc ( )    ((void) 0)

Definition at line 344 of file procarray.c.

Typedef Documentation

◆ ComputeXidHorizonsResult

◆ GlobalVisHorizonKind

◆ KAXCompressReason

◆ ProcArrayStruct

Enumeration Type Documentation

◆ GlobalVisHorizonKind

Enumerator
VISHORIZON_SHARED 
VISHORIZON_CATALOG 
VISHORIZON_DATA 
VISHORIZON_TEMP 

Definition at line 250 of file procarray.c.

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

◆ KAXCompressReason

Enumerator
KAX_NO_SPACE 
KAX_PRUNE 
KAX_TRANSACTION_END 
KAX_STARTUP_PROCESS_IDLE 

Definition at line 261 of file procarray.c.

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

Function Documentation

◆ BackendPidGetProc()

PGPROC* BackendPidGetProc ( int  pid)

Definition at line 3110 of file procarray.c.

3111 {
3112  PGPROC *result;
3113 
3114  if (pid == 0) /* never match dummy PGPROCs */
3115  return NULL;
3116 
3117  LWLockAcquire(ProcArrayLock, LW_SHARED);
3118 
3119  result = BackendPidGetProcWithLock(pid);
3120 
3121  LWLockRelease(ProcArrayLock);
3122 
3123  return result;
3124 }
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1168
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781
@ LW_SHARED
Definition: lwlock.h:117
PGPROC * BackendPidGetProcWithLock(int pid)
Definition: procarray.c:3133
Definition: proc.h:162

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

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

◆ BackendPidGetProcWithLock()

PGPROC* BackendPidGetProcWithLock ( int  pid)

Definition at line 3133 of file procarray.c.

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

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

Referenced by BackendPidGetProc(), and GetBlockerStatusData().

◆ BackendXidGetPid()

int BackendXidGetPid ( TransactionId  xid)

Definition at line 3170 of file procarray.c.

3171 {
3172  int result = 0;
3173  ProcArrayStruct *arrayP = procArray;
3174  TransactionId *other_xids = ProcGlobal->xids;
3175  int index;
3176 
3177  if (xid == InvalidTransactionId) /* never match invalid xid */
3178  return 0;
3179 
3180  LWLockAcquire(ProcArrayLock, LW_SHARED);
3181 
3182  for (index = 0; index < arrayP->numProcs; index++)
3183  {
3184  if (other_xids[index] == xid)
3185  {
3186  int pgprocno = arrayP->pgprocnos[index];
3187  PGPROC *proc = &allProcs[pgprocno];
3188 
3189  result = proc->pid;
3190  break;
3191  }
3192  }
3193 
3194  LWLockRelease(ProcArrayLock);
3195 
3196  return result;
3197 }
uint32 TransactionId
Definition: c.h:641
PROC_HDR * ProcGlobal
Definition: proc.c:81
TransactionId * xids
Definition: proc.h:361
#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 3574 of file procarray.c.

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

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

Referenced by ResolveRecoveryConflictWithDatabase(), and SendRecoveryConflictWithBufferPin().

◆ CancelVirtualTransaction()

pid_t CancelVirtualTransaction ( VirtualTransactionId  vxid,
ProcSignalReason  sigmode 
)

Definition at line 3405 of file procarray.c.

3406 {
3407  return SignalVirtualTransaction(vxid, sigmode, true);
3408 }
pid_t SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode, bool conflictPending)
Definition: procarray.c:3411

References SignalVirtualTransaction().

Referenced by ResolveRecoveryConflictWithVirtualXIDs().

◆ ComputeXidHorizons()

static void ComputeXidHorizons ( ComputeXidHorizonsResult h)
static

Definition at line 1724 of file procarray.c.

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

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

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

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

Referenced by ResolveRecoveryConflictWithDatabase().

◆ CountDBConnections()

int CountDBConnections ( Oid  databaseid)

Definition at line 3543 of file procarray.c.

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

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

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

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

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

◆ CountUserBackends()

int CountUserBackends ( Oid  roleid)

Definition at line 3614 of file procarray.c.

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

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

Referenced by InitializeSessionUserId().

◆ CreateSharedProcArray()

void CreateSharedProcArray ( void  )

Definition at line 419 of file procarray.c.

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

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

4440 {
4441  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4443 
4444  /*
4445  * Reset lastOverflowedXid. Currently, lastOverflowedXid has no use after
4446  * the call of this function. But do this for unification with what
4447  * ExpireOldKnownAssignedTransactionIds() do.
4448  */
4450  LWLockRelease(ProcArrayLock);
4451 }
static void KnownAssignedXidsRemovePreceding(TransactionId removeXid)
Definition: procarray.c:4952

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

Referenced by ShutdownRecoveryTransactionEnvironment().

◆ ExpireOldKnownAssignedTransactionIds()

void ExpireOldKnownAssignedTransactionIds ( TransactionId  xid)

Definition at line 4459 of file procarray.c.

4460 {
4461  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4462 
4463  /*
4464  * Reset lastOverflowedXid if we know all transactions that have been
4465  * possibly running are being gone. Not doing so could cause an incorrect
4466  * lastOverflowedXid value, which makes extra snapshots be marked as
4467  * suboverflowed.
4468  */
4472  LWLockRelease(ProcArrayLock);
4473 }
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 4413 of file procarray.c.

4415 {
4417 
4418  /*
4419  * Uses same locking as transaction commit
4420  */
4421  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4422 
4423  KnownAssignedXidsRemoveTree(xid, nsubxids, subxids);
4424 
4425  /* As in ProcArrayEndTransaction, advance latestCompletedXid */
4427 
4428  /* ... and xactCompletionCount */
4430 
4431  LWLockRelease(ProcArrayLock);
4432 }
static void KnownAssignedXidsRemoveTree(TransactionId xid, int nsubxids, TransactionId *subxids)
Definition: procarray.c:4930
static void MaintainLatestCompletedXidRecovery(TransactionId latestXid)
Definition: procarray.c:990
HotStandbyState standbyState
Definition: xlogutils.c:56
@ 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 4262 of file procarray.c.

4263 {
4264  TransactionId rel_xid = XidFromFullTransactionId(rel);
4265 
4267  Assert(TransactionIdIsValid(rel_xid));
4268 
4269  /* not guaranteed to find issues, but likely to catch mistakes */
4271 
4273  + (int32) (xid - rel_xid));
4274 }
signed int int32
Definition: c.h:483
#define U64FromFullTransactionId(x)
Definition: transam.h:49
static FullTransactionId FullTransactionIdFromU64(uint64 value)
Definition: transam.h:81
#define AssertTransactionIdInAllowableRange(xid)
Definition: transam.h:301

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

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

◆ GetConflictingVirtualXIDs()

VirtualTransactionId* GetConflictingVirtualXIDs ( TransactionId  limitXmin,
Oid  dbOid 
)

Definition at line 3331 of file procarray.c.

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

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

Referenced by ResolveRecoveryConflictWithSnapshot(), and ResolveRecoveryConflictWithTablespace().

◆ GetCurrentVirtualXIDs()

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

Definition at line 3238 of file procarray.c.

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

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

2070 {
2071  return TOTAL_MAX_CACHED_SUBXIDS;
2072 }

References TOTAL_MAX_CACHED_SUBXIDS.

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

◆ GetMaxSnapshotXidCount()

int GetMaxSnapshotXidCount ( void  )

Definition at line 2058 of file procarray.c.

2059 {
2060  return procArray->maxProcs;
2061 }

References ProcArrayStruct::maxProcs, and procArray.

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

◆ GetOldestActiveTransactionId()

TransactionId GetOldestActiveTransactionId ( void  )

Definition at line 2852 of file procarray.c.

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

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

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

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

◆ GetOldestSafeDecodingTransactionId()

TransactionId GetOldestSafeDecodingTransactionId ( bool  catalogOnly)

Definition at line 2917 of file procarray.c.

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

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

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

References ComputeXidHorizons(), and ComputeXidHorizonsResult::oldest_considered_running.

Referenced by CreateCheckPoint(), and CreateRestartPoint().

◆ GetReplicationHorizons()

void GetReplicationHorizons ( TransactionId xmin,
TransactionId catalog_xmin 
)

Definition at line 2036 of file procarray.c.

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

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

Referenced by XLogWalRcvSendHSFeedback().

◆ GetRunningTransactionData()

RunningTransactions GetRunningTransactionData ( void  )

Definition at line 2677 of file procarray.c.

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

References allProcs, Assert(), XidCacheStatus::count, ereport, errcode(), errmsg(), ERROR, TransamVariablesData::latestCompletedXid, RunningTransactionsData::latestCompletedXid, LW_SHARED, LWLockAcquire(), malloc, TransamVariablesData::nextXid, RunningTransactionsData::nextXid, ProcArrayStruct::numProcs, 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 LogStandbySnapshot().

◆ GetSnapshotData()

Snapshot GetSnapshotData ( Snapshot  snapshot)

Definition at line 2166 of file procarray.c.

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

References SnapshotData::active_count, allProcs, Assert(), SnapshotData::copied, XidCacheStatus::count, SnapshotData::curcid, GlobalVisState::definitely_needed, ereport, errcode(), errmsg(), ERROR, FullTransactionIdAdvance(), FullTransactionIdNewer(), FullXidRelativeTo(), GetCurrentCommandId(), GetMaxSnapshotSubxidCount(), GetMaxSnapshotXidCount(), GetSnapshotDataReuse(), GlobalVisCatalogRels, GlobalVisDataRels, GlobalVisSharedRels, GlobalVisTempRels, InvalidTransactionId, InvalidXLogRecPtr, KnownAssignedXidsGetAndSetXmin(), ProcArrayStruct::lastOverflowedXid, 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 2084 of file procarray.c.

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

References SnapshotData::active_count, Assert(), SnapshotData::copied, SnapshotData::curcid, GetCurrentCommandId(), InvalidXLogRecPtr, SnapshotData::lsn, LWLockHeldByMe(), MyProc, RecentXmin, SnapshotData::regd_count, 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 3015 of file procarray.c.

3016 {
3017  VirtualTransactionId *vxids;
3018  ProcArrayStruct *arrayP = procArray;
3019  int count = 0;
3020  int index;
3021 
3022  Assert(type != 0);
3023 
3024  /* allocate what's certainly enough result space */
3025  vxids = (VirtualTransactionId *)
3026  palloc(sizeof(VirtualTransactionId) * arrayP->maxProcs);
3027 
3028  LWLockAcquire(ProcArrayLock, LW_SHARED);
3029 
3030  for (index = 0; index < arrayP->numProcs; index++)
3031  {
3032  int pgprocno = arrayP->pgprocnos[index];
3033  PGPROC *proc = &allProcs[pgprocno];
3034 
3035  if ((proc->delayChkptFlags & type) != 0)
3036  {
3037  VirtualTransactionId vxid;
3038 
3039  GET_VXID_FROM_PGPROC(vxid, *proc);
3040  if (VirtualTransactionIdIsValid(vxid))
3041  vxids[count++] = vxid;
3042  }
3043  }
3044 
3045  LWLockRelease(ProcArrayLock);
3046 
3047  *nvxids = count;
3048  return vxids;
3049 }
int delayChkptFlags
Definition: proc.h:226
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 4227 of file procarray.c.

4228 {
4230 
4231  state = GlobalVisTestFor(rel);
4232 
4233  return GlobalVisTestIsRemovableFullXid(state, fxid);
4234 }
bool GlobalVisTestIsRemovableFullXid(GlobalVisState *state, FullTransactionId fxid)
Definition: procarray.c:4133
GlobalVisState * GlobalVisTestFor(Relation rel)
Definition: procarray.c:4018
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 4241 of file procarray.c.

4242 {
4244 
4245  state = GlobalVisTestFor(rel);
4246 
4247  return GlobalVisTestIsRemovableXid(state, xid);
4248 }
bool GlobalVisTestIsRemovableXid(GlobalVisState *state, TransactionId xid)
Definition: procarray.c:4175

References GlobalVisTestFor(), and GlobalVisTestIsRemovableXid().

Referenced by GinPageIsRecyclable().

◆ GlobalVisHorizonKindForRel()

static GlobalVisHorizonKind GlobalVisHorizonKindForRel ( Relation  rel)
inlinestatic

Definition at line 1960 of file procarray.c.

1961 {
1962  /*
1963  * Other relkinds currently don't contain xids, nor always the necessary
1964  * logical decoding markers.
1965  */
1966  Assert(!rel ||
1967  rel->rd_rel->relkind == RELKIND_RELATION ||
1968  rel->rd_rel->relkind == RELKIND_MATVIEW ||
1969  rel->rd_rel->relkind == RELKIND_TOASTVALUE);
1970 
1971  if (rel == NULL || rel->rd_rel->relisshared || RecoveryInProgress())
1972  return VISHORIZON_SHARED;
1973  else if (IsCatalogRelation(rel) ||
1975  return VISHORIZON_CATALOG;
1976  else if (!RELATION_IS_LOCAL(rel))
1977  return VISHORIZON_DATA;
1978  else
1979  return VISHORIZON_TEMP;
1980 }
bool IsCatalogRelation(Relation relation)
Definition: catalog.c:105
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:647
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:683
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 4018 of file procarray.c.

4019 {
4020  GlobalVisState *state = NULL;
4021 
4022  /* XXX: we should assert that a snapshot is pushed or registered */
4023  Assert(RecentXmin);
4024 
4025  switch (GlobalVisHorizonKindForRel(rel))
4026  {
4027  case VISHORIZON_SHARED:
4029  break;
4030  case VISHORIZON_CATALOG:
4032  break;
4033  case VISHORIZON_DATA:
4035  break;
4036  case VISHORIZON_TEMP:
4038  break;
4039  }
4040 
4041  Assert(FullTransactionIdIsValid(state->definitely_needed) &&
4042  FullTransactionIdIsValid(state->maybe_needed));
4043 
4044  return state;
4045 }
#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 4133 of file procarray.c.

4135 {
4136  /*
4137  * If fxid is older than maybe_needed bound, it definitely is visible to
4138  * everyone.
4139  */
4140  if (FullTransactionIdPrecedes(fxid, state->maybe_needed))
4141  return true;
4142 
4143  /*
4144  * If fxid is >= definitely_needed bound, it is very likely to still be
4145  * considered running.
4146  */
4147  if (FullTransactionIdFollowsOrEquals(fxid, state->definitely_needed))
4148  return false;
4149 
4150  /*
4151  * fxid is between maybe_needed and definitely_needed, i.e. there might or
4152  * might not exist a snapshot considering fxid running. If it makes sense,
4153  * update boundaries and recheck.
4154  */
4156  {
4157  GlobalVisUpdate();
4158 
4159  Assert(FullTransactionIdPrecedes(fxid, state->definitely_needed));
4160 
4161  return FullTransactionIdPrecedes(fxid, state->maybe_needed);
4162  }
4163  else
4164  return false;
4165 }
static bool GlobalVisTestShouldUpdate(GlobalVisState *state)
Definition: procarray.c:4058
static void GlobalVisUpdate(void)
Definition: procarray.c:4116
#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 4175 of file procarray.c.

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

References FullXidRelativeTo(), and GlobalVisTestIsRemovableFullXid().

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

◆ GlobalVisTestNonRemovableFullHorizon()

FullTransactionId GlobalVisTestNonRemovableFullHorizon ( GlobalVisState state)

Definition at line 4202 of file procarray.c.

4203 {
4204  /* acquire accurate horizon if not already done */
4206  GlobalVisUpdate();
4207 
4208  return state->maybe_needed;
4209 }

References GlobalVisTestShouldUpdate(), and GlobalVisUpdate().

Referenced by GlobalVisTestNonRemovableHorizon().

◆ GlobalVisTestNonRemovableHorizon()

TransactionId GlobalVisTestNonRemovableHorizon ( GlobalVisState state)

Definition at line 4213 of file procarray.c.

4214 {
4215  FullTransactionId cutoff;
4216 
4218 
4219  return XidFromFullTransactionId(cutoff);
4220 }
FullTransactionId GlobalVisTestNonRemovableFullHorizon(GlobalVisState *state)
Definition: procarray.c:4202

References GlobalVisTestNonRemovableFullHorizon(), and XidFromFullTransactionId.

◆ GlobalVisTestShouldUpdate()

static bool GlobalVisTestShouldUpdate ( GlobalVisState state)
static

Definition at line 4058 of file procarray.c.

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

References ComputeXidHorizonsResultLastXmin, FullTransactionIdFollowsOrEquals, RecentXmin, and TransactionIdIsValid.

Referenced by GlobalVisTestIsRemovableFullXid(), and GlobalVisTestNonRemovableFullHorizon().

◆ GlobalVisUpdate()

static void GlobalVisUpdate ( void  )
static

Definition at line 4116 of file procarray.c.

4117 {
4118  ComputeXidHorizonsResult horizons;
4119 
4120  /* updates the horizons as a side-effect */
4121  ComputeXidHorizons(&horizons);
4122 }

References ComputeXidHorizons().

Referenced by GlobalVisTestIsRemovableFullXid(), and GlobalVisTestNonRemovableFullHorizon().

◆ GlobalVisUpdateApply()

static void GlobalVisUpdateApply ( ComputeXidHorizonsResult horizons)
static

Definition at line 4077 of file procarray.c.

4078 {
4081  horizons->shared_oldest_nonremovable);
4084  horizons->catalog_oldest_nonremovable);
4087  horizons->data_oldest_nonremovable);
4090  horizons->temp_oldest_nonremovable);
4091 
4092  /*
4093  * In longer running transactions it's possible that transactions we
4094  * previously needed to treat as running aren't around anymore. So update
4095  * definitely_needed to not be earlier than maybe_needed.
4096  */
4107 
4109 }

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

3062 {
3063  bool result = false;
3064  ProcArrayStruct *arrayP = procArray;
3065  int index;
3066 
3067  Assert(type != 0);
3068 
3069  LWLockAcquire(ProcArrayLock, LW_SHARED);
3070 
3071  for (index = 0; index < arrayP->numProcs; index++)
3072  {
3073  int pgprocno = arrayP->pgprocnos[index];
3074  PGPROC *proc = &allProcs[pgprocno];
3075  VirtualTransactionId vxid;
3076 
3077  GET_VXID_FROM_PGPROC(vxid, *proc);
3078 
3079  if ((proc->delayChkptFlags & type) != 0 &&
3081  {
3082  int i;
3083 
3084  for (i = 0; i < nvxids; i++)
3085  {
3086  if (VirtualTransactionIdEquals(vxid, vxids[i]))
3087  {
3088  result = true;
3089  break;
3090  }
3091  }
3092  if (result)
3093  break;
3094  }
3095  }
3096 
3097  LWLockRelease(ProcArrayLock);
3098 
3099  return result;
3100 }
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 3205 of file procarray.c.

3206 {
3207  return (BackendPidGetProc(pid) != NULL);
3208 }
PGPROC * BackendPidGetProc(int pid)
Definition: procarray.c:3110

References BackendPidGetProc().

Referenced by pg_stat_get_subscription().

◆ KnownAssignedTransactionIdsIdleMaintenance()

void KnownAssignedTransactionIdsIdleMaintenance ( void  )

Definition at line 4481 of file procarray.c.

4482 {
4484 }
static void KnownAssignedXidsCompress(KAXCompressReason reason, bool haveLock)
Definition: procarray.c:4582

References KAX_STARTUP_PROCESS_IDLE, and KnownAssignedXidsCompress().

Referenced by WaitForWALToBecomeAvailable().

◆ KnownAssignedXidExists()

static bool KnownAssignedXidExists ( TransactionId  xid)
static

Definition at line 4891 of file procarray.c.

4892 {
4894 
4895  return KnownAssignedXidsSearch(xid, false);
4896 }
static bool KnownAssignedXidsSearch(TransactionId xid, bool remove)
Definition: procarray.c:4803

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

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

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

5136 {
5137  ProcArrayStruct *pArray = procArray;
5139  int head,
5140  tail,
5141  i;
5142  int nxids = 0;
5143 
5144  tail = pArray->tailKnownAssignedXids;
5145  head = pArray->headKnownAssignedXids;
5146 
5147  initStringInfo(&buf);
5148 
5149  for (i = tail; i < head; i++)
5150  {
5152  {
5153  nxids++;
5154  appendStringInfo(&buf, "[%d]=%u ", i, KnownAssignedXids[i]);
5155  }
5156  }
5157 
5158  elog(trace_level, "%d KnownAssignedXids (num=%d tail=%d head=%d) %s",
5159  nxids,
5160  pArray->numKnownAssignedXids,
5161  pArray->tailKnownAssignedXids,
5162  pArray->headKnownAssignedXids,
5163  buf.data);
5164 
5165  pfree(buf.data);
5166 }
void pfree(void *pointer)
Definition: mcxt.c:1431
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 5030 of file procarray.c.

5031 {
5033 
5034  return KnownAssignedXidsGetAndSetXmin(xarray, &xtmp, xmax);
5035 }

References InvalidTransactionId, and KnownAssignedXidsGetAndSetXmin().

Referenced by TransactionIdIsInProgress().

◆ KnownAssignedXidsGetAndSetXmin()

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

Definition at line 5044 of file procarray.c.

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

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

5101 {
5102  int head,
5103  tail;
5104  int i;
5105 
5106  /*
5107  * Fetch head just once, since it may change while we loop.
5108  */
5111 
5112  pg_read_barrier(); /* pairs with KnownAssignedXidsAdd */
5113 
5114  for (i = tail; i < head; i++)
5115  {
5116  /* Skip any gaps in the array */
5118  return KnownAssignedXids[i];
5119  }
5120 
5121  return InvalidTransactionId;
5122 }

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

4905 {
4907 
4908  elog(DEBUG4, "remove KnownAssignedXid %u", xid);
4909 
4910  /*
4911  * Note: we cannot consider it an error to remove an XID that's not
4912  * present. We intentionally remove subxact IDs while processing
4913  * XLOG_XACT_ASSIGNMENT, to avoid array overflow. Then those XIDs will be
4914  * removed again when the top-level xact commits or aborts.
4915  *
4916  * It might be possible to track such XIDs to distinguish this case from
4917  * actual errors, but it would be complicated and probably not worth it.
4918  * So, just ignore the search result.
4919  */
4920  (void) KnownAssignedXidsSearch(xid, true);
4921 }
#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 4952 of file procarray.c.

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

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

4932 {
4933  int i;
4934 
4935  if (TransactionIdIsValid(xid))
4937 
4938  for (i = 0; i < nsubxids; i++)
4939  KnownAssignedXidsRemove(subxids[i]);
4940 
4941  /* Opportunistically compress the array */
4943 }
static void KnownAssignedXidsRemove(TransactionId xid)
Definition: procarray.c:4904

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

Referenced by ExpireTreeKnownAssignedTransactionIds(), and ProcArrayApplyXidAssignment().

◆ KnownAssignedXidsReset()

static void KnownAssignedXidsReset ( void  )
static

Definition at line 5173 of file procarray.c.

5174 {
5175  ProcArrayStruct *pArray = procArray;
5176 
5177  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
5178 
5179  pArray->numKnownAssignedXids = 0;
5180  pArray->tailKnownAssignedXids = 0;
5181  pArray->headKnownAssignedXids = 0;
5182 
5183  LWLockRelease(ProcArrayLock);
5184 }

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

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

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

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

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

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

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

Referenced by XLogFlush().

◆ ProcArrayAdd()

void ProcArrayAdd ( PGPROC proc)

Definition at line 469 of file procarray.c.

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

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

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

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

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

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

Referenced by PrepareTransaction().

◆ ProcArrayEndTransaction()

void ProcArrayEndTransaction ( PGPROC proc,
TransactionId  latestXid 
)

Definition at line 668 of file procarray.c.

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

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

Referenced by AbortTransaction(), and CommitTransaction().

◆ ProcArrayEndTransactionInternal()

static void ProcArrayEndTransactionInternal ( PGPROC proc,
TransactionId  latestXid 
)
inlinestatic

Definition at line 732 of file procarray.c.

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

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

3881 {
3882  LWLockAcquire(ProcArrayLock, LW_SHARED);
3883 
3884  if (xmin != NULL)
3886 
3887  if (catalog_xmin != NULL)
3888  *catalog_xmin = procArray->replication_slot_catalog_xmin;
3889 
3890  LWLockRelease(ProcArrayLock);
3891 }

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

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

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

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

Referenced by StartupXLOG().

◆ ProcArrayInstallImportedXmin()

bool ProcArrayInstallImportedXmin ( TransactionId  xmin,
VirtualTransactionId sourcevxid 
)

Definition at line 2525 of file procarray.c.

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

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

Referenced by GetSerializableTransactionSnapshotInt(), and SetTransactionSnapshot().

◆ ProcArrayInstallRestoredXmin()

bool ProcArrayInstallRestoredXmin ( TransactionId  xmin,
PGPROC proc 
)

Definition at line 2604 of file procarray.c.

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

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

Referenced by SetTransactionSnapshot().

◆ ProcArrayRemove()

void ProcArrayRemove ( PGPROC proc,
TransactionId  latestXid 
)

Definition at line 566 of file procarray.c.

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

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

3856 {
3857  Assert(!already_locked || LWLockHeldByMe(ProcArrayLock));
3858 
3859  if (!already_locked)
3860  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3861 
3863  procArray->replication_slot_catalog_xmin = catalog_xmin;
3864 
3865  if (!already_locked)
3866  LWLockRelease(ProcArrayLock);
3867 
3868  elog(DEBUG1, "xmin required by slots: data %u, catalog %u",
3869  xmin, catalog_xmin);
3870 }

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

Referenced by ReplicationSlotsComputeRequiredXmin().

◆ ProcArrayShmemSize()

Size ProcArrayShmemSize ( void  )

Definition at line 377 of file procarray.c.

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

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

Referenced by CalculateShmemSize().

◆ RecordKnownAssignedTransactionIds()

void RecordKnownAssignedTransactionIds ( TransactionId  xid)

Definition at line 4344 of file procarray.c.

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

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

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

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

Referenced by CancelVirtualTransaction(), and ResolveRecoveryConflictWithLock().

◆ TerminateOtherDBBackends()

void TerminateOtherDBBackends ( Oid  databaseId)

Definition at line 3742 of file procarray.c.

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

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

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

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

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

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