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

Go to the source code of this file.

Data Structures

struct  ProcArrayStruct
 
struct  GlobalVisState
 
struct  ComputeXidHorizonsResult
 

Macros

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

Typedefs

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

Enumerations

enum  GlobalVisHorizonKind { VISHORIZON_SHARED , VISHORIZON_CATALOG , VISHORIZON_DATA , VISHORIZON_TEMP }
 

Functions

static void KnownAssignedXidsCompress (bool force)
 
static void KnownAssignedXidsAdd (TransactionId from_xid, TransactionId to_xid, bool exclusive_lock)
 
static bool KnownAssignedXidsSearch (TransactionId xid, bool remove)
 
static bool KnownAssignedXidExists (TransactionId xid)
 
static void KnownAssignedXidsRemove (TransactionId xid)
 
static void KnownAssignedXidsRemoveTree (TransactionId xid, int nsubxids, TransactionId *subxids)
 
static void KnownAssignedXidsRemovePreceding (TransactionId xid)
 
static int KnownAssignedXidsGet (TransactionId *xarray, TransactionId xmax)
 
static int KnownAssignedXidsGetAndSetXmin (TransactionId *xarray, TransactionId *xmin, TransactionId xmax)
 
static TransactionId KnownAssignedXidsGetOldestXmin (void)
 
static void KnownAssignedXidsDisplay (int trace_level)
 
static void KnownAssignedXidsReset (void)
 
static void ProcArrayEndTransactionInternal (PGPROC *proc, TransactionId latestXid)
 
static void ProcArrayGroupClearXid (PGPROC *proc, TransactionId latestXid)
 
static void MaintainLatestCompletedXid (TransactionId latestXid)
 
static void MaintainLatestCompletedXidRecovery (TransactionId latestXid)
 
static FullTransactionId FullXidRelativeTo (FullTransactionId rel, TransactionId xid)
 
static void GlobalVisUpdateApply (ComputeXidHorizonsResult *horizons)
 
Size ProcArrayShmemSize (void)
 
void CreateSharedProcArray (void)
 
void ProcArrayAdd (PGPROC *proc)
 
void ProcArrayRemove (PGPROC *proc, TransactionId latestXid)
 
void ProcArrayEndTransaction (PGPROC *proc, TransactionId latestXid)
 
void ProcArrayClearTransaction (PGPROC *proc)
 
void ProcArrayInitRecovery (TransactionId initializedUptoXID)
 
void ProcArrayApplyRecoveryInfo (RunningTransactions running)
 
void ProcArrayApplyXidAssignment (TransactionId topxid, int nsubxids, TransactionId *subxids)
 
bool TransactionIdIsInProgress (TransactionId xid)
 
bool TransactionIdIsActive (TransactionId xid)
 
static void ComputeXidHorizons (ComputeXidHorizonsResult *h)
 
static GlobalVisHorizonKind GlobalVisHorizonKindForRel (Relation rel)
 
TransactionId GetOldestNonRemovableTransactionId (Relation rel)
 
TransactionId GetOldestTransactionIdConsideredRunning (void)
 
void GetReplicationHorizons (TransactionId *xmin, TransactionId *catalog_xmin)
 
int GetMaxSnapshotXidCount (void)
 
int GetMaxSnapshotSubxidCount (void)
 
static void GetSnapshotDataInitOldSnapshot (Snapshot snapshot)
 
static bool GetSnapshotDataReuse (Snapshot snapshot)
 
Snapshot GetSnapshotData (Snapshot snapshot)
 
bool ProcArrayInstallImportedXmin (TransactionId xmin, VirtualTransactionId *sourcevxid)
 
bool ProcArrayInstallRestoredXmin (TransactionId xmin, PGPROC *proc)
 
RunningTransactions GetRunningTransactionData (void)
 
TransactionId GetOldestActiveTransactionId (void)
 
TransactionId GetOldestSafeDecodingTransactionId (bool catalogOnly)
 
VirtualTransactionIdGetVirtualXIDsDelayingChkpt (int *nvxids, 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)
 

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

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

◆ xc_by_known_assigned_inc

#define xc_by_known_assigned_inc ( )    ((void) 0)

Definition at line 332 of file procarray.c.

◆ xc_by_known_xact_inc

#define xc_by_known_xact_inc ( )    ((void) 0)

Definition at line 327 of file procarray.c.

◆ xc_by_latest_xid_inc

#define xc_by_latest_xid_inc ( )    ((void) 0)

Definition at line 329 of file procarray.c.

◆ xc_by_main_xid_inc

#define xc_by_main_xid_inc ( )    ((void) 0)

Definition at line 330 of file procarray.c.

◆ xc_by_my_xact_inc

#define xc_by_my_xact_inc ( )    ((void) 0)

Definition at line 328 of file procarray.c.

◆ xc_by_recent_xmin_inc

#define xc_by_recent_xmin_inc ( )    ((void) 0)

Definition at line 326 of file procarray.c.

◆ xc_no_overflow_inc

#define xc_no_overflow_inc ( )    ((void) 0)

Definition at line 333 of file procarray.c.

◆ xc_slow_answer_inc

#define xc_slow_answer_inc ( )    ((void) 0)

Definition at line 334 of file procarray.c.

Typedef Documentation

◆ ComputeXidHorizonsResult

◆ GlobalVisHorizonKind

◆ ProcArrayStruct

Enumeration Type Documentation

◆ GlobalVisHorizonKind

Enumerator
VISHORIZON_SHARED 
VISHORIZON_CATALOG 
VISHORIZON_DATA 
VISHORIZON_TEMP 

Definition at line 251 of file procarray.c.

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

Function Documentation

◆ BackendPidGetProc()

PGPROC* BackendPidGetProc ( int  pid)

Definition at line 3155 of file procarray.c.

3156 {
3157  PGPROC *result;
3158 
3159  if (pid == 0) /* never match dummy PGPROCs */
3160  return NULL;
3161 
3162  LWLockAcquire(ProcArrayLock, LW_SHARED);
3163 
3164  result = BackendPidGetProcWithLock(pid);
3165 
3166  LWLockRelease(ProcArrayLock);
3167 
3168  return result;
3169 }
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1196
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1800
@ LW_SHARED
Definition: lwlock.h:105
PGPROC * BackendPidGetProcWithLock(int pid)
Definition: procarray.c:3178
Definition: proc.h:160

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

