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

Go to the source code of this file.

Data Structures

struct  ProcArrayStruct
 
struct  GlobalVisState
 
struct  ComputeXidHorizonsResult
 

Macros

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

Typedefs

typedef struct ProcArrayStruct ProcArrayStruct
 
typedef struct ComputeXidHorizonsResult ComputeXidHorizonsResult
 

Functions

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

Variables

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

Macro Definition Documentation

◆ MAXAUTOVACPIDS

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

Referenced by CountOtherDBBackends().

◆ PROCARRAY_MAXPROCS

◆ TOTAL_MAX_CACHED_SUBXIDS

◆ UINT32_ACCESS_ONCE

◆ xc_by_child_xid_inc

#define xc_by_child_xid_inc ( )    ((void) 0)

Definition at line 316 of file procarray.c.

Referenced by TransactionIdIsInProgress().

◆ xc_by_known_assigned_inc

#define xc_by_known_assigned_inc ( )    ((void) 0)

Definition at line 317 of file procarray.c.

Referenced by TransactionIdIsInProgress().

◆ xc_by_known_xact_inc

#define xc_by_known_xact_inc ( )    ((void) 0)

Definition at line 312 of file procarray.c.

Referenced by TransactionIdIsInProgress().

◆ xc_by_latest_xid_inc

#define xc_by_latest_xid_inc ( )    ((void) 0)

Definition at line 314 of file procarray.c.

Referenced by TransactionIdIsInProgress().

◆ xc_by_main_xid_inc

#define xc_by_main_xid_inc ( )    ((void) 0)

Definition at line 315 of file procarray.c.

Referenced by TransactionIdIsInProgress().

◆ xc_by_my_xact_inc

#define xc_by_my_xact_inc ( )    ((void) 0)

Definition at line 313 of file procarray.c.

Referenced by TransactionIdIsInProgress().

◆ xc_by_recent_xmin_inc

#define xc_by_recent_xmin_inc ( )    ((void) 0)

Definition at line 311 of file procarray.c.

Referenced by TransactionIdIsInProgress().

◆ xc_no_overflow_inc

#define xc_no_overflow_inc ( )    ((void) 0)

Definition at line 318 of file procarray.c.

Referenced by TransactionIdIsInProgress().

◆ xc_slow_answer_inc

#define xc_slow_answer_inc ( )    ((void) 0)

Definition at line 319 of file procarray.c.

Referenced by TransactionIdIsInProgress().

Typedef Documentation

◆ ComputeXidHorizonsResult

◆ ProcArrayStruct

Function Documentation

◆ BackendPidGetProc()

PGPROC* BackendPidGetProc ( int  pid)

Definition at line 3062 of file procarray.c.

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

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

3063 {
3064  PGPROC *result;
3065 
3066  if (pid == 0) /* never match dummy PGPROCs */
3067  return NULL;
3068 
3069  LWLockAcquire(ProcArrayLock, LW_SHARED);
3070 
3071  result = BackendPidGetProcWithLock(pid);
3072 
3073  LWLockRelease(ProcArrayLock);
3074 
3075  return result;
3076 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
PGPROC * BackendPidGetProcWithLock(int pid)
Definition: procarray.c:3085
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
Definition: proc.h:121

◆ BackendPidGetProcWithLock()

PGPROC* BackendPidGetProcWithLock ( int  pid)

Definition at line 3085 of file procarray.c.

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

Referenced by BackendPidGetProc(), and GetBlockerStatusData().

3086 {
3087  PGPROC *result = NULL;
3088  ProcArrayStruct *arrayP = procArray;
3089  int index;
3090 
3091  if (pid == 0) /* never match dummy PGPROCs */
3092  return NULL;
3093 
3094  for (index = 0; index < arrayP->numProcs; index++)
3095  {
3096  PGPROC *proc = &allProcs[arrayP->pgprocnos[index]];
3097 
3098  if (proc->pid == pid)
3099  {
3100  result = proc;
3101  break;
3102  }
3103  }
3104 
3105  return result;
3106 }
Definition: type.h:89
static PGPROC * allProcs
Definition: procarray.c:252
static ProcArrayStruct * procArray
Definition: procarray.c:250
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
Definition: proc.h:121
int pid
Definition: proc.h:146

◆ BackendXidGetPid()

int BackendXidGetPid ( TransactionId  xid)

Definition at line 3122 of file procarray.c.

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

Referenced by pgrowlocks().

3123 {
3124  int result = 0;
3125  ProcArrayStruct *arrayP = procArray;
3126  TransactionId *other_xids = ProcGlobal->xids;
3127  int index;
3128 
3129  if (xid == InvalidTransactionId) /* never match invalid xid */
3130  return 0;
3131 
3132  LWLockAcquire(ProcArrayLock, LW_SHARED);
3133 
3134  for (index = 0; index < arrayP->numProcs; index++)
3135  {
3136  int pgprocno = arrayP->pgprocnos[index];
3137  PGPROC *proc = &allProcs[pgprocno];
3138 
3139  if (other_xids[index] == xid)
3140  {
3141  result = proc->pid;
3142  break;
3143  }
3144  }
3145 
3146  LWLockRelease(ProcArrayLock);
3147 
3148  return result;
3149 }
uint32 TransactionId
Definition: c.h:587
PROC_HDR * ProcGlobal
Definition: proc.c:80
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
#define InvalidTransactionId
Definition: transam.h:31
TransactionId * xids
Definition: proc.h:321
static PGPROC * allProcs
Definition: procarray.c:252
static ProcArrayStruct * procArray
Definition: procarray.c:250
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
Definition: proc.h:121
int pid
Definition: proc.h:146

◆ CancelDBBackends()

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

Definition at line 3521 of file procarray.c.

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

Referenced by ResolveRecoveryConflictWithDatabase(), and SendRecoveryConflictWithBufferPin().

3522 {
3523  ProcArrayStruct *arrayP = procArray;
3524  int index;
3525 
3526  /* tell all backends to die */
3527  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3528 
3529  for (index = 0; index < arrayP->numProcs; index++)
3530  {
3531  int pgprocno = arrayP->pgprocnos[index];
3532  PGPROC *proc = &allProcs[pgprocno];
3533 
3534  if (databaseid == InvalidOid || proc->databaseId == databaseid)
3535  {
3536  VirtualTransactionId procvxid;
3537  pid_t pid;
3538 
3539  GET_VXID_FROM_PGPROC(procvxid, *proc);
3540 
3541  proc->recoveryConflictPending = conflictPending;
3542  pid = proc->pid;
3543  if (pid != 0)
3544  {
3545  /*
3546  * Kill the pid if it's still here. If not, that's what we
3547  * wanted so ignore any errors.
3548  */
3549  (void) SendProcSignal(pid, sigmode, procvxid.backendId);
3550  }
3551  }
3552  }
3553 
3554  LWLockRelease(ProcArrayLock);
3555 }
#define GET_VXID_FROM_PGPROC(vxid, proc)
Definition: lock.h:81
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
int SendProcSignal(pid_t pid, ProcSignalReason reason, BackendId backendId)
Definition: procsignal.c:260
bool recoveryConflictPending
Definition: proc.h:167
static PGPROC * allProcs
Definition: procarray.c:252
Oid databaseId
Definition: proc.h:154
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define InvalidOid
Definition: postgres_ext.h:36
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
BackendId backendId
Definition: lock.h:65
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
Definition: proc.h:121
int pid
Definition: proc.h:146

◆ CancelVirtualTransaction()

pid_t CancelVirtualTransaction ( VirtualTransactionId  vxid,
ProcSignalReason  sigmode 
)

Definition at line 3352 of file procarray.c.

References SignalVirtualTransaction().

Referenced by ResolveRecoveryConflictWithVirtualXIDs().

3353 {
3354  return SignalVirtualTransaction(vxid, sigmode, true);
3355 }
pid_t SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode, bool conflictPending)
Definition: procarray.c:3358

◆ ComputeXidHorizons()

static void ComputeXidHorizons ( ComputeXidHorizonsResult h)
static

Definition at line 1662 of file procarray.c.

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

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

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

◆ CountDBBackends()

int CountDBBackends ( Oid  databaseid)

Definition at line 3460 of file procarray.c.

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

Referenced by ResolveRecoveryConflictWithDatabase().

3461 {
3462  ProcArrayStruct *arrayP = procArray;
3463  int count = 0;
3464  int index;
3465 
3466  LWLockAcquire(ProcArrayLock, LW_SHARED);
3467 
3468  for (index = 0; index < arrayP->numProcs; index++)
3469  {
3470  int pgprocno = arrayP->pgprocnos[index];
3471  PGPROC *proc = &allProcs[pgprocno];
3472 
3473  if (proc->pid == 0)
3474  continue; /* do not count prepared xacts */
3475  if (!OidIsValid(databaseid) ||
3476  proc->databaseId == databaseid)
3477  count++;
3478  }
3479 
3480  LWLockRelease(ProcArrayLock);
3481 
3482  return count;
3483 }
#define OidIsValid(objectId)
Definition: c.h:710
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
static PGPROC * allProcs
Definition: procarray.c:252
Oid databaseId
Definition: proc.h:154
static ProcArrayStruct * procArray
Definition: procarray.c:250
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
Definition: proc.h:121
int pid
Definition: proc.h:146

◆ CountDBConnections()

int CountDBConnections ( Oid  databaseid)

Definition at line 3490 of file procarray.c.

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

Referenced by CheckMyDatabase().

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

◆ CountOtherDBBackends()

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

Definition at line 3611 of file procarray.c.

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

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

3612 {
3613  ProcArrayStruct *arrayP = procArray;
3614 
3615 #define MAXAUTOVACPIDS 10 /* max autovacs to SIGTERM per iteration */
3616  int autovac_pids[MAXAUTOVACPIDS];
3617  int tries;
3618 
3619  /* 50 tries with 100ms sleep between tries makes 5 sec total wait */
3620  for (tries = 0; tries < 50; tries++)
3621  {
3622  int nautovacs = 0;
3623  bool found = false;
3624  int index;
3625 
3627 
3628  *nbackends = *nprepared = 0;
3629 
3630  LWLockAcquire(ProcArrayLock, LW_SHARED);
3631 
3632  for (index = 0; index < arrayP->numProcs; index++)
3633  {
3634  int pgprocno = arrayP->pgprocnos[index];
3635  PGPROC *proc = &allProcs[pgprocno];
3636  uint8 statusFlags = ProcGlobal->statusFlags[index];
3637 
3638  if (proc->databaseId != databaseId)
3639  continue;
3640  if (proc == MyProc)
3641  continue;
3642 
3643  found = true;
3644 
3645  if (proc->pid == 0)
3646  (*nprepared)++;
3647  else
3648  {
3649  (*nbackends)++;
3650  if ((statusFlags & PROC_IS_AUTOVACUUM) &&
3651  nautovacs < MAXAUTOVACPIDS)
3652  autovac_pids[nautovacs++] = proc->pid;
3653  }
3654  }
3655 
3656  LWLockRelease(ProcArrayLock);
3657 
3658  if (!found)
3659  return false; /* no conflicting backends, so done */
3660 
3661  /*
3662  * Send SIGTERM to any conflicting autovacuums before sleeping. We
3663  * postpone this step until after the loop because we don't want to
3664  * hold ProcArrayLock while issuing kill(). We have no idea what might
3665  * block kill() inside the kernel...
3666  */
3667  for (index = 0; index < nautovacs; index++)
3668  (void) kill(autovac_pids[index], SIGTERM); /* ignore any error */
3669 
3670  /* sleep, then try again */
3671  pg_usleep(100 * 1000L); /* 100ms */
3672  }
3673 
3674  return true; /* timed out, still conflicts */
3675 }
PGPROC * MyProc
Definition: proc.c:68
unsigned char uint8
Definition: c.h:439
PROC_HDR * ProcGlobal
Definition: proc.c:80
#define kill(pid, sig)
Definition: win32_port.h:454
#define MAXAUTOVACPIDS
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
void pg_usleep(long microsec)
Definition: signal.c:53
static PGPROC * allProcs
Definition: procarray.c:252
Oid databaseId
Definition: proc.h:154
static ProcArrayStruct * procArray
Definition: procarray.c:250
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:100
uint8 * statusFlags
Definition: proc.h:333
Definition: proc.h:121
int pid
Definition: proc.h:146
#define PROC_IS_AUTOVACUUM
Definition: proc.h:54