3179 {
3180  PGPROC *result = NULL;
3181  ProcArrayStruct *arrayP = procArray;
3182  int index;
3183 
3184  if (pid == 0) /* never match dummy PGPROCs */
3185  return NULL;
3186 
3187  for (index = 0; index < arrayP->numProcs; index++)
3188  {
3189  PGPROC *proc = &allProcs[arrayP->pgprocnos[index]];
3190 
3191  if (proc->pid == pid)
3192  {
3193  result = proc;
3194  break;
3195  }
3196  }
3197 
3198  return result;
3199 }
static PGPROC * allProcs
Definition: procarray.c:262
static ProcArrayStruct * procArray
Definition: procarray.c:260
int pid
Definition: proc.h:184
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
Definition: type.h:90

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

Referenced by BackendPidGetProc(), and GetBlockerStatusData().

◆ BackendXidGetPid()

int BackendXidGetPid ( TransactionId  xid)

Definition at line 3215 of file procarray.c.

3216 {
3217  int result = 0;
3218  ProcArrayStruct *arrayP = procArray;
3219  TransactionId *other_xids = ProcGlobal->xids;
3220  int index;
3221 
3222  if (xid == InvalidTransactionId) /* never match invalid xid */
3223  return 0;
3224 
3225  LWLockAcquire(ProcArrayLock, LW_SHARED);
3226 
3227  for (index = 0; index < arrayP->numProcs; index++)
3228  {
3229  int pgprocno = arrayP->pgprocnos[index];
3230  PGPROC *proc = &allProcs[pgprocno];
3231 
3232  if (other_xids[index] == xid)
3233  {
3234  result = proc->pid;
3235  break;
3236  }
3237  }
3238 
3239  LWLockRelease(ProcArrayLock);
3240 
3241  return result;
3242 }
uint32 TransactionId
Definition: c.h:587
PROC_HDR * ProcGlobal
Definition: proc.c:80
TransactionId * xids
Definition: proc.h:359
#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 3614 of file procarray.c.

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

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

Referenced by ResolveRecoveryConflictWithDatabase(), and SendRecoveryConflictWithBufferPin().

◆ CancelVirtualTransaction()

pid_t CancelVirtualTransaction ( VirtualTransactionId  vxid,
ProcSignalReason  sigmode 
)

Definition at line 3445 of file procarray.c.

3446 {
3447  return SignalVirtualTransaction(vxid, sigmode, true);
3448 }
pid_t SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode, bool conflictPending)
Definition: procarray.c:3451

References SignalVirtualTransaction().

Referenced by ResolveRecoveryConflictWithVirtualXIDs().

◆ ComputeXidHorizons()

static void ComputeXidHorizons ( ComputeXidHorizonsResult h)
static

Definition at line 1715 of file procarray.c.

1716 {
1717  ProcArrayStruct *arrayP = procArray;
1718  TransactionId kaxmin;
1719  bool in_recovery = RecoveryInProgress();
1720  TransactionId *other_xids = ProcGlobal->xids;
1721 
1722  /* inferred after ProcArrayLock is released */
1724 
1725  LWLockAcquire(ProcArrayLock, LW_SHARED);
1726 
1728 
1729  /*
1730  * We initialize the MIN() calculation with latestCompletedXid + 1. This
1731  * is a lower bound for the XIDs that might appear in the ProcArray later,
1732  * and so protects us against overestimating the result due to future
1733  * additions.
1734  */
1735  {
1736  TransactionId initial;
1737 
1739  Assert(TransactionIdIsValid(initial));
1740  TransactionIdAdvance(initial);
1741 
1742  h->oldest_considered_running = initial;
1743  h->shared_oldest_nonremovable = initial;
1744  h->data_oldest_nonremovable = initial;
1745 
1746  /*
1747  * Only modifications made by this backend affect the horizon for
1748  * temporary relations. Instead of a check in each iteration of the
1749  * loop over all PGPROCs it is cheaper to just initialize to the
1750  * current top-level xid any.
1751  *
1752  * Without an assigned xid we could use a horizon as aggressive as
1753  * ReadNewTransactionid(), but we can get away with the much cheaper
1754  * latestCompletedXid + 1: If this backend has no xid there, by
1755  * definition, can't be any newer changes in the temp table than
1756  * latestCompletedXid.
1757  */
1760  else
1761  h->temp_oldest_nonremovable = initial;
1762  }
1763 
1764  /*
1765  * Fetch slot horizons while ProcArrayLock is held - the
1766  * LWLockAcquire/LWLockRelease are a barrier, ensuring this happens inside
1767  * the lock.
1768  */
1771 
1772  for (int index = 0; index < arrayP->numProcs; index++)
1773  {
1774  int pgprocno = arrayP->pgprocnos[index];
1775  PGPROC *proc = &allProcs[pgprocno];
1776  int8 statusFlags = ProcGlobal->statusFlags[index];
1777  TransactionId xid;
1778  TransactionId xmin;
1779 
1780  /* Fetch xid just once - see GetNewTransactionId */
1781  xid = UINT32_ACCESS_ONCE(other_xids[index]);
1782  xmin = UINT32_ACCESS_ONCE(proc->xmin);
1783 
1784  /*
1785  * Consider both the transaction's Xmin, and its Xid.
1786  *
1787  * We must check both because a transaction might have an Xmin but not
1788  * (yet) an Xid; conversely, if it has an Xid, that could determine
1789  * some not-yet-set Xmin.
1790  */
1791  xmin = TransactionIdOlder(xmin, xid);
1792 
1793  /* if neither is set, this proc doesn't influence the horizon */
1794  if (!TransactionIdIsValid(xmin))
1795  continue;
1796 
1797  /*
1798  * Don't ignore any procs when determining which transactions might be
1799  * considered running. While slots should ensure logical decoding
1800  * backends are protected even without this check, it can't hurt to
1801  * include them here as well..
1802  */
1805 
1806  /*
1807  * Skip over backends either vacuuming (which is ok with rows being
1808  * removed, as long as pg_subtrans is not truncated) or doing logical
1809  * decoding (which manages xmin separately, check below).
1810  */
1811  if (statusFlags & (PROC_IN_VACUUM | PROC_IN_LOGICAL_DECODING))
1812  continue;
1813 
1814  /* shared tables need to take backends in all databases into account */
1817 
1818  /*
1819  * Normally sessions in other databases are ignored for anything but
1820  * the shared horizon.
1821  *
1822  * However, include them when MyDatabaseId is not (yet) set. A
1823  * backend in the process of starting up must not compute a "too
1824  * aggressive" horizon, otherwise we could end up using it to prune
1825  * still-needed data away. If the current backend never connects to a
1826  * database this is harmless, because data_oldest_nonremovable will
1827  * never be utilized.
1828  *
1829  * Also, sessions marked with PROC_AFFECTS_ALL_HORIZONS should always
1830  * be included. (This flag is used for hot standby feedback, which
1831  * can't be tied to a specific database.)
1832  *
1833  * Also, while in recovery we cannot compute an accurate per-database
1834  * horizon, as all xids are managed via the KnownAssignedXids
1835  * machinery.
1836  */
1837  if (proc->databaseId == MyDatabaseId ||
1838  MyDatabaseId == InvalidOid ||
1839  (statusFlags & PROC_AFFECTS_ALL_HORIZONS) ||
1840  in_recovery)
1841  {
1844  }
1845  }
1846 
1847  /*
1848  * If in recovery fetch oldest xid in KnownAssignedXids, will be applied
1849  * after lock is released.
1850  */
1851  if (in_recovery)
1852  kaxmin = KnownAssignedXidsGetOldestXmin();
1853 
1854  /*
1855  * No other information from shared state is needed, release the lock
1856  * immediately. The rest of the computations can be done without a lock.
1857  */
1858  LWLockRelease(ProcArrayLock);
1859 
1860  if (in_recovery)
1861  {
1868  /* temp relations cannot be accessed in recovery */
1869  }
1870  else
1871  {
1872  /*
1873  * Compute the cutoff XID by subtracting vacuum_defer_cleanup_age.
1874  *
1875  * vacuum_defer_cleanup_age provides some additional "slop" for the
1876  * benefit of hot standby queries on standby servers. This is quick
1877  * and dirty, and perhaps not all that useful unless the primary has a
1878  * predictable transaction rate, but it offers some protection when
1879  * there's no walsender connection. Note that we are assuming
1880  * vacuum_defer_cleanup_age isn't large enough to cause wraparound ---
1881  * so guc.c should limit it to no more than the xidStopLimit threshold
1882  * in varsup.c. Also note that we intentionally don't apply
1883  * vacuum_defer_cleanup_age on standby servers.
1884  */
1894  /* defer doesn't apply to temp relations */
1895  }
1896 
1897  /*
1898  * Check whether there are replication slots requiring an older xmin.
1899  */
1904 
1905  /*
1906  * The only difference between catalog / data horizons is that the slot's
1907  * catalog xmin is applied to the catalog one (so catalogs can be accessed
1908  * for logical decoding). Initialize with data horizon, and then back up
1909  * further if necessary. Have to back up the shared horizon as well, since
1910  * that also can contain catalogs.
1911  */
1915  h->slot_catalog_xmin);
1919  h->slot_catalog_xmin);
1920 
1921  /*
1922  * It's possible that slots / vacuum_defer_cleanup_age backed up the
1923  * horizons further than oldest_considered_running. Fix.
1924  */
1934 
1935  /*
1936  * shared horizons have to be at least as old as the oldest visible in
1937  * current db
1938  */
1943 
1944  /*
1945  * Horizons need to ensure that pg_subtrans access is still possible for
1946  * the relevant backends.
1947  */
1958  h->slot_xmin));
1961  h->slot_catalog_xmin));
1962 
1963  /* update approximate horizons with the computed horizons */
1965 }
signed char int8
Definition: c.h:427
Oid MyDatabaseId
Definition: globals.c:89
Assert(fmt[strlen(fmt) - 1] !='\n')
#define PROC_IN_LOGICAL_DECODING
Definition: proc.h:58
#define PROC_AFFECTS_ALL_HORIZONS
Definition: proc.h:59
#define PROC_IN_VACUUM
Definition: proc.h:55
#define UINT32_ACCESS_ONCE(var)
Definition: procarray.c:69
static void GlobalVisUpdateApply(ComputeXidHorizonsResult *horizons)
Definition: procarray.c:4110
static TransactionId KnownAssignedXidsGetOldestXmin(void)
Definition: procarray.c:5088
PGPROC * MyProc
Definition: proc.c:68
int vacuum_defer_cleanup_age
Definition: standby.c:40
TransactionId slot_catalog_xmin
Definition: procarray.c:194
TransactionId data_oldest_nonremovable
Definition: procarray.c:239
TransactionId temp_oldest_nonremovable
Definition: procarray.c:245
TransactionId shared_oldest_nonremovable
Definition: procarray.c:216
TransactionId oldest_considered_running
Definition: procarray.c:207
TransactionId slot_xmin
Definition: procarray.c:193
FullTransactionId latest_completed
Definition: procarray.c:187
TransactionId catalog_oldest_nonremovable
Definition: procarray.c:233
TransactionId shared_oldest_nonremovable_raw
Definition: procarray.c:227
TransactionId xmin
Definition: proc.h:176
TransactionId xid
Definition: proc.h:171
uint8 * statusFlags
Definition: proc.h:371
TransactionId replication_slot_xmin
Definition: procarray.c:96
TransactionId replication_slot_catalog_xmin
Definition: procarray.c:98
FullTransactionId latestCompletedXid
Definition: transam.h:238
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:292
static TransactionId TransactionIdRetreatedBy(TransactionId xid, uint32 amount)
Definition: transam.h:322
#define XidFromFullTransactionId(x)
Definition: transam.h:48
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define TransactionIdAdvance(dest)
Definition: transam.h:91
static TransactionId TransactionIdOlder(TransactionId a, TransactionId b)
Definition: transam.h:334
VariableCache ShmemVariableCache
Definition: varsup.c:34
bool RecoveryInProgress(void)
Definition: xlog.c:5762

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

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

◆ CountDBBackends()

int CountDBBackends ( Oid  databaseid)

Definition at line 3553 of file procarray.c.