◆ CountUserBackends()

int CountUserBackends ( Oid  roleid)

Definition at line 3561 of file procarray.c.

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

Referenced by InitializeSessionUserId().

3562 {
3563  ProcArrayStruct *arrayP = procArray;
3564  int count = 0;
3565  int index;
3566 
3567  LWLockAcquire(ProcArrayLock, LW_SHARED);
3568 
3569  for (index = 0; index < arrayP->numProcs; index++)
3570  {
3571  int pgprocno = arrayP->pgprocnos[index];
3572  PGPROC *proc = &allProcs[pgprocno];
3573 
3574  if (proc->pid == 0)
3575  continue; /* do not count prepared xacts */
3576  if (proc->isBackgroundWorker)
3577  continue; /* do not count background workers */
3578  if (proc->roleId == roleid)
3579  count++;
3580  }
3581 
3582  LWLockRelease(ProcArrayLock);
3583 
3584  return count;
3585 }
Oid roleId
Definition: proc.h:155
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
bool isBackgroundWorker
Definition: proc.h:160
static PGPROC * allProcs
Definition: procarray.c:252
static ProcArrayStruct * procArray
Definition: procarray.c:250
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
Definition: proc.h:121
int pid
Definition: proc.h:146

◆ CreateSharedProcArray()

void CreateSharedProcArray ( void  )

Definition at line 394 of file procarray.c.

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

Referenced by CreateSharedMemoryAndSemaphores().

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

◆ ExpireAllKnownAssignedTransactionIds()

void ExpireAllKnownAssignedTransactionIds ( void  )

Definition at line 4389 of file procarray.c.

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

Referenced by ShutdownRecoveryTransactionEnvironment().

4390 {
4391  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4393  LWLockRelease(ProcArrayLock);
4394 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
static void KnownAssignedXidsRemovePreceding(TransactionId xid)
Definition: procarray.c:4838
#define InvalidTransactionId
Definition: transam.h:31
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206

◆ ExpireOldKnownAssignedTransactionIds()

void ExpireOldKnownAssignedTransactionIds ( TransactionId  xid)

Definition at line 4401 of file procarray.c.

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

Referenced by ProcArrayApplyRecoveryInfo().

4402 {
4403  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4405  LWLockRelease(ProcArrayLock);
4406 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
static void KnownAssignedXidsRemovePreceding(TransactionId xid)
Definition: procarray.c:4838
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206

◆ ExpireTreeKnownAssignedTransactionIds()

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

Definition at line 4363 of file procarray.c.

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

Referenced by xact_redo_abort(), and xact_redo_commit().

4365 {
4367 
4368  /*
4369  * Uses same locking as transaction commit
4370  */
4371  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4372 
4373  KnownAssignedXidsRemoveTree(xid, nsubxids, subxids);
4374 
4375  /* As in ProcArrayEndTransaction, advance latestCompletedXid */
4377 
4378  /* ... and xactCompletionCount */
4380 
4381  LWLockRelease(ProcArrayLock);
4382 }
static void MaintainLatestCompletedXidRecovery(TransactionId latestXid)
Definition: procarray.c:935
uint64 xactCompletionCount
Definition: transam.h:241
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
VariableCache ShmemVariableCache
Definition: varsup.c:34
static void KnownAssignedXidsRemoveTree(TransactionId xid, int nsubxids, TransactionId *subxids)
Definition: procarray.c:4816
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
HotStandbyState standbyState
Definition: xlog.c:209

◆ FullXidRelativeTo()

static FullTransactionId FullXidRelativeTo ( FullTransactionId  rel,
TransactionId  xid 
)
inlinestatic

Definition at line 4210 of file procarray.c.

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

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

4211 {
4212  TransactionId rel_xid = XidFromFullTransactionId(rel);
4213 
4215  Assert(TransactionIdIsValid(rel_xid));
4216 
4217  /* not guaranteed to find issues, but likely to catch mistakes */
4219 
4221  + (int32) (xid - rel_xid));
4222 }
uint32 TransactionId
Definition: c.h:587
static FullTransactionId FullTransactionIdFromU64(uint64 value)
Definition: transam.h:81
signed int int32
Definition: c.h:429
#define XidFromFullTransactionId(x)
Definition: transam.h:48
#define AssertTransactionIdInAllowableRange(xid)
Definition: transam.h:294
#define Assert(condition)
Definition: c.h:804
#define U64FromFullTransactionId(x)
Definition: transam.h:49
#define TransactionIdIsValid(xid)
Definition: transam.h:41

◆ GetConflictingVirtualXIDs()

VirtualTransactionId* GetConflictingVirtualXIDs ( TransactionId  limitXmin,
Oid  dbOid 
)

Definition at line 3278 of file procarray.c.

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

Referenced by ResolveRecoveryConflictWithSnapshot(), and ResolveRecoveryConflictWithTablespace().

3279 {
3280  static VirtualTransactionId *vxids;
3281  ProcArrayStruct *arrayP = procArray;
3282  int count = 0;
3283  int index;
3284 
3285  /*
3286  * If first time through, get workspace to remember main XIDs in. We
3287  * malloc it permanently to avoid repeated palloc/pfree overhead. Allow
3288  * result space, remembering room for a terminator.
3289  */
3290  if (vxids == NULL)
3291  {
3292  vxids = (VirtualTransactionId *)
3293  malloc(sizeof(VirtualTransactionId) * (arrayP->maxProcs + 1));
3294  if (vxids == NULL)
3295  ereport(ERROR,
3296  (errcode(ERRCODE_OUT_OF_MEMORY),
3297  errmsg("out of memory")));
3298  }
3299 
3300  LWLockAcquire(ProcArrayLock, LW_SHARED);
3301 
3302  for (index = 0; index < arrayP->numProcs; index++)
3303  {
3304  int pgprocno = arrayP->pgprocnos[index];
3305  PGPROC *proc = &allProcs[pgprocno];
3306 
3307  /* Exclude prepared transactions */
3308  if (proc->pid == 0)
3309  continue;
3310 
3311  if (!OidIsValid(dbOid) ||
3312  proc->databaseId == dbOid)
3313  {
3314  /* Fetch xmin just once - can't change on us, but good coding */
3315  TransactionId pxmin = UINT32_ACCESS_ONCE(proc->xmin);
3316 
3317  /*
3318  * We ignore an invalid pxmin because this means that backend has
3319  * no snapshot currently. We hold a Share lock to avoid contention
3320  * with users taking snapshots. That is not a problem because the
3321  * current xmin is always at least one higher than the latest
3322  * removed xid, so any new snapshot would never conflict with the
3323  * test here.
3324  */
3325  if (!TransactionIdIsValid(limitXmin) ||
3326  (TransactionIdIsValid(pxmin) && !TransactionIdFollows(pxmin, limitXmin)))
3327  {
3328  VirtualTransactionId vxid;
3329 
3330  GET_VXID_FROM_PGPROC(vxid, *proc);
3331  if (VirtualTransactionIdIsValid(vxid))
3332  vxids[count++] = vxid;
3333  }
3334  }
3335  }
3336 
3337  LWLockRelease(ProcArrayLock);
3338 
3339  /* add the terminator */
3340  vxids[count].backendId = InvalidBackendId;
3342 
3343  return vxids;
3344 }
#define GET_VXID_FROM_PGPROC(vxid, proc)
Definition: lock.h:81
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:334
uint32 TransactionId
Definition: c.h:587
#define UINT32_ACCESS_ONCE(var)
Definition: procarray.c:69
int errcode(int sqlerrcode)
Definition: elog.c:694
LocalTransactionId localTransactionId
Definition: lock.h:66
#define OidIsValid(objectId)
Definition: c.h:710
Definition: type.h:89
#define malloc(a)
Definition: header.h:50
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
#define ERROR
Definition: elog.h:45
TransactionId xmin
Definition: proc.h:138
static PGPROC * allProcs
Definition: procarray.c:252
Oid databaseId
Definition: proc.h:154
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define VirtualTransactionIdIsValid(vxid)
Definition: lock.h:71
#define InvalidBackendId
Definition: backendid.h:23
#define ereport(elevel,...)
Definition: elog.h:155
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
BackendId backendId
Definition: lock.h:65
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
int errmsg(const char *fmt,...)
Definition: elog.c:905
#define InvalidLocalTransactionId
Definition: lock.h:69
#define TransactionIdIsValid(xid)
Definition: transam.h:41
Definition: proc.h:121
int pid
Definition: proc.h:146

◆ GetCurrentVirtualXIDs()

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

Definition at line 3190 of file procarray.c.

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

Referenced by WaitForOlderSnapshots().

3193 {
3194  VirtualTransactionId *vxids;
3195  ProcArrayStruct *arrayP = procArray;
3196  int count = 0;
3197  int index;
3198 
3199  /* allocate what's certainly enough result space */
3200  vxids = (VirtualTransactionId *)
3201  palloc(sizeof(VirtualTransactionId) * arrayP->maxProcs);
3202 
3203  LWLockAcquire(ProcArrayLock, LW_SHARED);
3204 
3205  for (index = 0; index < arrayP->numProcs; index++)
3206  {
3207  int pgprocno = arrayP->pgprocnos[index];
3208  PGPROC *proc = &allProcs[pgprocno];
3209  uint8 statusFlags = ProcGlobal->statusFlags[index];
3210 
3211  if (proc == MyProc)
3212  continue;
3213 
3214  if (excludeVacuum & statusFlags)
3215  continue;
3216 
3217  if (allDbs || proc->databaseId == MyDatabaseId)
3218  {
3219  /* Fetch xmin just once - might change on us */
3220  TransactionId pxmin = UINT32_ACCESS_ONCE(proc->xmin);
3221 
3222  if (excludeXmin0 && !TransactionIdIsValid(pxmin))
3223  continue;
3224 
3225  /*
3226  * InvalidTransactionId precedes all other XIDs, so a proc that
3227  * hasn't set xmin yet will not be rejected by this test.
3228  */
3229  if (!TransactionIdIsValid(limitXmin) ||
3230  TransactionIdPrecedesOrEquals(pxmin, limitXmin))
3231  {
3232  VirtualTransactionId vxid;
3233 
3234  GET_VXID_FROM_PGPROC(vxid, *proc);
3235  if (VirtualTransactionIdIsValid(vxid))
3236  vxids[count++] = vxid;
3237  }
3238  }
3239  }
3240 
3241  LWLockRelease(ProcArrayLock);
3242 
3243  *nvxids = count;
3244  return vxids;
3245 }
#define GET_VXID_FROM_PGPROC(vxid, proc)
Definition: lock.h:81
uint32 TransactionId
Definition: c.h:587
PGPROC * MyProc
Definition: proc.c:68
#define UINT32_ACCESS_ONCE(var)
Definition: procarray.c:69
unsigned char uint8
Definition: c.h:439
PROC_HDR * ProcGlobal
Definition: proc.c:80
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:319
TransactionId xmin
Definition: proc.h:138
static PGPROC * allProcs
Definition: procarray.c:252
Oid databaseId
Definition: proc.h:154
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define VirtualTransactionIdIsValid(vxid)
Definition: lock.h:71
Oid MyDatabaseId
Definition: globals.c:86
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
void * palloc(Size size)
Definition: mcxt.c:950
uint8 * statusFlags
Definition: proc.h:333
#define TransactionIdIsValid(xid)
Definition: transam.h:41
Definition: proc.h:121

◆ GetMaxSnapshotSubxidCount()

int GetMaxSnapshotSubxidCount ( void  )

Definition at line 2009 of file procarray.c.

References TOTAL_MAX_CACHED_SUBXIDS.

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

2010 {
2011  return TOTAL_MAX_CACHED_SUBXIDS;
2012 }
#define TOTAL_MAX_CACHED_SUBXIDS

◆ GetMaxSnapshotXidCount()

int GetMaxSnapshotXidCount ( void  )

Definition at line 1998 of file procarray.c.

References ProcArrayStruct::maxProcs.

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

1999 {
2000  return procArray->maxProcs;
2001 }
static ProcArrayStruct * procArray
Definition: procarray.c:250

◆ GetOldestActiveTransactionId()

TransactionId GetOldestActiveTransactionId ( void  )

Definition at line 2811 of file procarray.c.

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

Referenced by CreateCheckPoint().

2812 {
2813  ProcArrayStruct *arrayP = procArray;
2814  TransactionId *other_xids = ProcGlobal->xids;
2815  TransactionId oldestRunningXid;
2816  int index;
2817 
2819 
2820  /*
2821  * Read nextXid, as the upper bound of what's still active.
2822  *
2823  * Reading a TransactionId is atomic, but we must grab the lock to make
2824  * sure that all XIDs < nextXid are already present in the proc array (or
2825  * have already completed), when we spin over it.
2826  */
2827  LWLockAcquire(XidGenLock, LW_SHARED);
2829  LWLockRelease(XidGenLock);
2830 
2831  /*
2832  * Spin over procArray collecting all xids and subxids.
2833  */
2834  LWLockAcquire(ProcArrayLock, LW_SHARED);
2835  for (index = 0; index < arrayP->numProcs; index++)
2836  {
2837  TransactionId xid;
2838 
2839  /* Fetch xid just once - see GetNewTransactionId */
2840  xid = UINT32_ACCESS_ONCE(other_xids[index]);
2841 
2842  if (!TransactionIdIsNormal(xid))
2843  continue;
2844 
2845  if (TransactionIdPrecedes(xid, oldestRunningXid))
2846  oldestRunningXid = xid;
2847 
2848  /*
2849  * Top-level XID of a transaction is always less than any of its
2850  * subxids, so we don't need to check if any of the subxids are
2851  * smaller than oldestRunningXid
2852  */
2853  }
2854  LWLockRelease(ProcArrayLock);
2855 
2856  return oldestRunningXid;
2857 }
uint32 TransactionId
Definition: c.h:587
#define UINT32_ACCESS_ONCE(var)
Definition: procarray.c:69
PROC_HDR * ProcGlobal
Definition: proc.c:80
bool RecoveryInProgress(void)
Definition: xlog.c:8132
FullTransactionId nextXid
Definition: transam.h:213
#define XidFromFullTransactionId(x)
Definition: transam.h:48
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
VariableCache ShmemVariableCache
Definition: varsup.c:34
TransactionId * xids
Definition: proc.h:321
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
#define TransactionIdIsNormal(xid)
Definition: transam.h:42

◆ GetOldestNonRemovableTransactionId()

TransactionId GetOldestNonRemovableTransactionId ( Relation  rel)

Definition at line 1939 of file procarray.c.

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

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

1940 {
1941  ComputeXidHorizonsResult horizons;
1942 
1943  ComputeXidHorizons(&horizons);
1944 
1945  /* select horizon appropriate for relation */
1946  if (rel == NULL || rel->rd_rel->relisshared)
1947  return horizons.shared_oldest_nonremovable;
1949  return horizons.catalog_oldest_nonremovable;
1950  else if (RELATION_IS_LOCAL(rel))
1951  return horizons.temp_oldest_nonremovable;
1952  else
1953  return horizons.data_oldest_nonremovable;
1954 }
static void ComputeXidHorizons(ComputeXidHorizonsResult *h)
Definition: procarray.c:1662
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:584
Form_pg_class rd_rel
Definition: rel.h:110
TransactionId catalog_oldest_nonremovable
Definition: procarray.c:233
TransactionId shared_oldest_nonremovable
Definition: procarray.c:216
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:620
TransactionId temp_oldest_nonremovable
Definition: procarray.c:245
TransactionId data_oldest_nonremovable
Definition: procarray.c:239

◆ GetOldestSafeDecodingTransactionId()

TransactionId GetOldestSafeDecodingTransactionId ( bool  catalogOnly)

Definition at line 2876 of file procarray.c.

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

Referenced by CreateInitDecodingContext(), and SnapBuildInitialSnapshot().

2877 {
2878  ProcArrayStruct *arrayP = procArray;
2879  TransactionId oldestSafeXid;
2880  int index;
2881  bool recovery_in_progress = RecoveryInProgress();
2882 
2883  Assert(LWLockHeldByMe(ProcArrayLock));
2884 
2885  /*
2886  * Acquire XidGenLock, so no transactions can acquire an xid while we're
2887  * running. If no transaction with xid were running concurrently a new xid
2888  * could influence the RecentXmin et al.
2889  *
2890  * We initialize the computation to nextXid since that's guaranteed to be
2891  * a safe, albeit pessimal, value.
2892  */
2893  LWLockAcquire(XidGenLock, LW_SHARED);
2895 
2896  /*
2897  * If there's already a slot pegging the xmin horizon, we can start with
2898  * that value, it's guaranteed to be safe since it's computed by this
2899  * routine initially and has been enforced since. We can always use the
2900  * slot's general xmin horizon, but the catalog horizon is only usable
2901  * when only catalog data is going to be looked at.
2902  */
2905  oldestSafeXid))
2906  oldestSafeXid = procArray->replication_slot_xmin;
2907 
2908  if (catalogOnly &&
2911  oldestSafeXid))
2912  oldestSafeXid = procArray->replication_slot_catalog_xmin;
2913 
2914  /*
2915  * If we're not in recovery, we walk over the procarray and collect the
2916  * lowest xid. Since we're called with ProcArrayLock held and have
2917  * acquired XidGenLock, no entries can vanish concurrently, since
2918  * ProcGlobal->xids[i] is only set with XidGenLock held and only cleared
2919  * with ProcArrayLock held.
2920  *
2921  * In recovery we can't lower the safe value besides what we've computed
2922  * above, so we'll have to wait a bit longer there. We unfortunately can
2923  * *not* use KnownAssignedXidsGetOldestXmin() since the KnownAssignedXids
2924  * machinery can miss values and return an older value than is safe.
2925  */
2926  if (!recovery_in_progress)
2927  {
2928  TransactionId *other_xids = ProcGlobal->xids;
2929 
2930  /*
2931  * Spin over procArray collecting min(ProcGlobal->xids[i])
2932  */
2933  for (index = 0; index < arrayP->numProcs; index++)
2934  {
2935  TransactionId xid;
2936 
2937  /* Fetch xid just once - see GetNewTransactionId */
2938  xid = UINT32_ACCESS_ONCE(other_xids[index]);
2939 
2940  if (!TransactionIdIsNormal(xid))
2941  continue;
2942 
2943  if (TransactionIdPrecedes(xid, oldestSafeXid))
2944  oldestSafeXid = xid;
2945  }
2946  }
2947 
2948  LWLockRelease(XidGenLock);
2949 
2950  return oldestSafeXid;
2951 }
uint32 TransactionId
Definition: c.h:587
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1924
#define UINT32_ACCESS_ONCE(var)
Definition: procarray.c:69
TransactionId replication_slot_catalog_xmin
Definition: procarray.c:98
PROC_HDR * ProcGlobal
Definition: proc.c:80
bool RecoveryInProgress(void)
Definition: xlog.c:8132
FullTransactionId nextXid
Definition: transam.h:213
#define XidFromFullTransactionId(x)
Definition: transam.h:48
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
VariableCache ShmemVariableCache
Definition: varsup.c:34
TransactionId * xids
Definition: proc.h:321
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
static ProcArrayStruct * procArray
Definition: procarray.c:250
TransactionId replication_slot_xmin
Definition: procarray.c:96
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define TransactionIdIsNormal(xid)
Definition: transam.h:42