3554 {
3555  ProcArrayStruct *arrayP = procArray;
3556  int count = 0;
3557  int index;
3558 
3559  LWLockAcquire(ProcArrayLock, LW_SHARED);
3560 
3561  for (index = 0; index < arrayP->numProcs; index++)
3562  {
3563  int pgprocno = arrayP->pgprocnos[index];
3564  PGPROC *proc = &allProcs[pgprocno];
3565 
3566  if (proc->pid == 0)
3567  continue; /* do not count prepared xacts */
3568  if (!OidIsValid(databaseid) ||
3569  proc->databaseId == databaseid)
3570  count++;
3571  }
3572 
3573  LWLockRelease(ProcArrayLock);
3574 
3575  return count;
3576 }
#define OidIsValid(objectId)
Definition: c.h:710

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

Referenced by ResolveRecoveryConflictWithDatabase().

◆ CountDBConnections()

int CountDBConnections ( Oid  databaseid)

Definition at line 3583 of file procarray.c.

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

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

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

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

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

◆ CountUserBackends()

int CountUserBackends ( Oid  roleid)

Definition at line 3654 of file procarray.c.

3655 {
3656  ProcArrayStruct *arrayP = procArray;
3657  int count = 0;
3658  int index;
3659 
3660  LWLockAcquire(ProcArrayLock, LW_SHARED);
3661 
3662  for (index = 0; index < arrayP->numProcs; index++)
3663  {
3664  int pgprocno = arrayP->pgprocnos[index];
3665  PGPROC *proc = &allProcs[pgprocno];
3666 
3667  if (proc->pid == 0)
3668  continue; /* do not count prepared xacts */
3669  if (proc->isBackgroundWorker)
3670  continue; /* do not count background workers */
3671  if (proc->roleId == roleid)
3672  count++;
3673  }
3674 
3675  LWLockRelease(ProcArrayLock);
3676 
3677  return count;
3678 }
Oid roleId
Definition: proc.h:193

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