◆ GetOldestTransactionIdConsideredRunning()

TransactionId GetOldestTransactionIdConsideredRunning ( void  )

Definition at line 1963 of file procarray.c.

References ComputeXidHorizons(), and ComputeXidHorizonsResult::oldest_considered_running.

Referenced by CreateCheckPoint(), and CreateRestartPoint().

1964 {
1965  ComputeXidHorizonsResult horizons;
1966 
1967  ComputeXidHorizons(&horizons);
1968 
1969  return horizons.oldest_considered_running;
1970 }
TransactionId oldest_considered_running
Definition: procarray.c:207
static void ComputeXidHorizons(ComputeXidHorizonsResult *h)
Definition: procarray.c:1662

◆ GetReplicationHorizons()

void GetReplicationHorizons ( TransactionId xmin,
TransactionId catalog_xmin 
)

Definition at line 1976 of file procarray.c.

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

Referenced by XLogWalRcvSendHSFeedback().

1977 {
1978  ComputeXidHorizonsResult horizons;
1979 
1980  ComputeXidHorizons(&horizons);
1981 
1982  /*
1983  * Don't want to use shared_oldest_nonremovable here, as that contains the
1984  * effect of replication slot's catalog_xmin. We want to send a separate
1985  * feedback for the catalog horizon, so the primary can remove data table
1986  * contents more aggressively.
1987  */
1988  *xmin = horizons.shared_oldest_nonremovable_raw;
1989  *catalog_xmin = horizons.slot_catalog_xmin;
1990 }
static void ComputeXidHorizons(ComputeXidHorizonsResult *h)
Definition: procarray.c:1662
TransactionId shared_oldest_nonremovable_raw
Definition: procarray.c:227
TransactionId slot_catalog_xmin
Definition: procarray.c:194

◆ GetRunningTransactionData()

RunningTransactions GetRunningTransactionData ( void  )

Definition at line 2636 of file procarray.c.

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

Referenced by LogStandbySnapshot().

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

◆ GetSnapshotData()

Snapshot GetSnapshotData ( Snapshot  snapshot)

Definition at line 2135 of file procarray.c.

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

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

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

◆ GetSnapshotDataInitOldSnapshot()

static void GetSnapshotDataInitOldSnapshot ( Snapshot  snapshot)
static

Definition at line 2018 of file procarray.c.

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

Referenced by GetSnapshotData(), and GetSnapshotDataReuse().

2019 {
2021  {
2022  /*
2023  * If not using "snapshot too old" feature, fill related fields with
2024  * dummy values that don't require any locking.
2025  */
2026  snapshot->lsn = InvalidXLogRecPtr;
2027  snapshot->whenTaken = 0;
2028  }
2029  else
2030  {
2031  /*
2032  * Capture the current time and WAL stream location in case this
2033  * snapshot becomes old enough to need to fall back on the special
2034  * "old snapshot" logic.
2035  */
2036  snapshot->lsn = GetXLogInsertRecPtr();
2037  snapshot->whenTaken = GetSnapshotCurrentTimestamp();
2038  MaintainOldSnapshotTimeMapping(snapshot->whenTaken, snapshot->xmin);
2039  }
2040 }
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28
static bool OldSnapshotThresholdActive(void)
Definition: snapmgr.h:102
XLogRecPtr lsn
Definition: snapshot.h:209
TimestampTz GetSnapshotCurrentTimestamp(void)
Definition: snapmgr.c:1635
XLogRecPtr GetXLogInsertRecPtr(void)
Definition: xlog.c:11615
TransactionId xmin
Definition: snapshot.h:157
TimestampTz whenTaken
Definition: snapshot.h:208
void MaintainOldSnapshotTimeMapping(TimestampTz whenTaken, TransactionId xmin)
Definition: snapmgr.c:1858

◆ GetSnapshotDataReuse()

static bool GetSnapshotDataReuse ( Snapshot  snapshot)
static

Definition at line 2052 of file procarray.c.

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

Referenced by GetSnapshotData().

2053 {
2054  uint64 curXactCompletionCount;
2055 
2056  Assert(LWLockHeldByMe(ProcArrayLock));
2057 
2058  if (unlikely(snapshot->snapXactCompletionCount == 0))
2059  return false;
2060 
2061  curXactCompletionCount = ShmemVariableCache->xactCompletionCount;
2062  if (curXactCompletionCount != snapshot->snapXactCompletionCount)
2063  return false;
2064 
2065  /*
2066  * If the current xactCompletionCount is still the same as it was at the
2067  * time the snapshot was built, we can be sure that rebuilding the
2068  * contents of the snapshot the hard way would result in the same snapshot
2069  * contents:
2070  *
2071  * As explained in transam/README, the set of xids considered running by
2072  * GetSnapshotData() cannot change while ProcArrayLock is held. Snapshot
2073  * contents only depend on transactions with xids and xactCompletionCount
2074  * is incremented whenever a transaction with an xid finishes (while
2075  * holding ProcArrayLock) exclusively). Thus the xactCompletionCount check
2076  * ensures we would detect if the snapshot would have changed.
2077  *
2078  * As the snapshot contents are the same as it was before, it is safe
2079  * to re-enter the snapshot's xmin into the PGPROC array. None of the rows
2080  * visible under the snapshot could already have been removed (that'd
2081  * require the set of running transactions to change) and it fulfills the
2082  * requirement that concurrent GetSnapshotData() calls yield the same
2083  * xmin.
2084  */
2086  MyProc->xmin = TransactionXmin = snapshot->xmin;
2087 
2088  RecentXmin = snapshot->xmin;
2090 
2091  snapshot->curcid = GetCurrentCommandId(false);
2092  snapshot->active_count = 0;
2093  snapshot->regd_count = 0;
2094  snapshot->copied = false;
2095 
2097 
2098  return true;
2099 }
uint64 snapXactCompletionCount
Definition: snapshot.h:216
bool copied
Definition: snapshot.h:185
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1924
PGPROC * MyProc
Definition: proc.c:68
TransactionId RecentXmin
Definition: snapmgr.c:113
uint64 xactCompletionCount
Definition: transam.h:241
uint32 regd_count
Definition: snapshot.h:205
TransactionId TransactionXmin
Definition: snapmgr.c:112
static void GetSnapshotDataInitOldSnapshot(Snapshot snapshot)
Definition: procarray.c:2018
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:319
TransactionId xmin
Definition: proc.h:138
VariableCache ShmemVariableCache
Definition: varsup.c:34
TransactionId xmin
Definition: snapshot.h:157
CommandId curcid
Definition: snapshot.h:187
#define Assert(condition)
Definition: c.h:804
#define unlikely(x)
Definition: c.h:273
CommandId GetCurrentCommandId(bool used)
Definition: xact.c:761
#define TransactionIdIsValid(xid)
Definition: transam.h:41
uint32 active_count
Definition: snapshot.h:204

◆ GetVirtualXIDsDelayingChkpt()

VirtualTransactionId* GetVirtualXIDsDelayingChkpt ( int *  nvxids)

Definition at line 2972 of file procarray.c.

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

Referenced by CreateCheckPoint().

2973 {
2974  VirtualTransactionId *vxids;
2975  ProcArrayStruct *arrayP = procArray;
2976  int count = 0;
2977  int index;
2978 
2979  /* allocate what's certainly enough result space */
2980  vxids = (VirtualTransactionId *)
2981  palloc(sizeof(VirtualTransactionId) * arrayP->maxProcs);
2982 
2983  LWLockAcquire(ProcArrayLock, LW_SHARED);
2984 
2985  for (index = 0; index < arrayP->numProcs; index++)
2986  {
2987  int pgprocno = arrayP->pgprocnos[index];
2988  PGPROC *proc = &allProcs[pgprocno];
2989 
2990  if (proc->delayChkpt)
2991  {
2992  VirtualTransactionId vxid;
2993 
2994  GET_VXID_FROM_PGPROC(vxid, *proc);
2995  if (VirtualTransactionIdIsValid(vxid))
2996  vxids[count++] = vxid;
2997  }
2998  }
2999 
3000  LWLockRelease(ProcArrayLock);
3001 
3002  *nvxids = count;
3003  return vxids;
3004 }
#define GET_VXID_FROM_PGPROC(vxid, proc)
Definition: lock.h:81
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
bool delayChkpt
Definition: proc.h:187
static PGPROC * allProcs
Definition: procarray.c:252
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define VirtualTransactionIdIsValid(vxid)
Definition: lock.h:71
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
void * palloc(Size size)
Definition: mcxt.c:950
Definition: proc.h:121

◆ GlobalVisCheckRemovableFullXid()

bool GlobalVisCheckRemovableFullXid ( Relation  rel,
FullTransactionId  fxid 
)

Definition at line 4175 of file procarray.c.

References GlobalVisTestFor(), and GlobalVisTestIsRemovableFullXid().

Referenced by BTPageIsRecyclable(), and gistPageRecyclable().

4176 {
4178 
4179  state = GlobalVisTestFor(rel);
4180 
4181  return GlobalVisTestIsRemovableFullXid(state, fxid);
4182 }
bool GlobalVisTestIsRemovableFullXid(GlobalVisState *state, FullTransactionId fxid)
Definition: procarray.c:4081
GlobalVisState * GlobalVisTestFor(Relation rel)
Definition: procarray.c:3955
Definition: regguts.h:317

◆ GlobalVisCheckRemovableXid()

bool GlobalVisCheckRemovableXid ( Relation  rel,
TransactionId  xid 
)

Definition at line 4189 of file procarray.c.

References GlobalVisTestFor(), and GlobalVisTestIsRemovableXid().

Referenced by GinPageIsRecyclable().

4190 {
4192 
4193  state = GlobalVisTestFor(rel);
4194 
4195  return GlobalVisTestIsRemovableXid(state, xid);
4196 }
bool GlobalVisTestIsRemovableXid(GlobalVisState *state, TransactionId xid)
Definition: procarray.c:4123
GlobalVisState * GlobalVisTestFor(Relation rel)
Definition: procarray.c:3955
Definition: regguts.h:317

◆ GlobalVisTestFor()

GlobalVisState* GlobalVisTestFor ( Relation  rel)

Definition at line 3955 of file procarray.c.

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

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

3956 {
3957  bool need_shared;
3958  bool need_catalog;
3960 
3961  /* XXX: we should assert that a snapshot is pushed or registered */
3962  Assert(RecentXmin);
3963 
3964  if (!rel)
3965  need_shared = need_catalog = true;
3966  else
3967  {
3968  /*
3969  * Other kinds currently don't contain xids, nor always the necessary
3970  * logical decoding markers.
3971  */
3972  Assert(rel->rd_rel->relkind == RELKIND_RELATION ||
3973  rel->rd_rel->relkind == RELKIND_MATVIEW ||
3974  rel->rd_rel->relkind == RELKIND_TOASTVALUE);
3975 
3976  need_shared = rel->rd_rel->relisshared || RecoveryInProgress();
3977  need_catalog = IsCatalogRelation(rel) || RelationIsAccessibleInLogicalDecoding(rel);
3978  }
3979 
3980  if (need_shared)
3981  state = &GlobalVisSharedRels;
3982  else if (need_catalog)
3983  state = &GlobalVisCatalogRels;
3984  else if (RELATION_IS_LOCAL(rel))
3985  state = &GlobalVisTempRels;
3986  else
3987  state = &GlobalVisDataRels;
3988 
3991 
3992  return state;
3993 }
bool IsCatalogRelation(Relation relation)
Definition: catalog.c:96
#define FullTransactionIdIsValid(x)
Definition: transam.h:55
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:584
TransactionId RecentXmin
Definition: snapmgr.c:113
Form_pg_class rd_rel
Definition: rel.h:110
bool RecoveryInProgress(void)
Definition: xlog.c:8132
FullTransactionId definitely_needed
Definition: procarray.c:172
static GlobalVisState GlobalVisSharedRels
Definition: procarray.c:273
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:620
#define Assert(condition)
Definition: c.h:804
Definition: regguts.h:317
FullTransactionId maybe_needed
Definition: procarray.c:175
static GlobalVisState GlobalVisTempRels
Definition: procarray.c:276
static GlobalVisState GlobalVisCatalogRels
Definition: procarray.c:274
static GlobalVisState GlobalVisDataRels
Definition: procarray.c:275

◆ GlobalVisTestIsRemovableFullXid()

bool GlobalVisTestIsRemovableFullXid ( GlobalVisState state,
FullTransactionId  fxid 
)

Definition at line 4081 of file procarray.c.

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

Referenced by GlobalVisCheckRemovableFullXid(), and GlobalVisTestIsRemovableXid().

4083 {
4084  /*
4085  * If fxid is older than maybe_needed bound, it definitely is visible to
4086  * everyone.
4087  */
4088  if (FullTransactionIdPrecedes(fxid, state->maybe_needed))
4089  return true;
4090 
4091  /*
4092  * If fxid is >= definitely_needed bound, it is very likely to still be
4093  * considered running.
4094  */
4096  return false;
4097 
4098  /*
4099  * fxid is between maybe_needed and definitely_needed, i.e. there might or
4100  * might not exist a snapshot considering fxid running. If it makes sense,
4101  * update boundaries and recheck.
4102  */
4103  if (GlobalVisTestShouldUpdate(state))
4104  {
4105  GlobalVisUpdate();
4106 
4108 
4109  return FullTransactionIdPrecedes(fxid, state->maybe_needed);
4110  }
4111  else
4112  return false;
4113 }
FullTransactionId definitely_needed
Definition: procarray.c:172
static bool GlobalVisTestShouldUpdate(GlobalVisState *state)
Definition: procarray.c:4006
#define Assert(condition)
Definition: c.h:804
#define FullTransactionIdFollowsOrEquals(a, b)
Definition: transam.h:54
FullTransactionId maybe_needed
Definition: procarray.c:175
#define FullTransactionIdPrecedes(a, b)
Definition: transam.h:51
static void GlobalVisUpdate(void)
Definition: procarray.c:4064

◆ GlobalVisTestIsRemovableXid()

bool GlobalVisTestIsRemovableXid ( GlobalVisState state,
TransactionId  xid 
)

Definition at line 4123 of file procarray.c.

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

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

4124 {
4125  FullTransactionId fxid;
4126 
4127  /*
4128  * Convert 32 bit argument to FullTransactionId. We can do so safely
4129  * because we know the xid has to, at the very least, be between
4130  * [oldestXid, nextFullXid), i.e. within 2 billion of xid. To avoid taking
4131  * a lock to determine either, we can just compare with
4132  * state->definitely_needed, which was based on those value at the time
4133  * the current snapshot was built.
4134  */
4135  fxid = FullXidRelativeTo(state->definitely_needed, xid);
4136 
4137  return GlobalVisTestIsRemovableFullXid(state, fxid);
4138 }
static FullTransactionId FullXidRelativeTo(FullTransactionId rel, TransactionId xid)
Definition: procarray.c:4210
bool GlobalVisTestIsRemovableFullXid(GlobalVisState *state, FullTransactionId fxid)
Definition: procarray.c:4081
FullTransactionId definitely_needed
Definition: procarray.c:172

◆ GlobalVisTestNonRemovableFullHorizon()

FullTransactionId GlobalVisTestNonRemovableFullHorizon ( GlobalVisState state)

Definition at line 4150 of file procarray.c.

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

Referenced by GlobalVisTestNonRemovableHorizon().

4151 {
4152  /* acquire accurate horizon if not already done */
4153  if (GlobalVisTestShouldUpdate(state))
4154  GlobalVisUpdate();
4155 
4156  return state->maybe_needed;
4157 }
static bool GlobalVisTestShouldUpdate(GlobalVisState *state)
Definition: procarray.c:4006
FullTransactionId maybe_needed
Definition: procarray.c:175
static void GlobalVisUpdate(void)
Definition: procarray.c:4064

◆ GlobalVisTestNonRemovableHorizon()

TransactionId GlobalVisTestNonRemovableHorizon ( GlobalVisState state)

Definition at line 4161 of file procarray.c.

References GlobalVisTestNonRemovableFullHorizon(), and XidFromFullTransactionId.

Referenced by heap_page_prune_opt(), and heap_prune_satisfies_vacuum().

4162 {
4163  FullTransactionId cutoff;
4164 
4165  cutoff = GlobalVisTestNonRemovableFullHorizon(state);
4166 
4167  return XidFromFullTransactionId(cutoff);
4168 }
#define XidFromFullTransactionId(x)
Definition: transam.h:48
FullTransactionId GlobalVisTestNonRemovableFullHorizon(GlobalVisState *state)
Definition: procarray.c:4150

◆ GlobalVisTestShouldUpdate()

static bool GlobalVisTestShouldUpdate ( GlobalVisState state)
static

Definition at line 4006 of file procarray.c.

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

Referenced by GlobalVisTestIsRemovableFullXid(), and GlobalVisTestNonRemovableFullHorizon().

4007 {
4008  /* hasn't been updated yet */
4010  return true;
4011 
4012  /*
4013  * If the maybe_needed/definitely_needed boundaries are the same, it's
4014  * unlikely to be beneficial to refresh boundaries.
4015  */
4017  state->definitely_needed))
4018  return false;
4019 
4020  /* does the last snapshot built have a different xmin? */
4022 }
TransactionId RecentXmin
Definition: snapmgr.c:113
FullTransactionId definitely_needed
Definition: procarray.c:172
static TransactionId ComputeXidHorizonsResultLastXmin
Definition: procarray.c:283
#define FullTransactionIdFollowsOrEquals(a, b)
Definition: transam.h:54
FullTransactionId maybe_needed
Definition: procarray.c:175
#define TransactionIdIsValid(xid)
Definition: transam.h:41