410 {
411  bool found;
412 
413  /* Create or attach to the ProcArray shared structure */
415  ShmemInitStruct("Proc Array",
416  add_size(offsetof(ProcArrayStruct, pgprocnos),
417  mul_size(sizeof(int),
419  &found);
420 
421  if (!found)
422  {
423  /*
424  * We're the first - initialize.
425  */
426  procArray->numProcs = 0;
437  }
438 
440 
441  /* Create or attach to the KnownAssignedXids arrays too, if needed */
442  if (EnableHotStandby)
443  {
445  ShmemInitStruct("KnownAssignedXids",
446  mul_size(sizeof(TransactionId),
448  &found);
449  KnownAssignedXidsValid = (bool *)
450  ShmemInitStruct("KnownAssignedXidsValid",
451  mul_size(sizeof(bool), TOTAL_MAX_CACHED_SUBXIDS),
452  &found);
453  }
454 }
#define offsetof(type, field)
Definition: c.h:727
#define TOTAL_MAX_CACHED_SUBXIDS
#define PROCARRAY_MAXPROCS
static TransactionId * KnownAssignedXids
Definition: procarray.c:272
static bool * KnownAssignedXidsValid
Definition: procarray.c:273
Size add_size(Size s1, Size s2)
Definition: shmem.c:502
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:396
Size mul_size(Size s1, Size s2)
Definition: shmem.c:519
#define SpinLockInit(lock)
Definition: spin.h:60
PGPROC * allProcs
Definition: proc.h:356
int maxKnownAssignedXids
Definition: procarray.c:80
slock_t known_assigned_xids_lck
Definition: procarray.c:84
int numKnownAssignedXids
Definition: procarray.c:81
TransactionId lastOverflowedXid
Definition: procarray.c:93
int tailKnownAssignedXids
Definition: procarray.c:82
int headKnownAssignedXids
Definition: procarray.c:83
uint64 xactCompletionCount
Definition: transam.h:248
bool EnableHotStandby
Definition: xlog.c:122

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

Referenced by CreateSharedMemoryAndSemaphores().

◆ ExpireAllKnownAssignedTransactionIds()

void ExpireAllKnownAssignedTransactionIds ( void  )

Definition at line 4472 of file procarray.c.

4473 {
4474  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4476 
4477  /*
4478  * Reset lastOverflowedXid. Currently, lastOverflowedXid has no use after
4479  * the call of this function. But do this for unification with what
4480  * ExpireOldKnownAssignedTransactionIds() do.
4481  */
4483  LWLockRelease(ProcArrayLock);
4484 }
static void KnownAssignedXidsRemovePreceding(TransactionId xid)
Definition: procarray.c:4938

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

Referenced by ShutdownRecoveryTransactionEnvironment().

◆ ExpireOldKnownAssignedTransactionIds()

void ExpireOldKnownAssignedTransactionIds ( TransactionId  xid)

Definition at line 4492 of file procarray.c.

4493 {
4494  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4495 
4496  /*
4497  * Reset lastOverflowedXid if we know all transactions that have been
4498  * possibly running are being gone. Not doing so could cause an incorrect
4499  * lastOverflowedXid value, which makes extra snapshots be marked as
4500  * suboverflowed.
4501  */
4505  LWLockRelease(ProcArrayLock);
4506 }
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:273

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

4448 {
4450 
4451  /*
4452  * Uses same locking as transaction commit
4453  */
4454  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4455 
4456  KnownAssignedXidsRemoveTree(xid, nsubxids, subxids);
4457 
4458  /* As in ProcArrayEndTransaction, advance latestCompletedXid */
4460 
4461  /* ... and xactCompletionCount */
4463 
4464  LWLockRelease(ProcArrayLock);
4465 }
static void KnownAssignedXidsRemoveTree(TransactionId xid, int nsubxids, TransactionId *subxids)
Definition: procarray.c:4916
static void MaintainLatestCompletedXidRecovery(TransactionId latestXid)
Definition: procarray.c:979
HotStandbyState standbyState
Definition: xlogutils.c:56
@ STANDBY_INITIALIZED
Definition: xlogutils.h:50

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

Referenced by xact_redo_abort(), and xact_redo_commit().

◆ FullXidRelativeTo()

static FullTransactionId FullXidRelativeTo ( FullTransactionId  rel,
TransactionId  xid 
)
inlinestatic

Definition at line 4295 of file procarray.c.

4296 {
4297  TransactionId rel_xid = XidFromFullTransactionId(rel);
4298 
4300  Assert(TransactionIdIsValid(rel_xid));
4301 
4302  /* not guaranteed to find issues, but likely to catch mistakes */
4304 
4306  + (int32) (xid - rel_xid));
4307 }
signed int int32
Definition: c.h:429
#define U64FromFullTransactionId(x)
Definition: transam.h:49
static FullTransactionId FullTransactionIdFromU64(uint64 value)
Definition: transam.h:81
#define AssertTransactionIdInAllowableRange(xid)
Definition: transam.h: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 3371 of file procarray.c.

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

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

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

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

2082 {
2083  return TOTAL_MAX_CACHED_SUBXIDS;
2084 }

References TOTAL_MAX_CACHED_SUBXIDS.

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

◆ GetMaxSnapshotXidCount()

int GetMaxSnapshotXidCount ( void  )

Definition at line 2070 of file procarray.c.

2071 {
2072  return procArray->maxProcs;
2073 }

References ProcArrayStruct::maxProcs, and procArray.

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

◆ GetOldestActiveTransactionId()

TransactionId GetOldestActiveTransactionId ( void  )

Definition at line 2897 of file procarray.c.

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

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

Referenced by CreateCheckPoint().

◆ GetOldestNonRemovableTransactionId()

TransactionId GetOldestNonRemovableTransactionId ( Relation  rel)

Definition at line 2006 of file procarray.c.

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

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

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

◆ GetOldestSafeDecodingTransactionId()

TransactionId GetOldestSafeDecodingTransactionId ( bool  catalogOnly)

Definition at line 2962 of file procarray.c.

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

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

Referenced by CreateInitDecodingContext(), and SnapBuildInitialSnapshot().

◆ GetOldestTransactionIdConsideredRunning()

TransactionId GetOldestTransactionIdConsideredRunning ( void  )

Definition at line 2035 of file procarray.c.

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

References ComputeXidHorizons(), and ComputeXidHorizonsResult::oldest_considered_running.

Referenced by CreateCheckPoint(), and CreateRestartPoint().

◆ GetReplicationHorizons()

void GetReplicationHorizons ( TransactionId xmin,
TransactionId catalog_xmin 
)

Definition at line 2048 of file procarray.c.

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

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

Referenced by XLogWalRcvSendHSFeedback().

◆ GetRunningTransactionData()

RunningTransactions GetRunningTransactionData ( void  )

Definition at line 2722 of file procarray.c.

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

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

Referenced by LogStandbySnapshot().

◆ GetSnapshotData()

Snapshot GetSnapshotData ( Snapshot  snapshot)

Definition at line 2207 of file procarray.c.

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

References SnapshotData::active_count, allProcs, Assert(), SnapshotData::copied, XidCacheStatus::count, SnapshotData::curcid, GlobalVisState::definitely_needed, ereport, errcode(), errmsg(), ERROR, FullTransactionIdAdvance(), FullTransactionIdNewer(), FullXidRelativeTo(), GetCurrentCommandId(), GetMaxSnapshotSubxidCount(), GetMaxSnapshotXidCount(), GetSnapshotDataInitOldSnapshot(), GetSnapshotDataReuse(), GlobalVisCatalogRels, GlobalVisDataRels, GlobalVisSharedRels, GlobalVisTempRels, InvalidTransactionId, KnownAssignedXidsGetAndSetXmin(), ProcArrayStruct::lastOverflowedXid, VariableCacheData::latestCompletedXid, likely, LW_SHARED, LWLockAcquire(), LWLockRelease(), malloc, GlobalVisState::maybe_needed, MyProc, NormalTransactionIdPrecedes, ProcArrayStruct::numProcs, VariableCacheData::oldestXid, pg_read_barrier, ProcArrayStruct::pgprocnos, PGPROC::pgxactoff, PROC_IN_LOGICAL_DECODING, PROC_IN_VACUUM, procArray, ProcGlobal, RecentXmin, RecoveryInProgress(), SnapshotData::regd_count, ProcArrayStruct::replication_slot_catalog_xmin, ProcArrayStruct::replication_slot_xmin, ShmemVariableCache, SnapshotData::snapXactCompletionCount, PROC_HDR::statusFlags, SnapshotData::suboverflowed, SnapshotData::subxcnt, PGPROC::subxids, PROC_HDR::subxidStates, SnapshotData::subxip, SnapshotData::takenDuringRecovery, TransactionIdAdvance, TransactionIdIsNormal, TransactionIdIsValid, TransactionIdOlder(), TransactionIdPrecedesOrEquals(), TransactionIdRetreatedBy(), TransactionXmin, UINT32_ACCESS_ONCE, vacuum_defer_cleanup_age, VariableCacheData::xactCompletionCount, SnapshotData::xcnt, PGPROC::xid, XidFromFullTransactionId, XidCache::xids, PROC_HDR::xids, SnapshotData::xip, SnapshotData::xmax, PGPROC::xmin, and SnapshotData::xmin.

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

◆ GetSnapshotDataInitOldSnapshot()

static void GetSnapshotDataInitOldSnapshot ( Snapshot  snapshot)
static

Definition at line 2090 of file procarray.c.

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

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

Referenced by GetSnapshotData(), and GetSnapshotDataReuse().

◆ GetSnapshotDataReuse()

static bool GetSnapshotDataReuse ( Snapshot  snapshot)
static

Definition at line 2124 of file procarray.c.

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

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

Referenced by GetSnapshotData().

◆ GetVirtualXIDsDelayingChkpt()

VirtualTransactionId* GetVirtualXIDsDelayingChkpt ( int *  nvxids,
int  type 
)

Definition at line 3060 of file procarray.c.

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

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

Referenced by CreateCheckPoint().

◆ GlobalVisCheckRemovableFullXid()

bool GlobalVisCheckRemovableFullXid ( Relation  rel,
FullTransactionId  fxid 
)

Definition at line 4260 of file procarray.c.

4261 {
4263 
4264  state = GlobalVisTestFor(rel);
4265 
4266  return GlobalVisTestIsRemovableFullXid(state, fxid);
4267 }
bool GlobalVisTestIsRemovableFullXid(GlobalVisState *state, FullTransactionId fxid)
Definition: procarray.c:4166
GlobalVisState * GlobalVisTestFor(Relation rel)
Definition: procarray.c:4051
Definition: regguts.h:318

References GlobalVisTestFor(), and GlobalVisTestIsRemovableFullXid().

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

◆ GlobalVisCheckRemovableXid()

bool GlobalVisCheckRemovableXid ( Relation  rel,
TransactionId  xid 
)

Definition at line 4274 of file procarray.c.

4275 {
4277 
4278  state = GlobalVisTestFor(rel);
4279 
4280  return GlobalVisTestIsRemovableXid(state, xid);
4281 }
bool GlobalVisTestIsRemovableXid(GlobalVisState *state, TransactionId xid)
Definition: procarray.c:4208

References GlobalVisTestFor(), and GlobalVisTestIsRemovableXid().

Referenced by GinPageIsRecyclable().

◆ GlobalVisHorizonKindForRel()

static GlobalVisHorizonKind GlobalVisHorizonKindForRel ( Relation  rel)
inlinestatic

Definition at line 1972 of file procarray.c.

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

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

Referenced by GetOldestNonRemovableTransactionId(), and GlobalVisTestFor().

◆ GlobalVisTestFor()

GlobalVisState* GlobalVisTestFor ( Relation  rel)

Definition at line 4051 of file procarray.c.

4052 {
4053  GlobalVisState *state = NULL;
4054 
4055  /* XXX: we should assert that a snapshot is pushed or registered */
4056  Assert(RecentXmin);
4057 
4058  switch (GlobalVisHorizonKindForRel(rel))
4059  {
4060  case VISHORIZON_SHARED:
4062  break;
4063  case VISHORIZON_CATALOG:
4065  break;
4066  case VISHORIZON_DATA:
4068  break;
4069  case VISHORIZON_TEMP:
4071  break;
4072  }
4073 
4074  Assert(FullTransactionIdIsValid(state->definitely_needed) &&
4075  FullTransactionIdIsValid(state->maybe_needed));
4076 
4077  return state;
4078 }
#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 4166 of file procarray.c.

4168 {
4169  /*
4170  * If fxid is older than maybe_needed bound, it definitely is visible to
4171  * everyone.
4172  */
4173  if (FullTransactionIdPrecedes(fxid, state->maybe_needed))
4174  return true;
4175 
4176  /*
4177  * If fxid is >= definitely_needed bound, it is very likely to still be
4178  * considered running.
4179  */
4180  if (FullTransactionIdFollowsOrEquals(fxid, state->definitely_needed))
4181  return false;
4182 
4183  /*
4184  * fxid is between maybe_needed and definitely_needed, i.e. there might or
4185  * might not exist a snapshot considering fxid running. If it makes sense,
4186  * update boundaries and recheck.
4187  */
4189  {
4190  GlobalVisUpdate();
4191 
4192  Assert(FullTransactionIdPrecedes(fxid, state->definitely_needed));
4193 
4194  return FullTransactionIdPrecedes(fxid, state->maybe_needed);
4195  }
4196  else
4197  return false;
4198 }
static bool GlobalVisTestShouldUpdate(GlobalVisState *state)
Definition: procarray.c:4091
static void GlobalVisUpdate(void)
Definition: procarray.c:4149
#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 4208 of file procarray.c.

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

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

4236 {
4237  /* acquire accurate horizon if not already done */
4239  GlobalVisUpdate();
4240 
4241  return state->maybe_needed;
4242 }

References GlobalVisTestShouldUpdate(), and GlobalVisUpdate().

Referenced by GlobalVisTestNonRemovableHorizon().

◆ GlobalVisTestNonRemovableHorizon()

TransactionId GlobalVisTestNonRemovableHorizon ( GlobalVisState state)

Definition at line 4246 of file procarray.c.

4247 {
4248  FullTransactionId cutoff;
4249 
4251 
4252  return XidFromFullTransactionId(cutoff);
4253 }
FullTransactionId GlobalVisTestNonRemovableFullHorizon(GlobalVisState *state)
Definition: procarray.c:4235

References GlobalVisTestNonRemovableFullHorizon(), and XidFromFullTransactionId.

Referenced by heap_page_prune_opt(), and heap_prune_satisfies_vacuum().

◆ GlobalVisTestShouldUpdate()

static bool GlobalVisTestShouldUpdate ( GlobalVisState state)
static

Definition at line 4091 of file procarray.c.

4092 {
4093  /* hasn't been updated yet */
4095  return true;
4096 
4097  /*
4098  * If the maybe_needed/definitely_needed boundaries are the same, it's
4099  * unlikely to be beneficial to refresh boundaries.
4100  */
4101  if (FullTransactionIdFollowsOrEquals(state->maybe_needed,
4102  state->definitely_needed))
4103  return false;
4104 
4105  /* does the last snapshot built have a different xmin? */
4107 }
static TransactionId ComputeXidHorizonsResultLastXmin
Definition: procarray.c:298

References ComputeXidHorizonsResultLastXmin, FullTransactionIdFollowsOrEquals, RecentXmin, and TransactionIdIsValid.

Referenced by GlobalVisTestIsRemovableFullXid(), and GlobalVisTestNonRemovableFullHorizon().

◆ GlobalVisUpdate()

static void GlobalVisUpdate ( void  )
static

Definition at line 4149 of file procarray.c.

4150 {
4151  ComputeXidHorizonsResult horizons;
4152 
4153  /* updates the horizons as a side-effect */
4154  ComputeXidHorizons(&horizons);
4155 }

References ComputeXidHorizons().

Referenced by GlobalVisTestIsRemovableFullXid(), and GlobalVisTestNonRemovableFullHorizon().

◆ GlobalVisUpdateApply()

static void GlobalVisUpdateApply ( ComputeXidHorizonsResult horizons)
static

Definition at line 4110 of file procarray.c.

4111 {
4114  horizons->shared_oldest_nonremovable);
4117  horizons->catalog_oldest_nonremovable);
4120  horizons->data_oldest_nonremovable);
4123  horizons->temp_oldest_nonremovable);
4124 
4125  /*
4126  * In longer running transactions it's possible that transactions we
4127  * previously needed to treat as running aren't around anymore. So update
4128  * definitely_needed to not be earlier than maybe_needed.
4129  */
4140 
4142 }

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

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

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