◆ GlobalVisUpdate()

static void GlobalVisUpdate ( void  )
static

Definition at line 4064 of file procarray.c.

References ComputeXidHorizons().

Referenced by GlobalVisTestIsRemovableFullXid(), and GlobalVisTestNonRemovableFullHorizon().

4065 {
4066  ComputeXidHorizonsResult horizons;
4067 
4068  /* updates the horizons as a side-effect */
4069  ComputeXidHorizons(&horizons);
4070 }
static void ComputeXidHorizons(ComputeXidHorizonsResult *h)
Definition: procarray.c:1662

◆ GlobalVisUpdateApply()

static void GlobalVisUpdateApply ( ComputeXidHorizonsResult horizons)
static

Definition at line 4025 of file procarray.c.

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

Referenced by ComputeXidHorizons().

4026 {
4029  horizons->shared_oldest_nonremovable);
4032  horizons->catalog_oldest_nonremovable);
4035  horizons->data_oldest_nonremovable);
4038  horizons->temp_oldest_nonremovable);
4039 
4040  /*
4041  * In longer running transactions it's possible that transactions we
4042  * previously needed to treat as running aren't around anymore. So update
4043  * definitely_needed to not be earlier than maybe_needed.
4044  */
4055 
4057 }
FullTransactionId latest_completed
Definition: procarray.c:187
static FullTransactionId FullXidRelativeTo(FullTransactionId rel, TransactionId xid)
Definition: procarray.c:4210
TransactionId RecentXmin
Definition: snapmgr.c:113
TransactionId catalog_oldest_nonremovable
Definition: procarray.c:233
FullTransactionId definitely_needed
Definition: procarray.c:172
static GlobalVisState GlobalVisSharedRels
Definition: procarray.c:273
TransactionId shared_oldest_nonremovable
Definition: procarray.c:216
static TransactionId ComputeXidHorizonsResultLastXmin
Definition: procarray.c:283
TransactionId temp_oldest_nonremovable
Definition: procarray.c:245
FullTransactionId maybe_needed
Definition: procarray.c:175
static FullTransactionId FullTransactionIdNewer(FullTransactionId a, FullTransactionId b)
Definition: transam.h:353
static GlobalVisState GlobalVisTempRels
Definition: procarray.c:276
TransactionId data_oldest_nonremovable
Definition: procarray.c:239
static GlobalVisState GlobalVisCatalogRels
Definition: procarray.c:274
static GlobalVisState GlobalVisDataRels
Definition: procarray.c:275

◆ HaveVirtualXIDsDelayingChkpt()

bool HaveVirtualXIDsDelayingChkpt ( VirtualTransactionId vxids,
int  nvxids 
)

Definition at line 3016 of file procarray.c.

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

Referenced by CreateCheckPoint().

3017 {
3018  bool result = false;
3019  ProcArrayStruct *arrayP = procArray;
3020  int index;
3021 
3022  LWLockAcquire(ProcArrayLock, LW_SHARED);
3023 
3024  for (index = 0; index < arrayP->numProcs; index++)
3025  {
3026  int pgprocno = arrayP->pgprocnos[index];
3027  PGPROC *proc = &allProcs[pgprocno];
3028  VirtualTransactionId vxid;
3029 
3030  GET_VXID_FROM_PGPROC(vxid, *proc);
3031 
3032  if (proc->delayChkpt && VirtualTransactionIdIsValid(vxid))
3033  {
3034  int i;
3035 
3036  for (i = 0; i < nvxids; i++)
3037  {
3038  if (VirtualTransactionIdEquals(vxid, vxids[i]))
3039  {
3040  result = true;
3041  break;
3042  }
3043  }
3044  if (result)
3045  break;
3046  }
3047  }
3048 
3049  LWLockRelease(ProcArrayLock);
3050 
3051  return result;
3052 }
#define GET_VXID_FROM_PGPROC(vxid, proc)
Definition: lock.h:81
Definition: type.h:89
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
#define VirtualTransactionIdEquals(vxid1, vxid2)
Definition: lock.h:75
bool delayChkpt
Definition: proc.h:187
static PGPROC * allProcs
Definition: procarray.c:252
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define VirtualTransactionIdIsValid(vxid)
Definition: lock.h:71
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
int i
Definition: proc.h:121

◆ IsBackendPid()

bool IsBackendPid ( int  pid)

Definition at line 3157 of file procarray.c.

References BackendPidGetProc().

Referenced by pg_stat_get_subscription().

3158 {
3159  return (BackendPidGetProc(pid) != NULL);
3160 }
PGPROC * BackendPidGetProc(int pid)
Definition: procarray.c:3062

◆ KnownAssignedXidExists()

static bool KnownAssignedXidExists ( TransactionId  xid)
static

Definition at line 4777 of file procarray.c.

References Assert, KnownAssignedXidsSearch(), and TransactionIdIsValid.

Referenced by TransactionIdIsInProgress().

4778 {
4780 
4781  return KnownAssignedXidsSearch(xid, false);
4782 }
#define Assert(condition)
Definition: c.h:804
static bool KnownAssignedXidsSearch(TransactionId xid, bool remove)
Definition: procarray.c:4684
#define TransactionIdIsValid(xid)
Definition: transam.h:41

◆ KnownAssignedXidsAdd()

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

Definition at line 4566 of file procarray.c.

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

Referenced by ProcArrayApplyRecoveryInfo(), and RecordKnownAssignedTransactionIds().

4568 {
4569  ProcArrayStruct *pArray = procArray;
4570  TransactionId next_xid;
4571  int head,
4572  tail;
4573  int nxids;
4574  int i;
4575 
4576  Assert(TransactionIdPrecedesOrEquals(from_xid, to_xid));
4577 
4578  /*
4579  * Calculate how many array slots we'll need. Normally this is cheap; in
4580  * the unusual case where the XIDs cross the wrap point, we do it the hard
4581  * way.
4582  */
4583  if (to_xid >= from_xid)
4584  nxids = to_xid - from_xid + 1;
4585  else
4586  {
4587  nxids = 1;
4588  next_xid = from_xid;
4589  while (TransactionIdPrecedes(next_xid, to_xid))
4590  {
4591  nxids++;
4592  TransactionIdAdvance(next_xid);
4593  }
4594  }
4595 
4596  /*
4597  * Since only the startup process modifies the head/tail pointers, we
4598  * don't need a lock to read them here.
4599  */
4600  head = pArray->headKnownAssignedXids;
4601  tail = pArray->tailKnownAssignedXids;
4602 
4603  Assert(head >= 0 && head <= pArray->maxKnownAssignedXids);
4604  Assert(tail >= 0 && tail < pArray->maxKnownAssignedXids);
4605 
4606  /*
4607  * Verify that insertions occur in TransactionId sequence. Note that even
4608  * if the last existing element is marked invalid, it must still have a
4609  * correctly sequenced XID value.
4610  */
4611  if (head > tail &&
4612  TransactionIdFollowsOrEquals(KnownAssignedXids[head - 1], from_xid))
4613  {
4615  elog(ERROR, "out-of-order XID insertion in KnownAssignedXids");
4616  }
4617 
4618  /*
4619  * If our xids won't fit in the remaining space, compress out free space
4620  */
4621  if (head + nxids > pArray->maxKnownAssignedXids)
4622  {
4623  /* must hold lock to compress */
4624  if (!exclusive_lock)
4625  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4626 
4628 
4629  head = pArray->headKnownAssignedXids;
4630  /* note: we no longer care about the tail pointer */
4631 
4632  if (!exclusive_lock)
4633  LWLockRelease(ProcArrayLock);
4634 
4635  /*
4636  * If it still won't fit then we're out of memory
4637  */
4638  if (head + nxids > pArray->maxKnownAssignedXids)
4639  elog(ERROR, "too many KnownAssignedXids");
4640  }
4641 
4642  /* Now we can insert the xids into the space starting at head */
4643  next_xid = from_xid;
4644  for (i = 0; i < nxids; i++)
4645  {
4646  KnownAssignedXids[head] = next_xid;
4647  KnownAssignedXidsValid[head] = true;
4648  TransactionIdAdvance(next_xid);
4649  head++;
4650  }
4651 
4652  /* Adjust count of number of valid entries */
4653  pArray->numKnownAssignedXids += nxids;
4654 
4655  /*
4656  * Now update the head pointer. We use a spinlock to protect this
4657  * pointer, not because the update is likely to be non-atomic, but to
4658  * ensure that other processors see the above array updates before they
4659  * see the head pointer change.
4660  *
4661  * If we're holding ProcArrayLock exclusively, there's no need to take the
4662  * spinlock.
4663  */
4664  if (exclusive_lock)
4665  pArray->headKnownAssignedXids = head;
4666  else
4667  {
4669  pArray->headKnownAssignedXids = head;
4671  }
4672 }
#define TransactionIdAdvance(dest)
Definition: transam.h:91
static void KnownAssignedXidsDisplay(int trace_level)
Definition: procarray.c:5023
uint32 TransactionId
Definition: c.h:587
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:349
slock_t known_assigned_xids_lck
Definition: procarray.c:84
#define LOG
Definition: elog.h:26
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
#define SpinLockAcquire(lock)
Definition: spin.h:62
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:319
#define ERROR
Definition: elog.h:45
int maxKnownAssignedXids
Definition: procarray.c:80
int numKnownAssignedXids
Definition: procarray.c:81
static bool * KnownAssignedXidsValid
Definition: procarray.c:258
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define SpinLockRelease(lock)
Definition: spin.h:64
#define Assert(condition)
Definition: c.h:804
static TransactionId * KnownAssignedXids
Definition: procarray.c:257
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
static void KnownAssignedXidsCompress(bool force)
Definition: procarray.c:4504
#define elog(elevel,...)
Definition: elog.h:227
int i
int tailKnownAssignedXids
Definition: procarray.c:82
int headKnownAssignedXids
Definition: procarray.c:83

◆ KnownAssignedXidsCompress()

static void KnownAssignedXidsCompress ( bool  force)
static

Definition at line 4504 of file procarray.c.

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

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

4505 {
4506  ProcArrayStruct *pArray = procArray;
4507  int head,
4508  tail;
4509  int compress_index;
4510  int i;
4511 
4512  /* no spinlock required since we hold ProcArrayLock exclusively */
4513  head = pArray->headKnownAssignedXids;
4514  tail = pArray->tailKnownAssignedXids;
4515 
4516  if (!force)
4517  {
4518  /*
4519  * If we can choose how much to compress, use a heuristic to avoid
4520  * compressing too often or not often enough.
4521  *
4522  * Heuristic is if we have a large enough current spread and less than
4523  * 50% of the elements are currently in use, then compress. This
4524  * should ensure we compress fairly infrequently. We could compress
4525  * less often though the virtual array would spread out more and
4526  * snapshots would become more expensive.
4527  */
4528  int nelements = head - tail;
4529 
4530  if (nelements < 4 * PROCARRAY_MAXPROCS ||
4531  nelements < 2 * pArray->numKnownAssignedXids)
4532  return;
4533  }
4534 
4535  /*
4536  * We compress the array by reading the valid values from tail to head,
4537  * re-aligning data to 0th element.
4538  */
4539  compress_index = 0;
4540  for (i = tail; i < head; i++)
4541  {
4542  if (KnownAssignedXidsValid[i])
4543  {
4544  KnownAssignedXids[compress_index] = KnownAssignedXids[i];
4545  KnownAssignedXidsValid[compress_index] = true;
4546  compress_index++;
4547  }
4548  }
4549 
4550  pArray->tailKnownAssignedXids = 0;
4551  pArray->headKnownAssignedXids = compress_index;
4552 }
#define PROCARRAY_MAXPROCS
static bool * KnownAssignedXidsValid
Definition: procarray.c:258
static ProcArrayStruct * procArray
Definition: procarray.c:250
static TransactionId * KnownAssignedXids
Definition: procarray.c:257
int i
int tailKnownAssignedXids
Definition: procarray.c:82
int headKnownAssignedXids
Definition: procarray.c:83

◆ KnownAssignedXidsDisplay()

static void KnownAssignedXidsDisplay ( int  trace_level)
static

Definition at line 5023 of file procarray.c.

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

Referenced by KnownAssignedXidsAdd(), and ProcArrayApplyRecoveryInfo().

5024 {
5025  ProcArrayStruct *pArray = procArray;
5027  int head,
5028  tail,
5029  i;
5030  int nxids = 0;
5031 
5032  tail = pArray->tailKnownAssignedXids;
5033  head = pArray->headKnownAssignedXids;
5034 
5035  initStringInfo(&buf);
5036 
5037  for (i = tail; i < head; i++)
5038  {
5039  if (KnownAssignedXidsValid[i])
5040  {
5041  nxids++;
5042  appendStringInfo(&buf, "[%d]=%u ", i, KnownAssignedXids[i]);
5043  }
5044  }
5045 
5046  elog(trace_level, "%d KnownAssignedXids (num=%d tail=%d head=%d) %s",
5047  nxids,
5048  pArray->numKnownAssignedXids,
5049  pArray->tailKnownAssignedXids,
5050  pArray->headKnownAssignedXids,
5051  buf.data);
5052 
5053  pfree(buf.data);
5054 }
void pfree(void *pointer)
Definition: mcxt.c:1057
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
static char * buf
Definition: pg_test_fsync.c:68
int numKnownAssignedXids
Definition: procarray.c:81
static bool * KnownAssignedXidsValid
Definition: procarray.c:258
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
static ProcArrayStruct * procArray
Definition: procarray.c:250
static TransactionId * KnownAssignedXids
Definition: procarray.c:257
#define elog(elevel,...)
Definition: elog.h:227
int i
int tailKnownAssignedXids
Definition: procarray.c:82
int headKnownAssignedXids
Definition: procarray.c:83

◆ KnownAssignedXidsGet()

static int KnownAssignedXidsGet ( TransactionId xarray,
TransactionId  xmax 
)
static

Definition at line 4916 of file procarray.c.

References InvalidTransactionId, and KnownAssignedXidsGetAndSetXmin().

Referenced by TransactionIdIsInProgress().

4917 {
4919 
4920  return KnownAssignedXidsGetAndSetXmin(xarray, &xtmp, xmax);
4921 }
uint32 TransactionId
Definition: c.h:587
#define InvalidTransactionId
Definition: transam.h:31
static int KnownAssignedXidsGetAndSetXmin(TransactionId *xarray, TransactionId *xmin, TransactionId xmax)
Definition: procarray.c:4930

◆ KnownAssignedXidsGetAndSetXmin()

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

Definition at line 4930 of file procarray.c.

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

Referenced by GetSnapshotData(), and KnownAssignedXidsGet().

4932 {
4933  int count = 0;
4934  int head,
4935  tail;
4936  int i;
4937 
4938  /*
4939  * Fetch head just once, since it may change while we loop. We can stop
4940  * once we reach the initially seen head, since we are certain that an xid
4941  * cannot enter and then leave the array while we hold ProcArrayLock. We
4942  * might miss newly-added xids, but they should be >= xmax so irrelevant
4943  * anyway.
4944  *
4945  * Must take spinlock to ensure we see up-to-date array contents.
4946  */
4951 
4952  for (i = tail; i < head; i++)
4953  {
4954  /* Skip any gaps in the array */
4955  if (KnownAssignedXidsValid[i])
4956  {
4957  TransactionId knownXid = KnownAssignedXids[i];
4958 
4959  /*
4960  * Update xmin if required. Only the first XID need be checked,
4961  * since the array is sorted.
4962  */
4963  if (count == 0 &&
4964  TransactionIdPrecedes(knownXid, *xmin))
4965  *xmin = knownXid;
4966 
4967  /*
4968  * Filter out anything >= xmax, again relying on sorted property
4969  * of array.
4970  */
4971  if (TransactionIdIsValid(xmax) &&
4972  TransactionIdFollowsOrEquals(knownXid, xmax))
4973  break;
4974 
4975  /* Add knownXid into output array */
4976  xarray[count++] = knownXid;
4977  }
4978  }
4979 
4980  return count;
4981 }
uint32 TransactionId
Definition: c.h:587
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:349
slock_t known_assigned_xids_lck
Definition: procarray.c:84
#define SpinLockAcquire(lock)
Definition: spin.h:62
static bool * KnownAssignedXidsValid
Definition: procarray.c:258
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define SpinLockRelease(lock)
Definition: spin.h:64
static TransactionId * KnownAssignedXids
Definition: procarray.c:257
int i
#define TransactionIdIsValid(xid)
Definition: transam.h:41
int tailKnownAssignedXids
Definition: procarray.c:82
int headKnownAssignedXids
Definition: procarray.c:83

◆ KnownAssignedXidsGetOldestXmin()

static TransactionId KnownAssignedXidsGetOldestXmin ( void  )
static

Definition at line 4988 of file procarray.c.

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

Referenced by ComputeXidHorizons().

4989 {
4990  int head,
4991  tail;
4992  int i;
4993 
4994  /*
4995  * Fetch head just once, since it may change while we loop.
4996  */
5001 
5002  for (i = tail; i < head; i++)
5003  {
5004  /* Skip any gaps in the array */
5005  if (KnownAssignedXidsValid[i])
5006  return KnownAssignedXids[i];
5007  }
5008 
5009  return InvalidTransactionId;
5010 }
slock_t known_assigned_xids_lck
Definition: procarray.c:84
#define SpinLockAcquire(lock)
Definition: spin.h:62
#define InvalidTransactionId
Definition: transam.h:31
static bool * KnownAssignedXidsValid
Definition: procarray.c:258
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define SpinLockRelease(lock)
Definition: spin.h:64
static TransactionId * KnownAssignedXids
Definition: procarray.c:257
int i
int tailKnownAssignedXids
Definition: procarray.c:82
int headKnownAssignedXids
Definition: procarray.c:83

◆ KnownAssignedXidsRemove()

static void KnownAssignedXidsRemove ( TransactionId  xid)
static

Definition at line 4790 of file procarray.c.

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

Referenced by KnownAssignedXidsRemoveTree().

4791 {
4793 
4794  elog(trace_recovery(DEBUG4), "remove KnownAssignedXid %u", xid);
4795 
4796  /*
4797  * Note: we cannot consider it an error to remove an XID that's not
4798  * present. We intentionally remove subxact IDs while processing
4799  * XLOG_XACT_ASSIGNMENT, to avoid array overflow. Then those XIDs will be
4800  * removed again when the top-level xact commits or aborts.
4801  *
4802  * It might be possible to track such XIDs to distinguish this case from
4803  * actual errors, but it would be complicated and probably not worth it.
4804  * So, just ignore the search result.
4805  */
4806  (void) KnownAssignedXidsSearch(xid, true);
4807 }
#define DEBUG4
Definition: elog.h:22
int trace_recovery(int trace_level)
Definition: elog.c:3568
#define Assert(condition)
Definition: c.h:804
static bool KnownAssignedXidsSearch(TransactionId xid, bool remove)
Definition: procarray.c:4684
#define elog(elevel,...)
Definition: elog.h:227
#define TransactionIdIsValid(xid)
Definition: transam.h:41

◆ KnownAssignedXidsRemovePreceding()

static void KnownAssignedXidsRemovePreceding ( TransactionId  xid)
static

Definition at line 4838 of file procarray.c.

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

Referenced by ExpireAllKnownAssignedTransactionIds(), and ExpireOldKnownAssignedTransactionIds().

4839 {
4840  ProcArrayStruct *pArray = procArray;
4841  int count = 0;
4842  int head,
4843  tail,
4844  i;
4845 
4846  if (!TransactionIdIsValid(removeXid))
4847  {
4848  elog(trace_recovery(DEBUG4), "removing all KnownAssignedXids");
4849  pArray->numKnownAssignedXids = 0;
4850  pArray->headKnownAssignedXids = pArray->tailKnownAssignedXids = 0;
4851  return;
4852  }
4853 
4854  elog(trace_recovery(DEBUG4), "prune KnownAssignedXids to %u", removeXid);
4855 
4856  /*
4857  * Mark entries invalid starting at the tail. Since array is sorted, we
4858  * can stop as soon as we reach an entry >= removeXid.
4859  */
4860  tail = pArray->tailKnownAssignedXids;
4861  head = pArray->headKnownAssignedXids;
4862 
4863  for (i = tail; i < head; i++)
4864  {
4865  if (KnownAssignedXidsValid[i])
4866  {
4867  TransactionId knownXid = KnownAssignedXids[i];
4868 
4869  if (TransactionIdFollowsOrEquals(knownXid, removeXid))
4870  break;
4871 
4872  if (!StandbyTransactionIdIsPrepared(knownXid))
4873  {
4874  KnownAssignedXidsValid[i] = false;
4875  count++;
4876  }
4877  }
4878  }
4879 
4880  pArray->numKnownAssignedXids -= count;
4881  Assert(pArray->numKnownAssignedXids >= 0);
4882 
4883  /*
4884  * Advance the tail pointer if we've marked the tail item invalid.
4885  */
4886  for (i = tail; i < head; i++)
4887  {
4888  if (KnownAssignedXidsValid[i])
4889  break;
4890  }
4891  if (i >= head)
4892  {
4893  /* Array is empty, so we can reset both pointers */
4894  pArray->headKnownAssignedXids = 0;
4895  pArray->tailKnownAssignedXids = 0;
4896  }
4897  else
4898  {
4899  pArray->tailKnownAssignedXids = i;
4900  }
4901 
4902  /* Opportunistically compress the array */
4904 }
uint32 TransactionId
Definition: c.h:587
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:349
#define DEBUG4
Definition: elog.h:22
int trace_recovery(int trace_level)
Definition: elog.c:3568
bool StandbyTransactionIdIsPrepared(TransactionId xid)
Definition: twophase.c:1368
int numKnownAssignedXids
Definition: procarray.c:81
static bool * KnownAssignedXidsValid
Definition: procarray.c:258
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define Assert(condition)
Definition: c.h:804
static TransactionId * KnownAssignedXids
Definition: procarray.c:257
static void KnownAssignedXidsCompress(bool force)
Definition: procarray.c:4504
#define elog(elevel,...)
Definition: elog.h:227
int i
#define TransactionIdIsValid(xid)
Definition: transam.h:41
int tailKnownAssignedXids
Definition: procarray.c:82
int headKnownAssignedXids
Definition: procarray.c:83

◆ KnownAssignedXidsRemoveTree()

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

Definition at line 4816 of file procarray.c.

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

Referenced by ExpireTreeKnownAssignedTransactionIds(), and ProcArrayApplyXidAssignment().

4818 {
4819  int i;
4820 
4821  if (TransactionIdIsValid(xid))
4823 
4824  for (i = 0; i < nsubxids; i++)
4825  KnownAssignedXidsRemove(subxids[i]);
4826 
4827  /* Opportunistically compress the array */
4829 }
static void KnownAssignedXidsCompress(bool force)
Definition: procarray.c:4504
static void KnownAssignedXidsRemove(TransactionId xid)
Definition: procarray.c:4790
int i
#define TransactionIdIsValid(xid)
Definition: transam.h:41

◆ KnownAssignedXidsReset()

static void KnownAssignedXidsReset ( void  )
static

Definition at line 5061 of file procarray.c.

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

Referenced by ProcArrayApplyRecoveryInfo().

5062 {
5063  ProcArrayStruct *pArray = procArray;
5064 
5065  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
5066 
5067  pArray->numKnownAssignedXids = 0;
5068  pArray->tailKnownAssignedXids = 0;
5069  pArray->headKnownAssignedXids = 0;
5070 
5071  LWLockRelease(ProcArrayLock);
5072 }
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
int numKnownAssignedXids
Definition: procarray.c:81
static ProcArrayStruct * procArray
Definition: procarray.c:250
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
int tailKnownAssignedXids
Definition: procarray.c:82
int headKnownAssignedXids
Definition: procarray.c:83

◆ KnownAssignedXidsSearch()

static bool KnownAssignedXidsSearch ( TransactionId  xid,
bool  remove 
)
static

Definition at line 4684 of file procarray.c.

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

Referenced by KnownAssignedXidExists(), and KnownAssignedXidsRemove().