Referenced by CreateCheckPoint().

◆ IsBackendPid()

bool IsBackendPid ( int  pid)

Definition at line 3250 of file procarray.c.

3251 {
3252  return (BackendPidGetProc(pid) != NULL);
3253 }
PGPROC * BackendPidGetProc(int pid)
Definition: procarray.c:3155

References BackendPidGetProc().

Referenced by pg_stat_get_subscription().

◆ KnownAssignedXidExists()

static bool KnownAssignedXidExists ( TransactionId  xid)
static

Definition at line 4877 of file procarray.c.

4878 {
4880 
4881  return KnownAssignedXidsSearch(xid, false);
4882 }
static bool KnownAssignedXidsSearch(TransactionId xid, bool remove)
Definition: procarray.c:4784

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

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

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

Referenced by ProcArrayApplyRecoveryInfo(), and RecordKnownAssignedTransactionIds().

◆ KnownAssignedXidsCompress()

static void KnownAssignedXidsCompress ( bool  force)
static

Definition at line 4604 of file procarray.c.

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

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

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

◆ KnownAssignedXidsDisplay()

static void KnownAssignedXidsDisplay ( int  trace_level)
static

Definition at line 5123 of file procarray.c.

5124 {
5125  ProcArrayStruct *pArray = procArray;
5127  int head,
5128  tail,
5129  i;
5130  int nxids = 0;
5131 
5132  tail = pArray->tailKnownAssignedXids;
5133  head = pArray->headKnownAssignedXids;
5134 
5135  initStringInfo(&buf);
5136 
5137  for (i = tail; i < head; i++)
5138  {
5140  {
5141  nxids++;
5142  appendStringInfo(&buf, "[%d]=%u ", i, KnownAssignedXids[i]);
5143  }
5144  }
5145 
5146  elog(trace_level, "%d KnownAssignedXids (num=%d tail=%d head=%d) %s",
5147  nxids,
5148  pArray->numKnownAssignedXids,
5149  pArray->tailKnownAssignedXids,
5150  pArray->headKnownAssignedXids,
5151  buf.data);
5152 
5153  pfree(buf.data);
5154 }
void pfree(void *pointer)
Definition: mcxt.c:1175
static char * buf
Definition: pg_test_fsync.c:67
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59

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