4685 {
4686  ProcArrayStruct *pArray = procArray;
4687  int first,
4688  last;
4689  int head;
4690  int tail;
4691  int result_index = -1;
4692 
4693  if (remove)
4694  {
4695  /* we hold ProcArrayLock exclusively, so no need for spinlock */
4696  tail = pArray->tailKnownAssignedXids;
4697  head = pArray->headKnownAssignedXids;
4698  }
4699  else
4700  {
4701  /* take spinlock to ensure we see up-to-date array contents */
4703  tail = pArray->tailKnownAssignedXids;
4704  head = pArray->headKnownAssignedXids;
4706  }
4707 
4708  /*
4709  * Standard binary search. Note we can ignore the KnownAssignedXidsValid
4710  * array here, since even invalid entries will contain sorted XIDs.
4711  */
4712  first = tail;
4713  last = head - 1;
4714  while (first <= last)
4715  {
4716  int mid_index;
4717  TransactionId mid_xid;
4718 
4719  mid_index = (first + last) / 2;
4720  mid_xid = KnownAssignedXids[mid_index];
4721 
4722  if (xid == mid_xid)
4723  {
4724  result_index = mid_index;
4725  break;
4726  }
4727  else if (TransactionIdPrecedes(xid, mid_xid))
4728  last = mid_index - 1;
4729  else
4730  first = mid_index + 1;
4731  }
4732 
4733  if (result_index < 0)
4734  return false; /* not in array */
4735 
4736  if (!KnownAssignedXidsValid[result_index])
4737  return false; /* in array, but invalid */
4738 
4739  if (remove)
4740  {
4741  KnownAssignedXidsValid[result_index] = false;
4742 
4743  pArray->numKnownAssignedXids--;
4744  Assert(pArray->numKnownAssignedXids >= 0);
4745 
4746  /*
4747  * If we're removing the tail element then advance tail pointer over
4748  * any invalid elements. This will speed future searches.
4749  */
4750  if (result_index == tail)
4751  {
4752  tail++;
4753  while (tail < head && !KnownAssignedXidsValid[tail])
4754  tail++;
4755  if (tail >= head)
4756  {
4757  /* Array is empty, so we can reset both pointers */
4758  pArray->headKnownAssignedXids = 0;
4759  pArray->tailKnownAssignedXids = 0;
4760  }
4761  else
4762  {
4763  pArray->tailKnownAssignedXids = tail;
4764  }
4765  }
4766  }
4767 
4768  return true;
4769 }
uint32 TransactionId
Definition: c.h:587
slock_t known_assigned_xids_lck
Definition: procarray.c:84
#define SpinLockAcquire(lock)
Definition: spin.h:62
int numKnownAssignedXids
Definition: procarray.c:81
static bool * KnownAssignedXidsValid
Definition: procarray.c:258
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define SpinLockRelease(lock)
Definition: spin.h:64
#define Assert(condition)
Definition: c.h:804
static TransactionId * KnownAssignedXids
Definition: procarray.c:257
int tailKnownAssignedXids
Definition: procarray.c:82
int headKnownAssignedXids
Definition: procarray.c:83

◆ MaintainLatestCompletedXid()

static void MaintainLatestCompletedXid ( TransactionId  latestXid)
static

Definition at line 913 of file procarray.c.

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

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

914 {
916 
917  Assert(FullTransactionIdIsValid(cur_latest));
919  Assert(LWLockHeldByMe(ProcArrayLock));
920 
921  if (TransactionIdPrecedes(XidFromFullTransactionId(cur_latest), latestXid))
922  {
924  FullXidRelativeTo(cur_latest, latestXid);
925  }
926 
929 }
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1924
#define FullTransactionIdIsValid(x)
Definition: transam.h:55
static FullTransactionId FullXidRelativeTo(FullTransactionId rel, TransactionId xid)
Definition: procarray.c:4210
FullTransactionId latestCompletedXid
Definition: transam.h:231
bool RecoveryInProgress(void)
Definition: xlog.c:8132
#define XidFromFullTransactionId(x)
Definition: transam.h:48
#define FullTransactionIdIsNormal(x)
Definition: transam.h:58
VariableCache ShmemVariableCache
Definition: varsup.c:34
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define Assert(condition)
Definition: c.h:804
#define IsBootstrapProcessingMode()
Definition: miscadmin.h:394

◆ MaintainLatestCompletedXidRecovery()

static void MaintainLatestCompletedXidRecovery ( TransactionId  latestXid)
static

Definition at line 935 of file procarray.c.

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

Referenced by ExpireTreeKnownAssignedTransactionIds(), and ProcArrayApplyRecoveryInfo().

936 {
938  FullTransactionId rel;
939 
941  Assert(LWLockHeldByMe(ProcArrayLock));
942 
943  /*
944  * Need a FullTransactionId to compare latestXid with. Can't rely on
945  * latestCompletedXid to be initialized in recovery. But in recovery it's
946  * safe to access nextXid without a lock for the startup process.
947  */
950 
951  if (!FullTransactionIdIsValid(cur_latest) ||
952  TransactionIdPrecedes(XidFromFullTransactionId(cur_latest), latestXid))
953  {
955  FullXidRelativeTo(rel, latestXid);
956  }
957 
959 }
#define AmStartupProcess()
Definition: miscadmin.h:432
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1924
#define FullTransactionIdIsValid(x)
Definition: transam.h:55
static FullTransactionId FullXidRelativeTo(FullTransactionId rel, TransactionId xid)
Definition: procarray.c:4210
FullTransactionId latestCompletedXid
Definition: transam.h:231
FullTransactionId nextXid
Definition: transam.h:213
#define XidFromFullTransactionId(x)
Definition: transam.h:48
#define FullTransactionIdIsNormal(x)
Definition: transam.h:58
bool IsUnderPostmaster
Definition: globals.c:110
VariableCache ShmemVariableCache
Definition: varsup.c:34
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
#define Assert(condition)
Definition: c.h:804

◆ MinimumActiveBackends()

bool MinimumActiveBackends ( int  min)

Definition at line 3407 of file procarray.c.

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

Referenced by XLogFlush().

3408 {
3409  ProcArrayStruct *arrayP = procArray;
3410  int count = 0;
3411  int index;
3412 
3413  /* Quick short-circuit if no minimum is specified */
3414  if (min == 0)
3415  return true;
3416 
3417  /*
3418  * Note: for speed, we don't acquire ProcArrayLock. This is a little bit
3419  * bogus, but since we are only testing fields for zero or nonzero, it
3420  * should be OK. The result is only used for heuristic purposes anyway...
3421  */
3422  for (index = 0; index < arrayP->numProcs; index++)
3423  {
3424  int pgprocno = arrayP->pgprocnos[index];
3425  PGPROC *proc = &allProcs[pgprocno];
3426 
3427  /*
3428  * Since we're not holding a lock, need to be prepared to deal with
3429  * garbage, as someone could have incremented numProcs but not yet
3430  * filled the structure.
3431  *
3432  * If someone just decremented numProcs, 'proc' could also point to a
3433  * PGPROC entry that's no longer in the array. It still points to a
3434  * PGPROC struct, though, because freed PGPROC entries just go to the
3435  * free list and are recycled. Its contents are nonsense in that case,
3436  * but that's acceptable for this function.
3437  */
3438  if (pgprocno == -1)
3439  continue; /* do not count deleted entries */
3440  if (proc == MyProc)
3441  continue; /* do not count myself */
3442  if (proc->xid == InvalidTransactionId)
3443  continue; /* do not count if no XID assigned */
3444  if (proc->pid == 0)
3445  continue; /* do not count prepared xacts */
3446  if (proc->waitLock != NULL)
3447  continue; /* do not count if blocked on a lock */
3448  count++;
3449  if (count >= min)
3450  break;
3451  }
3452 
3453  return count >= min;
3454 }
PGPROC * MyProc
Definition: proc.c:68
Definition: type.h:89
#define InvalidTransactionId
Definition: transam.h:31
static PGPROC * allProcs
Definition: procarray.c:252
LOCK * waitLock
Definition: proc.h:179
static ProcArrayStruct * procArray
Definition: procarray.c:250
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
TransactionId xid
Definition: proc.h:133
Definition: proc.h:121
int pid
Definition: proc.h:146

◆ ProcArrayAdd()

void ProcArrayAdd ( PGPROC proc)

Definition at line 445 of file procarray.c.

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

Referenced by InitProcessPhase2(), and MarkAsPrepared().

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

◆ ProcArrayApplyRecoveryInfo()

void ProcArrayApplyRecoveryInfo ( RunningTransactions  running)

Definition at line 1000 of file procarray.c.

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

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

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

◆ ProcArrayApplyXidAssignment()

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

Definition at line 1236 of file procarray.c.

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

Referenced by xact_redo().

1238 {
1239  TransactionId max_xid;
1240  int i;
1241 
1243 
1244  max_xid = TransactionIdLatest(topxid, nsubxids, subxids);
1245 
1246  /*
1247  * Mark all the subtransactions as observed.
1248  *
1249  * NOTE: This will fail if the subxid contains too many previously
1250  * unobserved xids to fit into known-assigned-xids. That shouldn't happen
1251  * as the code stands, because xid-assignment records should never contain
1252  * more than PGPROC_MAX_CACHED_SUBXIDS entries.
1253  */
1255 
1256  /*
1257  * Notice that we update pg_subtrans with the top-level xid, rather than
1258  * the parent xid. This is a difference between normal processing and
1259  * recovery, yet is still correct in all cases. The reason is that
1260  * subtransaction commit is not marked in clog until commit processing, so
1261  * all aborted subtransactions have already been clearly marked in clog.
1262  * As a result we are able to refer directly to the top-level
1263  * transaction's state rather than skipping through all the intermediate
1264  * states in the subtransaction tree. This should be the first time we
1265  * have attempted to SubTransSetParent().
1266  */
1267  for (i = 0; i < nsubxids; i++)
1268  SubTransSetParent(subxids[i], topxid);
1269 
1270  /* KnownAssignedXids isn't maintained yet, so we're done for now */
1272  return;
1273 
1274  /*
1275  * Uses same locking as transaction commit
1276  */
1277  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
1278 
1279  /*
1280  * Remove subxids from known-assigned-xacts.
1281  */
1283 
1284  /*
1285  * Advance lastOverflowedXid to be at least the last of these subxids.
1286  */
1288  procArray->lastOverflowedXid = max_xid;
1289 
1290  LWLockRelease(ProcArrayLock);
1291 }
uint32 TransactionId
Definition: c.h:587
TransactionId TransactionIdLatest(TransactionId mainxid, int nxids, const TransactionId *xids)
Definition: transam.c:365
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
#define InvalidTransactionId
Definition: transam.h:31
TransactionId lastOverflowedXid
Definition: procarray.c:93
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
static void KnownAssignedXidsRemoveTree(TransactionId xid, int nsubxids, TransactionId *subxids)
Definition: procarray.c:4816
static ProcArrayStruct * procArray
Definition: procarray.c:250
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
int i
void RecordKnownAssignedTransactionIds(TransactionId xid)
Definition: procarray.c:4292
void SubTransSetParent(TransactionId xid, TransactionId parent)
Definition: subtrans.c:74
HotStandbyState standbyState
Definition: xlog.c:209

◆ ProcArrayClearTransaction()

void ProcArrayClearTransaction ( PGPROC proc)

Definition at line 853 of file procarray.c.

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

Referenced by PrepareTransaction().