Referenced by KnownAssignedXidsAdd(), and ProcArrayApplyRecoveryInfo().

◆ KnownAssignedXidsGet()

static int KnownAssignedXidsGet ( TransactionId xarray,
TransactionId  xmax 
)
static

Definition at line 5016 of file procarray.c.

5017 {
5019 
5020  return KnownAssignedXidsGetAndSetXmin(xarray, &xtmp, xmax);
5021 }

References InvalidTransactionId, and KnownAssignedXidsGetAndSetXmin().

Referenced by TransactionIdIsInProgress().

◆ KnownAssignedXidsGetAndSetXmin()

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

Definition at line 5030 of file procarray.c.

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

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

Referenced by GetSnapshotData(), and KnownAssignedXidsGet().

◆ KnownAssignedXidsGetOldestXmin()

static TransactionId KnownAssignedXidsGetOldestXmin ( void  )
static

Definition at line 5088 of file procarray.c.

5089 {
5090  int head,
5091  tail;
5092  int i;
5093 
5094  /*
5095  * Fetch head just once, since it may change while we loop.
5096  */
5101 
5102  for (i = tail; i < head; i++)
5103  {
5104  /* Skip any gaps in the array */
5106  return KnownAssignedXids[i];
5107  }
5108 
5109  return InvalidTransactionId;
5110 }

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

Referenced by ComputeXidHorizons().

◆ KnownAssignedXidsRemove()

static void KnownAssignedXidsRemove ( TransactionId  xid)
static

Definition at line 4890 of file procarray.c.

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

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

Referenced by KnownAssignedXidsRemoveTree().

◆ KnownAssignedXidsRemovePreceding()

static void KnownAssignedXidsRemovePreceding ( TransactionId  xid)
static

Definition at line 4938 of file procarray.c.

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

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

Referenced by ExpireAllKnownAssignedTransactionIds(), and ExpireOldKnownAssignedTransactionIds().

◆ KnownAssignedXidsRemoveTree()

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

Definition at line 4916 of file procarray.c.

4918 {
4919  int i;
4920 
4921  if (TransactionIdIsValid(xid))
4923 
4924  for (i = 0; i < nsubxids; i++)
4925  KnownAssignedXidsRemove(subxids[i]);
4926 
4927  /* Opportunistically compress the array */
4929 }
static void KnownAssignedXidsRemove(TransactionId xid)
Definition: procarray.c:4890

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

Referenced by ExpireTreeKnownAssignedTransactionIds(), and ProcArrayApplyXidAssignment().

◆ KnownAssignedXidsReset()

static void KnownAssignedXidsReset ( void  )
static

Definition at line 5161 of file procarray.c.

5162 {
5163  ProcArrayStruct *pArray = procArray;
5164 
5165  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
5166 
5167  pArray->numKnownAssignedXids = 0;
5168  pArray->tailKnownAssignedXids = 0;
5169  pArray->headKnownAssignedXids = 0;
5170 
5171  LWLockRelease(ProcArrayLock);
5172 }

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

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

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

Referenced by KnownAssignedXidExists(), and KnownAssignedXidsRemove().

◆ MaintainLatestCompletedXid()

◆ MaintainLatestCompletedXidRecovery()

static void MaintainLatestCompletedXidRecovery ( TransactionId  latestXid)
static

Definition at line 979 of file procarray.c.

980 {
982  FullTransactionId rel;
983 
985  Assert(LWLockHeldByMe(ProcArrayLock));
986 
987  /*
988  * Need a FullTransactionId to compare latestXid with. Can't rely on
989  * latestCompletedXid to be initialized in recovery. But in recovery it's
990  * safe to access nextXid without a lock for the startup process.
991  */
994 
995  if (!FullTransactionIdIsValid(cur_latest) ||
996  TransactionIdPrecedes(XidFromFullTransactionId(cur_latest), latestXid))
997  {
999  FullXidRelativeTo(rel, latestXid);
1000  }
1001 
1003 }
bool IsUnderPostmaster
Definition: globals.c:113
#define AmStartupProcess()
Definition: miscadmin.h:444

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

Referenced by ExpireTreeKnownAssignedTransactionIds(), and ProcArrayApplyRecoveryInfo().

◆ MinimumActiveBackends()

bool MinimumActiveBackends ( int  min)

Definition at line 3500 of file procarray.c.

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

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

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

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

Referenced by InitProcessPhase2(), and MarkAsPrepared().

◆ ProcArrayApplyRecoveryInfo()

void ProcArrayApplyRecoveryInfo ( RunningTransactions  running)

Definition at line 1044 of file procarray.c.

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

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

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

◆ ProcArrayApplyXidAssignment()

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

Definition at line 1290 of file procarray.c.

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

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

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

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

Referenced by PrepareTransaction().

◆ ProcArrayEndTransaction()

void ProcArrayEndTransaction ( PGPROC proc,
TransactionId  latestXid 
)

Definition at line 658 of file procarray.c.

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

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

723 {
724  int pgxactoff = proc->pgxactoff;
725 
726  /*
727  * Note: we need exclusive lock here because we're going to change other
728  * processes' PGPROC entries.
729  */
730  Assert(LWLockHeldByMeInMode(ProcArrayLock, LW_EXCLUSIVE));
732  Assert(ProcGlobal->xids[pgxactoff] == proc->xid);
733 
734  ProcGlobal->xids[pgxactoff] = InvalidTransactionId;
735  proc->xid = InvalidTransactionId;
737  proc->xmin = InvalidTransactionId;
738 
739  /* be sure this is cleared in abort */
740  proc->delayChkptFlags = 0;
741 
742  proc->recoveryConflictPending = false;
743 
744  /* must be cleared with xid/xmin: */
745  /* avoid unnecessarily dirtying shared cachelines */
747  {
750  }
751 
752  /* Clear the subtransaction-XID cache too while holding the lock */
753  Assert(ProcGlobal->subxidStates[pgxactoff].count == proc->subxidStatus.count &&
755  if (proc->subxidStatus.count > 0 || proc->subxidStatus.overflowed)
756  {
757  ProcGlobal->subxidStates[pgxactoff].count = 0;
758  ProcGlobal->subxidStates[pgxactoff].overflowed = false;
759  proc->subxidStatus.count = 0;
760  proc->subxidStatus.overflowed = false;
761  }
762 
763  /* Also advance global latestCompletedXid while holding the lock */
764  MaintainLatestCompletedXid(latestXid);
765 
766  /* Same with xactCompletionCount */
768 }
bool LWLockHeldByMeInMode(LWLock *l, LWLockMode mode)
Definition: lwlock.c:1934
static void MaintainLatestCompletedXid(TransactionId latestXid)
Definition: procarray.c:957

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

Referenced by ProcArrayEndTransaction(), and ProcArrayGroupClearXid().

◆ ProcArrayGetReplicationSlotXmin()

void ProcArrayGetReplicationSlotXmin ( TransactionId xmin,
TransactionId catalog_xmin 
)

Definition at line 3912 of file procarray.c.

3914 {
3915  LWLockAcquire(ProcArrayLock, LW_SHARED);
3916 
3917  if (xmin != NULL)
3919 
3920  if (catalog_xmin != NULL)
3921  *catalog_xmin = procArray->replication_slot_catalog_xmin;
3922 
3923  LWLockRelease(ProcArrayLock);
3924 }

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

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

References allProcs, Assert(), INVALID_PGPROCNO, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MyProc, pg_atomic_compare_exchange_u32(), pg_atomic_exchange_u32(), pg_atomic_read_u32(), pg_atomic_write_u32(), pg_write_barrier, PGPROC::pgprocno, PGSemaphoreLock(), PGSemaphoreUnlock(), pgstat_report_wait_end(), pgstat_report_wait_start(), ProcArrayEndTransactionInternal(), PROC_HDR::procArrayGroupFirst, PGPROC::procArrayGroupMember, PGPROC::procArrayGroupMemberXid, PGPROC::procArrayGroupNext, ProcGlobal, PGPROC::sem, TransactionIdIsValid, WAIT_EVENT_PROCARRAY_GROUP_UPDATE, and PGPROC::xid.

Referenced by ProcArrayEndTransaction().

◆ ProcArrayInitRecovery()

void ProcArrayInitRecovery ( TransactionId  initializedUptoXID)

Definition at line 1013 of file procarray.c.

1014 {
1016  Assert(TransactionIdIsNormal(initializedUptoXID));
1017 
1018  /*
1019  * we set latestObservedXid to the xid SUBTRANS has been initialized up
1020  * to, so we can extend it from that point onwards in
1021  * RecordKnownAssignedTransactionIds, and when we get consistent in
1022  * ProcArrayApplyRecoveryInfo().
1023  */
1024  latestObservedXid = initializedUptoXID;
1026 }

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

Referenced by StartupXLOG().

◆ ProcArrayInstallImportedXmin()

bool ProcArrayInstallImportedXmin ( TransactionId  xmin,
VirtualTransactionId sourcevxid 
)

Definition at line 2570 of file procarray.c.

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

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

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

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

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

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

Referenced by FinishPreparedTransaction(), and RemoveProcFromArray().

◆ ProcArraySetReplicationSlotXmin()

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

Definition at line 3890 of file procarray.c.

3892 {
3893  Assert(!already_locked || LWLockHeldByMe(ProcArrayLock));
3894 
3895  if (!already_locked)
3896  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3897 
3899  procArray->replication_slot_catalog_xmin = catalog_xmin;
3900 
3901  if (!already_locked)
3902  LWLockRelease(ProcArrayLock);
3903 }

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

Referenced by ReplicationSlotsComputeRequiredXmin().

◆ ProcArrayShmemSize()

Size ProcArrayShmemSize ( void  )

Definition at line 367 of file procarray.c.

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

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

Referenced by CalculateShmemSize().

◆ RecordKnownAssignedTransactionIds()

void RecordKnownAssignedTransactionIds ( TransactionId  xid)

Definition at line 4377 of file procarray.c.

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

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

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

◆ SignalVirtualTransaction()

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

Definition at line 3451 of file procarray.c.

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

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

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

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

Referenced by dropdb().

◆ TransactionIdIsActive()

bool TransactionIdIsActive ( TransactionId  xid)

Definition at line 1611 of file procarray.c.

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

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

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

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

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

◆ XidCacheRemoveRunningXids()

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

Definition at line 3935 of file procarray.c.

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