854 {
855  size_t pgxactoff;
856 
857  /*
858  * Currently we need to lock ProcArrayLock exclusively here, as we
859  * increment xactCompletionCount below. We also need it at least in shared
860  * mode for pgproc->pgxactoff to stay the same below.
861  *
862  * We could however, as this action does not actually change anyone's view
863  * of the set of running XIDs (our entry is duplicate with the gxact that
864  * has already been inserted into the ProcArray), lower the lock level to
865  * shared if we were to make xactCompletionCount an atomic variable. But
866  * that doesn't seem worth it currently, as a 2PC commit is heavyweight
867  * enough for this not to be the bottleneck. If it ever becomes a
868  * bottleneck it may also be worth considering to combine this with the
869  * subsequent ProcArrayRemove()
870  */
871  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
872 
873  pgxactoff = proc->pgxactoff;
874 
875  ProcGlobal->xids[pgxactoff] = InvalidTransactionId;
876  proc->xid = InvalidTransactionId;
877 
879  proc->xmin = InvalidTransactionId;
880  proc->recoveryConflictPending = false;
881 
883  Assert(!proc->delayChkpt);
884 
885  /*
886  * Need to increment completion count even though transaction hasn't
887  * really committed yet. The reason for that is that GetSnapshotData()
888  * omits the xid of the current transaction, thus without the increment we
889  * otherwise could end up reusing the snapshot later. Which would be bad,
890  * because it might not count the prepared transaction as running.
891  */
893 
894  /* Clear the subtransaction-XID cache too */
895  Assert(ProcGlobal->subxidStates[pgxactoff].count == proc->subxidStatus.count &&
897  if (proc->subxidStatus.count > 0 || proc->subxidStatus.overflowed)
898  {
899  ProcGlobal->subxidStates[pgxactoff].count = 0;
900  ProcGlobal->subxidStates[pgxactoff].overflowed = false;
901  proc->subxidStatus.count = 0;
902  proc->subxidStatus.overflowed = false;
903  }
904 
905  LWLockRelease(ProcArrayLock);
906 }
XidCacheStatus * subxidStates
Definition: proc.h:327
uint64 xactCompletionCount
Definition: transam.h:241
PROC_HDR * ProcGlobal
Definition: proc.c:80
uint8 statusFlags
Definition: proc.h:189
XidCacheStatus subxidStatus
Definition: proc.h:210
#define PROC_VACUUM_STATE_MASK
Definition: proc.h:65
bool overflowed
Definition: proc.h:43
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
bool delayChkpt
Definition: proc.h:187
TransactionId xmin
Definition: proc.h:138
bool recoveryConflictPending
Definition: proc.h:167
VariableCache ShmemVariableCache
Definition: varsup.c:34
#define InvalidTransactionId
Definition: transam.h:31
TransactionId * xids
Definition: proc.h:321
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
uint8 count
Definition: proc.h:41
TransactionId xid
Definition: proc.h:133
#define InvalidLocalTransactionId
Definition: lock.h:69
int pgxactoff
Definition: proc.h:148
LocalTransactionId lxid
Definition: proc.h:143

◆ ProcArrayEndTransaction()

void ProcArrayEndTransaction ( PGPROC proc,
TransactionId  latestXid 
)

Definition at line 620 of file procarray.c.

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

Referenced by AbortTransaction(), and CommitTransaction().

621 {
622  if (TransactionIdIsValid(latestXid))
623  {
624  /*
625  * We must lock ProcArrayLock while clearing our advertised XID, so
626  * that we do not exit the set of "running" transactions while someone
627  * else is taking a snapshot. See discussion in
628  * src/backend/access/transam/README.
629  */
631 
632  /*
633  * If we can immediately acquire ProcArrayLock, we clear our own XID
634  * and release the lock. If not, use group XID clearing to improve
635  * efficiency.
636  */
637  if (LWLockConditionalAcquire(ProcArrayLock, LW_EXCLUSIVE))
638  {
639  ProcArrayEndTransactionInternal(proc, latestXid);
640  LWLockRelease(ProcArrayLock);
641  }
642  else
643  ProcArrayGroupClearXid(proc, latestXid);
644  }
645  else
646  {
647  /*
648  * If we have no XID, we don't need to lock, since we won't affect
649  * anyone else's calculation of a snapshot. We might change their
650  * estimate of global xmin, but that's OK.
651  */
653  Assert(proc->subxidStatus.count == 0);
655 
657  proc->xmin = InvalidTransactionId;
658  proc->delayChkpt = false; /* be sure this is cleared in abort */
659  proc->recoveryConflictPending = false;
660 
661  /* must be cleared with xid/xmin: */
662  /* avoid unnecessarily dirtying shared cachelines */
664  {
665  Assert(!LWLockHeldByMe(ProcArrayLock));
666  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
670  LWLockRelease(ProcArrayLock);
671  }
672  }
673 }
bool LWLockHeldByMe(LWLock *l)
Definition: lwlock.c:1924
static void ProcArrayEndTransactionInternal(PGPROC *proc, TransactionId latestXid)
Definition: procarray.c:681
static void ProcArrayGroupClearXid(PGPROC *proc, TransactionId latestXid)
Definition: procarray.c:739
PROC_HDR * ProcGlobal
Definition: proc.c:80
uint8 statusFlags
Definition: proc.h:189
XidCacheStatus subxidStatus
Definition: proc.h:210
#define PROC_VACUUM_STATE_MASK
Definition: proc.h:65
bool overflowed
Definition: proc.h:43
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
bool delayChkpt
Definition: proc.h:187
TransactionId xmin
Definition: proc.h:138
bool LWLockConditionalAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1378
bool recoveryConflictPending
Definition: proc.h:167
#define InvalidTransactionId
Definition: transam.h:31
#define Assert(condition)
Definition: c.h:804
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206
uint8 count
Definition: proc.h:41
TransactionId xid
Definition: proc.h:133
#define InvalidLocalTransactionId
Definition: lock.h:69
int pgxactoff
Definition: proc.h:148
uint8 * statusFlags
Definition: proc.h:333
#define TransactionIdIsValid(xid)
Definition: transam.h:41
LocalTransactionId lxid
Definition: proc.h:143

◆ ProcArrayEndTransactionInternal()

static void ProcArrayEndTransactionInternal ( PGPROC proc,
TransactionId  latestXid 
)
inlinestatic

Definition at line 681 of file procarray.c.

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

Referenced by ProcArrayEndTransaction(), and ProcArrayGroupClearXid().

682 {
683  size_t pgxactoff = proc->pgxactoff;
684 
685  /*
686  * Note: we need exclusive lock here because we're going to change other
687  * processes' PGPROC entries.
688  */
689  Assert(LWLockHeldByMeInMode(ProcArrayLock, LW_EXCLUSIVE));
691  Assert(ProcGlobal->xids[pgxactoff] == proc->xid);
692 
693  ProcGlobal->xids[pgxactoff] = InvalidTransactionId;
694  proc->xid = InvalidTransactionId;
696  proc->xmin = InvalidTransactionId;
697  proc->delayChkpt = false; /* be sure this is cleared in abort */
698  proc->recoveryConflictPending = false;
699 
700  /* must be cleared with xid/xmin: */
701  /* avoid unnecessarily dirtying shared cachelines */
703  {
706  }
707 
708  /* Clear the subtransaction-XID cache too while holding the lock */
709  Assert(ProcGlobal->subxidStates[pgxactoff].count == proc->subxidStatus.count &&
711  if (proc->subxidStatus.count > 0 || proc->subxidStatus.overflowed)
712  {
713  ProcGlobal->subxidStates[pgxactoff].count = 0;
714  ProcGlobal->subxidStates[pgxactoff].overflowed = false;
715  proc->subxidStatus.count = 0;
716  proc->subxidStatus.overflowed = false;
717  }
718 
719  /* Also advance global latestCompletedXid while holding the lock */
720  MaintainLatestCompletedXid(latestXid);
721 
722  /* Same with xactCompletionCount */
724 }
bool LWLockHeldByMeInMode(LWLock *l, LWLockMode mode)
Definition: lwlock.c:1942
XidCacheStatus * subxidStates
Definition: proc.h:327
uint64 xactCompletionCount
Definition: transam.h:241
PROC_HDR * ProcGlobal
Definition: proc.c:80
uint8 statusFlags
Definition: proc.h:189
XidCacheStatus subxidStatus
Definition: proc.h:210
#define PROC_VACUUM_STATE_MASK
Definition: proc.h:65
bool overflowed
Definition: proc.h:43
bool delayChkpt
Definition: proc.h:187
TransactionId xmin
Definition: proc.h:138
bool recoveryConflictPending
Definition: proc.h:167
VariableCache ShmemVariableCache
Definition: varsup.c:34
#define InvalidTransactionId
Definition: transam.h:31
TransactionId * xids
Definition: proc.h:321
static void MaintainLatestCompletedXid(TransactionId latestXid)
Definition: procarray.c:913
#define Assert(condition)
Definition: c.h:804
uint8 count
Definition: proc.h:41
TransactionId xid
Definition: proc.h:133
#define InvalidLocalTransactionId
Definition: lock.h:69
int pgxactoff
Definition: proc.h:148
uint8 * statusFlags
Definition: proc.h:333
#define TransactionIdIsValid(xid)
Definition: transam.h:41
LocalTransactionId lxid
Definition: proc.h:143

◆ ProcArrayGetReplicationSlotXmin()

void ProcArrayGetReplicationSlotXmin ( TransactionId xmin,
TransactionId catalog_xmin 
)

Definition at line 3819 of file procarray.c.

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

Referenced by logical_begin_heap_rewrite().

3821 {
3822  LWLockAcquire(ProcArrayLock, LW_SHARED);
3823 
3824  if (xmin != NULL)
3826 
3827  if (catalog_xmin != NULL)
3828  *catalog_xmin = procArray->replication_slot_catalog_xmin;
3829 
3830  LWLockRelease(ProcArrayLock);
3831 }
TransactionId replication_slot_catalog_xmin
Definition: procarray.c:98
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
static ProcArrayStruct * procArray
Definition: procarray.c:250
TransactionId replication_slot_xmin
Definition: procarray.c:96
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1206

◆ ProcArrayGroupClearXid()

static void ProcArrayGroupClearXid ( PGPROC proc,
TransactionId  latestXid 
)
static

Definition at line 739 of file procarray.c.

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

Referenced by ProcArrayEndTransaction().

740 {
741  PROC_HDR *procglobal = ProcGlobal;
742  uint32 nextidx;
743  uint32 wakeidx;
744 
745  /* We should definitely have an XID to clear. */
747 
748  /* Add ourselves to the list of processes needing a group XID clear. */
749  proc->procArrayGroupMember = true;
750  proc->procArrayGroupMemberXid = latestXid;
751  nextidx = pg_atomic_read_u32(&procglobal->procArrayGroupFirst);
752  while (true)
753  {
754  pg_atomic_write_u32(&proc->procArrayGroupNext, nextidx);
755 
757  &nextidx,
758  (uint32) proc->pgprocno))
759  break;
760  }
761 
762  /*
763  * If the list was not empty, the leader will clear our XID. It is
764  * impossible to have followers without a leader because the first process
765  * that has added itself to the list will always have nextidx as
766  * INVALID_PGPROCNO.
767  */
768  if (nextidx != INVALID_PGPROCNO)
769  {
770  int extraWaits = 0;
771 
772  /* Sleep until the leader clears our XID. */
774  for (;;)
775  {
776  /* acts as a read barrier */
777  PGSemaphoreLock(proc->sem);
778  if (!proc->procArrayGroupMember)
779  break;
780  extraWaits++;
781  }
783 
785 
786  /* Fix semaphore count for any absorbed wakeups */
787  while (extraWaits-- > 0)
788  PGSemaphoreUnlock(proc->sem);
789  return;
790  }
791 
792  /* We are the leader. Acquire the lock on behalf of everyone. */
793  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
794 
795  /*
796  * Now that we've got the lock, clear the list of processes waiting for
797  * group XID clearing, saving a pointer to the head of the list. Trying
798  * to pop elements one at a time could lead to an ABA problem.
799  */
800  nextidx = pg_atomic_exchange_u32(&procglobal->procArrayGroupFirst,
802 
803  /* Remember head of list so we can perform wakeups after dropping lock. */
804  wakeidx = nextidx;
805 
806  /* Walk the list and clear all XIDs. */
807  while (nextidx != INVALID_PGPROCNO)
808  {
809  PGPROC *proc = &allProcs[nextidx];
810 
812 
813  /* Move to next proc in list. */
814  nextidx = pg_atomic_read_u32(&proc->procArrayGroupNext);
815  }
816 
817  /* We're done with the lock now. */
818  LWLockRelease(ProcArrayLock);
819 
820  /*
821  * Now that we've released the lock, go back and wake everybody up. We
822  * don't do this under the lock so as to keep lock hold times to a
823  * minimum. The system calls we need to perform to wake other processes
824  * up are probably much slower than the simple memory writes we did while
825  * holding the lock.
826  */
827  while (wakeidx != INVALID_PGPROCNO)
828  {
829  PGPROC *proc = &allProcs[wakeidx];
830 
831  wakeidx = pg_atomic_read_u32(&proc->procArrayGroupNext);
833 
834  /* ensure all previous writes are visible before follower continues. */
836 
837  proc->procArrayGroupMember = false;
838 
839  if (proc != MyProc)
840  PGSemaphoreUnlock(proc->sem);
841  }
842 }
bool procArrayGroupMember
Definition: proc.h:216