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

Go to the source code of this file.

Data Structures

struct  ProcArrayStruct
 
struct  GlobalVisState
 
struct  ComputeXidHorizonsResult
 

Macros

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

Typedefs

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

Enumerations

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

Functions

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

Variables

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

Macro Definition Documentation

◆ KAX_COMPRESS_FREQUENCY

#define KAX_COMPRESS_FREQUENCY   128 /* in transactions */

◆ KAX_COMPRESS_IDLE_INTERVAL

#define KAX_COMPRESS_IDLE_INTERVAL   1000 /* in ms */

◆ MAXAUTOVACPIDS

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

◆ PROCARRAY_MAXPROCS

#define PROCARRAY_MAXPROCS   (MaxBackends + max_prepared_xacts)

◆ TOTAL_MAX_CACHED_SUBXIDS

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

◆ UINT32_ACCESS_ONCE

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

Definition at line 70 of file procarray.c.

◆ xc_by_child_xid_inc

#define xc_by_child_xid_inc ( )    ((void) 0)

Definition at line 342 of file procarray.c.

◆ xc_by_known_assigned_inc

#define xc_by_known_assigned_inc ( )    ((void) 0)

Definition at line 343 of file procarray.c.

◆ xc_by_known_xact_inc

#define xc_by_known_xact_inc ( )    ((void) 0)

Definition at line 338 of file procarray.c.

◆ xc_by_latest_xid_inc

#define xc_by_latest_xid_inc ( )    ((void) 0)

Definition at line 340 of file procarray.c.

◆ xc_by_main_xid_inc

#define xc_by_main_xid_inc ( )    ((void) 0)

Definition at line 341 of file procarray.c.

◆ xc_by_my_xact_inc

#define xc_by_my_xact_inc ( )    ((void) 0)

Definition at line 339 of file procarray.c.

◆ xc_by_recent_xmin_inc

#define xc_by_recent_xmin_inc ( )    ((void) 0)

Definition at line 337 of file procarray.c.

◆ xc_no_overflow_inc

#define xc_no_overflow_inc ( )    ((void) 0)

Definition at line 344 of file procarray.c.

◆ xc_slow_answer_inc

#define xc_slow_answer_inc ( )    ((void) 0)

Definition at line 345 of file procarray.c.

Typedef Documentation

◆ ComputeXidHorizonsResult

◆ GlobalVisHorizonKind

◆ KAXCompressReason

◆ ProcArrayStruct

Enumeration Type Documentation

◆ GlobalVisHorizonKind

Enumerator
VISHORIZON_SHARED 
VISHORIZON_CATALOG 
VISHORIZON_DATA 
VISHORIZON_TEMP 

Definition at line 251 of file procarray.c.

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

◆ KAXCompressReason

Enumerator
KAX_NO_SPACE 
KAX_PRUNE 
KAX_TRANSACTION_END 
KAX_STARTUP_PROCESS_IDLE 

Definition at line 262 of file procarray.c.

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

Function Documentation

◆ BackendPidGetProc()

PGPROC * BackendPidGetProc ( int  pid)

Definition at line 3159 of file procarray.c.

3160{
3161 PGPROC *result;
3162
3163 if (pid == 0) /* never match dummy PGPROCs */
3164 return NULL;
3165
3166 LWLockAcquire(ProcArrayLock, LW_SHARED);
3167
3168 result = BackendPidGetProcWithLock(pid);
3169
3170 LWLockRelease(ProcArrayLock);
3171
3172 return result;
3173}
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1178
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1898
@ LW_SHARED
Definition: lwlock.h:113
PGPROC * BackendPidGetProcWithLock(int pid)
Definition: procarray.c:3182
Definition: proc.h:179

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

Referenced by IsBackendPid(), pg_isolation_test_session_is_blocked(), pg_log_backend_memory_contexts(), pg_signal_backend(), pg_stat_get_activity(), pg_stat_get_backend_wait_event(), pg_stat_get_backend_wait_event_type(), pg_stat_reset_backend_stats(), pgstat_fetch_stat_backend_by_pid(), TerminateBackgroundWorkersForDatabase(), TerminateOtherDBBackends(), and test_shm_mq_main().

◆ BackendPidGetProcWithLock()

PGPROC * BackendPidGetProcWithLock ( int  pid)

Definition at line 3182 of file procarray.c.

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

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

Referenced by BackendPidGetProc(), and GetBlockerStatusData().

◆ BackendXidGetPid()

int BackendXidGetPid ( TransactionId  xid)

Definition at line 3219 of file procarray.c.

3220{
3221 int result = 0;
3222 ProcArrayStruct *arrayP = procArray;
3223 TransactionId *other_xids = ProcGlobal->xids;
3224 int index;
3225
3226 if (xid == InvalidTransactionId) /* never match invalid xid */
3227 return 0;
3228
3229 LWLockAcquire(ProcArrayLock, LW_SHARED);
3230
3231 for (index = 0; index < arrayP->numProcs; index++)
3232 {
3233 if (other_xids[index] == xid)
3234 {
3235 int pgprocno = arrayP->pgprocnos[index];
3236 PGPROC *proc = &allProcs[pgprocno];
3237
3238 result = proc->pid;
3239 break;
3240 }
3241 }
3242
3243 LWLockRelease(ProcArrayLock);
3244
3245 return result;
3246}
uint32 TransactionId
Definition: c.h:672
PROC_HDR * ProcGlobal
Definition: proc.c:79
TransactionId * xids
Definition: proc.h:391
#define InvalidTransactionId
Definition: transam.h:31

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

Referenced by pgrowlocks().

◆ CancelDBBackends()

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

Definition at line 3621 of file procarray.c.

3622{
3623 ProcArrayStruct *arrayP = procArray;
3624 int index;
3625
3626 /* tell all backends to die */
3627 LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3628
3629 for (index = 0; index < arrayP->numProcs; index++)
3630 {
3631 int pgprocno = arrayP->pgprocnos[index];
3632 PGPROC *proc = &allProcs[pgprocno];
3633
3634 if (databaseid == InvalidOid || proc->databaseId == databaseid)
3635 {
3636 VirtualTransactionId procvxid;
3637 pid_t pid;
3638
3639 GET_VXID_FROM_PGPROC(procvxid, *proc);
3640
3641 proc->recoveryConflictPending = conflictPending;
3642 pid = proc->pid;
3643 if (pid != 0)
3644 {
3645 /*
3646 * Kill the pid if it's still here. If not, that's what we
3647 * wanted so ignore any errors.
3648 */
3649 (void) SendProcSignal(pid, sigmode, procvxid.procNumber);
3650 }
3651 }
3652 }
3653
3654 LWLockRelease(ProcArrayLock);
3655}
#define GET_VXID_FROM_PGPROC(vxid_dst, proc)
Definition: lock.h:79
@ LW_EXCLUSIVE
Definition: lwlock.h:112
#define InvalidOid
Definition: postgres_ext.h:37
int SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
Definition: procsignal.c:284
bool recoveryConflictPending
Definition: proc.h:237
Oid databaseId
Definition: proc.h:224
ProcNumber procNumber
Definition: lock.h:63

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

Referenced by ResolveRecoveryConflictWithDatabase(), and SendRecoveryConflictWithBufferPin().

◆ CancelVirtualTransaction()

pid_t CancelVirtualTransaction ( VirtualTransactionId  vxid,
ProcSignalReason  sigmode 
)

Definition at line 3453 of file procarray.c.

3454{
3455 return SignalVirtualTransaction(vxid, sigmode, true);
3456}
pid_t SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode, bool conflictPending)
Definition: procarray.c:3459

References SignalVirtualTransaction().

Referenced by ResolveRecoveryConflictWithVirtualXIDs().

◆ ComputeXidHorizons()

static void ComputeXidHorizons ( ComputeXidHorizonsResult h)
static

Definition at line 1685 of file procarray.c.

1686{
1687 ProcArrayStruct *arrayP = procArray;
1688 TransactionId kaxmin;
1689 bool in_recovery = RecoveryInProgress();
1690 TransactionId *other_xids = ProcGlobal->xids;
1691
1692 /* inferred after ProcArrayLock is released */
1694
1695 LWLockAcquire(ProcArrayLock, LW_SHARED);
1696
1698
1699 /*
1700 * We initialize the MIN() calculation with latestCompletedXid + 1. This
1701 * is a lower bound for the XIDs that might appear in the ProcArray later,
1702 * and so protects us against overestimating the result due to future
1703 * additions.
1704 */
1705 {
1706 TransactionId initial;
1707
1709 Assert(TransactionIdIsValid(initial));
1710 TransactionIdAdvance(initial);
1711
1712 h->oldest_considered_running = initial;
1713 h->shared_oldest_nonremovable = initial;
1714 h->data_oldest_nonremovable = initial;
1715
1716 /*
1717 * Only modifications made by this backend affect the horizon for
1718 * temporary relations. Instead of a check in each iteration of the
1719 * loop over all PGPROCs it is cheaper to just initialize to the
1720 * current top-level xid any.
1721 *
1722 * Without an assigned xid we could use a horizon as aggressive as
1723 * GetNewTransactionId(), but we can get away with the much cheaper
1724 * latestCompletedXid + 1: If this backend has no xid there, by
1725 * definition, can't be any newer changes in the temp table than
1726 * latestCompletedXid.
1727 */
1730 else
1731 h->temp_oldest_nonremovable = initial;
1732 }
1733
1734 /*
1735 * Fetch slot horizons while ProcArrayLock is held - the
1736 * LWLockAcquire/LWLockRelease are a barrier, ensuring this happens inside
1737 * the lock.
1738 */
1741
1742 for (int index = 0; index < arrayP->numProcs; index++)
1743 {
1744 int pgprocno = arrayP->pgprocnos[index];
1745 PGPROC *proc = &allProcs[pgprocno];
1746 int8 statusFlags = ProcGlobal->statusFlags[index];
1747 TransactionId xid;
1748 TransactionId xmin;
1749
1750 /* Fetch xid just once - see GetNewTransactionId */
1751 xid = UINT32_ACCESS_ONCE(other_xids[index]);
1752 xmin = UINT32_ACCESS_ONCE(proc->xmin);
1753
1754 /*
1755 * Consider both the transaction's Xmin, and its Xid.
1756 *
1757 * We must check both because a transaction might have an Xmin but not
1758 * (yet) an Xid; conversely, if it has an Xid, that could determine
1759 * some not-yet-set Xmin.
1760 */
1761 xmin = TransactionIdOlder(xmin, xid);
1762
1763 /* if neither is set, this proc doesn't influence the horizon */
1764 if (!TransactionIdIsValid(xmin))
1765 continue;
1766
1767 /*
1768 * Don't ignore any procs when determining which transactions might be
1769 * considered running. While slots should ensure logical decoding
1770 * backends are protected even without this check, it can't hurt to
1771 * include them here as well..
1772 */
1775
1776 /*
1777 * Skip over backends either vacuuming (which is ok with rows being
1778 * removed, as long as pg_subtrans is not truncated) or doing logical
1779 * decoding (which manages xmin separately, check below).
1780 */
1781 if (statusFlags & (PROC_IN_VACUUM | PROC_IN_LOGICAL_DECODING))
1782 continue;
1783
1784 /* shared tables need to take backends in all databases into account */
1787
1788 /*
1789 * Normally sessions in other databases are ignored for anything but
1790 * the shared horizon.
1791 *
1792 * However, include them when MyDatabaseId is not (yet) set. A
1793 * backend in the process of starting up must not compute a "too
1794 * aggressive" horizon, otherwise we could end up using it to prune
1795 * still-needed data away. If the current backend never connects to a
1796 * database this is harmless, because data_oldest_nonremovable will
1797 * never be utilized.
1798 *
1799 * Also, sessions marked with PROC_AFFECTS_ALL_HORIZONS should always
1800 * be included. (This flag is used for hot standby feedback, which
1801 * can't be tied to a specific database.)
1802 *
1803 * Also, while in recovery we cannot compute an accurate per-database
1804 * horizon, as all xids are managed via the KnownAssignedXids
1805 * machinery.
1806 */
1807 if (proc->databaseId == MyDatabaseId ||
1809 (statusFlags & PROC_AFFECTS_ALL_HORIZONS) ||
1810 in_recovery)
1811 {
1814 }
1815 }
1816
1817 /*
1818 * If in recovery fetch oldest xid in KnownAssignedXids, will be applied
1819 * after lock is released.
1820 */
1821 if (in_recovery)
1823
1824 /*
1825 * No other information from shared state is needed, release the lock
1826 * immediately. The rest of the computations can be done without a lock.
1827 */
1828 LWLockRelease(ProcArrayLock);
1829
1830 if (in_recovery)
1831 {
1838 /* temp relations cannot be accessed in recovery */
1839 }
1840
1845
1846 /*
1847 * Check whether there are replication slots requiring an older xmin.
1848 */
1853
1854 /*
1855 * The only difference between catalog / data horizons is that the slot's
1856 * catalog xmin is applied to the catalog one (so catalogs can be accessed
1857 * for logical decoding). Initialize with data horizon, and then back up
1858 * further if necessary. Have to back up the shared horizon as well, since
1859 * that also can contain catalogs.
1860 */
1869
1870 /*
1871 * It's possible that slots backed up the horizons further than
1872 * oldest_considered_running. Fix.
1873 */
1883
1884 /*
1885 * shared horizons have to be at least as old as the oldest visible in
1886 * current db
1887 */
1892
1893 /*
1894 * Horizons need to ensure that pg_subtrans access is still possible for
1895 * the relevant backends.
1896 */
1907 h->slot_xmin));
1910 h->slot_catalog_xmin));
1911
1912 /* update approximate horizons with the computed horizons */
1914}
int8_t int8
Definition: c.h:546
Oid MyDatabaseId
Definition: globals.c:94
Assert(PointerIsAligned(start, uint64))
#define PROC_IN_LOGICAL_DECODING
Definition: proc.h:61
#define PROC_AFFECTS_ALL_HORIZONS
Definition: proc.h:62
#define PROC_IN_VACUUM
Definition: proc.h:58
#define UINT32_ACCESS_ONCE(var)
Definition: procarray.c:70
static void GlobalVisUpdateApply(ComputeXidHorizonsResult *horizons)
Definition: procarray.c:4145
static TransactionId KnownAssignedXidsGetOldestXmin(void)
Definition: procarray.c:5162
PGPROC * MyProc
Definition: proc.c:67
TransactionId slot_catalog_xmin
Definition: procarray.c:194
TransactionId data_oldest_nonremovable
Definition: procarray.c:239
TransactionId temp_oldest_nonremovable
Definition: procarray.c:245
TransactionId shared_oldest_nonremovable
Definition: procarray.c:216
TransactionId oldest_considered_running
Definition: procarray.c:207
TransactionId slot_xmin
Definition: procarray.c:193
FullTransactionId latest_completed
Definition: procarray.c:187
TransactionId catalog_oldest_nonremovable
Definition: procarray.c:233
TransactionId shared_oldest_nonremovable_raw
Definition: procarray.c:227
TransactionId xmin
Definition: proc.h:194
TransactionId xid
Definition: proc.h:189
uint8 * statusFlags
Definition: proc.h:403
TransactionId replication_slot_xmin
Definition: procarray.c:96
TransactionId replication_slot_catalog_xmin
Definition: procarray.c:98
FullTransactionId latestCompletedXid
Definition: transam.h:238
static bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.h:282
#define XidFromFullTransactionId(x)
Definition: transam.h:48
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define TransactionIdAdvance(dest)
Definition: transam.h:91
static TransactionId TransactionIdOlder(TransactionId a, TransactionId b)
Definition: transam.h:396
TransamVariablesData * TransamVariables
Definition: varsup.c:34
bool RecoveryInProgress(void)
Definition: xlog.c:6461

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

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

◆ CountDBBackends()

int CountDBBackends ( Oid  databaseid)

Definition at line 3561 of file procarray.c.

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 (!OidIsValid(databaseid) ||
3577 proc->databaseId == databaseid)
3578 count++;
3579 }
3580
3581 LWLockRelease(ProcArrayLock);
3582
3583 return count;
3584}
#define OidIsValid(objectId)
Definition: c.h:794

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

Referenced by ResolveRecoveryConflictWithDatabase().

◆ CountDBConnections()

int CountDBConnections ( Oid  databaseid)

Definition at line 3590 of file procarray.c.

3591{
3592 ProcArrayStruct *arrayP = procArray;
3593 int count = 0;
3594 int index;
3595
3596 LWLockAcquire(ProcArrayLock, LW_SHARED);
3597
3598 for (index = 0; index < arrayP->numProcs; index++)
3599 {
3600 int pgprocno = arrayP->pgprocnos[index];
3601 PGPROC *proc = &allProcs[pgprocno];
3602
3603 if (proc->pid == 0)
3604 continue; /* do not count prepared xacts */
3605 if (!proc->isRegularBackend)
3606 continue; /* count only regular backend processes */
3607 if (!OidIsValid(databaseid) ||
3608 proc->databaseId == databaseid)
3609 count++;
3610 }
3611
3612 LWLockRelease(ProcArrayLock);
3613
3614 return count;
3615}
bool isRegularBackend
Definition: proc.h:230

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

Referenced by CheckMyDatabase().

◆ CountOtherDBBackends()

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

Definition at line 3714 of file procarray.c.

3715{
3716 ProcArrayStruct *arrayP = procArray;
3717
3718#define MAXAUTOVACPIDS 10 /* max autovacs to SIGTERM per iteration */
3719 int autovac_pids[MAXAUTOVACPIDS];
3720
3721 /*
3722 * Retry up to 50 times with 100ms between attempts (max 5s total). Can be
3723 * reduced to 3 attempts (max 0.3s total) to speed up tests.
3724 */
3725 int ntries = 50;
3726
3727#ifdef USE_INJECTION_POINTS
3728 if (IS_INJECTION_POINT_ATTACHED("procarray-reduce-count"))
3729 ntries = 3;
3730#endif
3731
3732 for (int tries = 0; tries < ntries; tries++)
3733 {
3734 int nautovacs = 0;
3735 bool found = false;
3736 int index;
3737
3739
3740 *nbackends = *nprepared = 0;
3741
3742 LWLockAcquire(ProcArrayLock, LW_SHARED);
3743
3744 for (index = 0; index < arrayP->numProcs; index++)
3745 {
3746 int pgprocno = arrayP->pgprocnos[index];
3747 PGPROC *proc = &allProcs[pgprocno];
3748 uint8 statusFlags = ProcGlobal->statusFlags[index];
3749
3750 if (proc->databaseId != databaseId)
3751 continue;
3752 if (proc == MyProc)
3753 continue;
3754
3755 found = true;
3756
3757 if (proc->pid == 0)
3758 (*nprepared)++;
3759 else
3760 {
3761 (*nbackends)++;
3762 if ((statusFlags & PROC_IS_AUTOVACUUM) &&
3763 nautovacs < MAXAUTOVACPIDS)
3764 autovac_pids[nautovacs++] = proc->pid;
3765 }
3766 }
3767
3768 LWLockRelease(ProcArrayLock);
3769
3770 if (!found)
3771 return false; /* no conflicting backends, so done */
3772
3773 /*
3774 * Send SIGTERM to any conflicting autovacuums before sleeping. We
3775 * postpone this step until after the loop because we don't want to
3776 * hold ProcArrayLock while issuing kill(). We have no idea what might
3777 * block kill() inside the kernel...
3778 */
3779 for (index = 0; index < nautovacs; index++)
3780 (void) kill(autovac_pids[index], SIGTERM); /* ignore any error */
3781
3782 /*
3783 * Terminate all background workers for this database, if they have
3784 * requested it (BGWORKER_INTERRUPTIBLE).
3785 */
3787
3788 /* sleep, then try again */
3789 pg_usleep(100 * 1000L); /* 100ms */
3790 }
3791
3792 return true; /* timed out, still conflicts */
3793}
void TerminateBackgroundWorkersForDatabase(Oid databaseId)
Definition: bgworker.c:1420
uint8_t uint8
Definition: c.h:550
#define IS_INJECTION_POINT_ATTACHED(name)
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:123
#define PROC_IS_AUTOVACUUM
Definition: proc.h:57
#define MAXAUTOVACPIDS
void pg_usleep(long microsec)
Definition: signal.c:53
#define kill(pid, sig)
Definition: win32_port.h:490

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

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

◆ CountUserBackends()

int CountUserBackends ( Oid  roleid)

Definition at line 3662 of file procarray.c.

3663{
3664 ProcArrayStruct *arrayP = procArray;
3665 int count = 0;
3666 int index;
3667
3668 LWLockAcquire(ProcArrayLock, LW_SHARED);
3669
3670 for (index = 0; index < arrayP->numProcs; index++)
3671 {
3672 int pgprocno = arrayP->pgprocnos[index];
3673 PGPROC *proc = &allProcs[pgprocno];
3674
3675 if (proc->pid == 0)
3676 continue; /* do not count prepared xacts */
3677 if (!proc->isRegularBackend)
3678 continue; /* count only regular backend processes */
3679 if (proc->roleId == roleid)
3680 count++;
3681 }
3682
3683 LWLockRelease(ProcArrayLock);
3684
3685 return count;
3686}
Oid roleId
Definition: proc.h:225

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

Referenced by InitializeSessionUserId().

◆ ExpireAllKnownAssignedTransactionIds()

void ExpireAllKnownAssignedTransactionIds ( void  )

Definition at line 4477 of file procarray.c.

4478{
4479 FullTransactionId latestXid;
4480
4481 LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4483
4484 /* Reset latestCompletedXid to nextXid - 1 */
4486 latestXid = TransamVariables->nextXid;
4487 FullTransactionIdRetreat(&latestXid);
4489
4490 /*
4491 * Any transactions that were in-progress were effectively aborted, so
4492 * advance xactCompletionCount.
4493 */
4495
4496 /*
4497 * Reset lastOverflowedXid. Currently, lastOverflowedXid has no use after
4498 * the call of this function. But do this for unification with what
4499 * ExpireOldKnownAssignedTransactionIds() do.
4500 */
4502 LWLockRelease(ProcArrayLock);
4503}
static void KnownAssignedXidsRemovePreceding(TransactionId removeXid)
Definition: procarray.c:5014
TransactionId lastOverflowedXid
Definition: procarray.c:93
FullTransactionId nextXid
Definition: transam.h:220
uint64 xactCompletionCount
Definition: transam.h:248
static void FullTransactionIdRetreat(FullTransactionId *dest)
Definition: transam.h:103
#define FullTransactionIdIsValid(x)
Definition: transam.h:55

References Assert(), FullTransactionIdIsValid, FullTransactionIdRetreat(), InvalidTransactionId, KnownAssignedXidsRemovePreceding(), ProcArrayStruct::lastOverflowedXid, TransamVariablesData::latestCompletedXid, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), TransamVariablesData::nextXid, procArray, TransamVariables, and TransamVariablesData::xactCompletionCount.

Referenced by ShutdownRecoveryTransactionEnvironment().

◆ ExpireOldKnownAssignedTransactionIds()

void ExpireOldKnownAssignedTransactionIds ( TransactionId  xid)

Definition at line 4511 of file procarray.c.

4512{
4513 TransactionId latestXid;
4514
4515 LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4516
4517 /* As in ProcArrayEndTransaction, advance latestCompletedXid */
4518 latestXid = xid;
4519 TransactionIdRetreat(latestXid);
4521
4522 /* ... and xactCompletionCount */
4524
4525 /*
4526 * Reset lastOverflowedXid if we know all transactions that have been
4527 * possibly running are being gone. Not doing so could cause an incorrect
4528 * lastOverflowedXid value, which makes extra snapshots be marked as
4529 * suboverflowed.
4530 */
4534 LWLockRelease(ProcArrayLock);
4535}
static void MaintainLatestCompletedXidRecovery(TransactionId latestXid)
Definition: procarray.c:991
#define TransactionIdRetreat(dest)
Definition: transam.h:141
static bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.h:263

References InvalidTransactionId, KnownAssignedXidsRemovePreceding(), ProcArrayStruct::lastOverflowedXid, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MaintainLatestCompletedXidRecovery(), procArray, TransactionIdPrecedes(), TransactionIdRetreat, TransamVariables, and TransamVariablesData::xactCompletionCount.

Referenced by ProcArrayApplyRecoveryInfo().

◆ ExpireTreeKnownAssignedTransactionIds()

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

Definition at line 4451 of file procarray.c.

4453{
4455
4456 /*
4457 * Uses same locking as transaction commit
4458 */
4459 LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4460
4461 KnownAssignedXidsRemoveTree(xid, nsubxids, subxids);
4462
4463 /* As in ProcArrayEndTransaction, advance latestCompletedXid */
4465
4466 /* ... and xactCompletionCount */
4468
4469 LWLockRelease(ProcArrayLock);
4470}
static void KnownAssignedXidsRemoveTree(TransactionId xid, int nsubxids, TransactionId *subxids)
Definition: procarray.c:4992
HotStandbyState standbyState
Definition: xlogutils.c:53
@ STANDBY_INITIALIZED
Definition: xlogutils.h:53

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

Referenced by xact_redo_abort(), and xact_redo_commit().

◆ FullXidRelativeTo()

static FullTransactionId FullXidRelativeTo ( FullTransactionId  rel,
TransactionId  xid 
)
inlinestatic

Definition at line 4300 of file procarray.c.

4301{
4303
4305 Assert(TransactionIdIsValid(rel_xid));
4306
4307 /* not guaranteed to find issues, but likely to catch mistakes */
4309
4311 + (int32) (xid - rel_xid));
4312}
int32_t int32
Definition: c.h:548
#define U64FromFullTransactionId(x)
Definition: transam.h:49
static FullTransactionId FullTransactionIdFromU64(uint64 value)
Definition: transam.h:81
#define AssertTransactionIdInAllowableRange(xid)
Definition: transam.h:363

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

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

◆ GetConflictingVirtualXIDs()

VirtualTransactionId * GetConflictingVirtualXIDs ( TransactionId  limitXmin,
Oid  dbOid 
)

Definition at line 3379 of file procarray.c.

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

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

Referenced by ResolveRecoveryConflictWithSnapshot(), and ResolveRecoveryConflictWithTablespace().

◆ GetCurrentVirtualXIDs()

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

Definition at line 3287 of file procarray.c.

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

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

Referenced by WaitForOlderSnapshots().

◆ GetMaxSnapshotSubxidCount()

int GetMaxSnapshotSubxidCount ( void  )

Definition at line 2030 of file procarray.c.

2031{
2033}
#define TOTAL_MAX_CACHED_SUBXIDS

References TOTAL_MAX_CACHED_SUBXIDS.

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

◆ GetMaxSnapshotXidCount()

int GetMaxSnapshotXidCount ( void  )

Definition at line 2019 of file procarray.c.

2020{
2021 return procArray->maxProcs;
2022}

References ProcArrayStruct::maxProcs, and procArray.

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

◆ GetOldestActiveTransactionId()

TransactionId GetOldestActiveTransactionId ( bool  inCommitOnly,
bool  allDbs 
)

Definition at line 2835 of file procarray.c.

2836{
2837 ProcArrayStruct *arrayP = procArray;
2838 TransactionId *other_xids = ProcGlobal->xids;
2839 TransactionId oldestRunningXid;
2840 int index;
2841
2843
2844 /*
2845 * Read nextXid, as the upper bound of what's still active.
2846 *
2847 * Reading a TransactionId is atomic, but we must grab the lock to make
2848 * sure that all XIDs < nextXid are already present in the proc array (or
2849 * have already completed), when we spin over it.
2850 */
2851 LWLockAcquire(XidGenLock, LW_SHARED);
2853 LWLockRelease(XidGenLock);
2854
2855 /*
2856 * Spin over procArray collecting all xids and subxids.
2857 */
2858 LWLockAcquire(ProcArrayLock, LW_SHARED);
2859 for (index = 0; index < arrayP->numProcs; index++)
2860 {
2861 TransactionId xid;
2862 int pgprocno = arrayP->pgprocnos[index];
2863 PGPROC *proc = &allProcs[pgprocno];
2864
2865 /* Fetch xid just once - see GetNewTransactionId */
2866 xid = UINT32_ACCESS_ONCE(other_xids[index]);
2867
2868 if (!TransactionIdIsNormal(xid))
2869 continue;
2870
2871 if (inCommitOnly &&
2873 continue;
2874
2875 if (!allDbs && proc->databaseId != MyDatabaseId)
2876 continue;
2877
2878 if (TransactionIdPrecedes(xid, oldestRunningXid))
2879 oldestRunningXid = xid;
2880
2881 /*
2882 * Top-level XID of a transaction is always less than any of its
2883 * subxids, so we don't need to check if any of the subxids are
2884 * smaller than oldestRunningXid
2885 */
2886 }
2887 LWLockRelease(ProcArrayLock);
2888
2889 return oldestRunningXid;
2890}
#define DELAY_CHKPT_IN_COMMIT
Definition: proc.h:137
int delayChkptFlags
Definition: proc.h:257
#define TransactionIdIsNormal(xid)
Definition: transam.h:42

References allProcs, Assert(), PGPROC::databaseId, DELAY_CHKPT_IN_COMMIT, PGPROC::delayChkptFlags, LW_SHARED, LWLockAcquire(), LWLockRelease(), MyDatabaseId, TransamVariablesData::nextXid, ProcArrayStruct::numProcs, ProcArrayStruct::pgprocnos, procArray, ProcGlobal, RecoveryInProgress(), TransactionIdIsNormal, TransactionIdPrecedes(), TransamVariables, UINT32_ACCESS_ONCE, XidFromFullTransactionId, and PROC_HDR::xids.

Referenced by CreateCheckPoint(), get_candidate_xid(), and ProcessStandbyPSRequestMessage().

◆ GetOldestNonRemovableTransactionId()

TransactionId GetOldestNonRemovableTransactionId ( Relation  rel)

◆ GetOldestSafeDecodingTransactionId()

TransactionId GetOldestSafeDecodingTransactionId ( bool  catalogOnly)

Definition at line 2909 of file procarray.c.

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

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

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

◆ GetOldestTransactionIdConsideredRunning()

TransactionId GetOldestTransactionIdConsideredRunning ( void  )

Definition at line 1984 of file procarray.c.

1985{
1986 ComputeXidHorizonsResult horizons;
1987
1988 ComputeXidHorizons(&horizons);
1989
1990 return horizons.oldest_considered_running;
1991}

References ComputeXidHorizons(), and ComputeXidHorizonsResult::oldest_considered_running.

Referenced by CreateCheckPoint(), and CreateRestartPoint().

◆ GetReplicationHorizons()

void GetReplicationHorizons ( TransactionId xmin,
TransactionId catalog_xmin 
)

Definition at line 1997 of file procarray.c.

1998{
1999 ComputeXidHorizonsResult horizons;
2000
2001 ComputeXidHorizons(&horizons);
2002
2003 /*
2004 * Don't want to use shared_oldest_nonremovable here, as that contains the
2005 * effect of replication slot's catalog_xmin. We want to send a separate
2006 * feedback for the catalog horizon, so the primary can remove data table
2007 * contents more aggressively.
2008 */
2009 *xmin = horizons.shared_oldest_nonremovable_raw;
2010 *catalog_xmin = horizons.slot_catalog_xmin;
2011}

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

Referenced by XLogWalRcvSendHSFeedback().

◆ GetRunningTransactionData()

RunningTransactions GetRunningTransactionData ( void  )

Definition at line 2639 of file procarray.c.

2640{
2641 /* result workspace */
2642 static RunningTransactionsData CurrentRunningXactsData;
2643
2644 ProcArrayStruct *arrayP = procArray;
2645 TransactionId *other_xids = ProcGlobal->xids;
2646 RunningTransactions CurrentRunningXacts = &CurrentRunningXactsData;
2647 TransactionId latestCompletedXid;
2648 TransactionId oldestRunningXid;
2649 TransactionId oldestDatabaseRunningXid;
2650 TransactionId *xids;
2651 int index;
2652 int count;
2653 int subcount;
2654 bool suboverflowed;
2655
2657
2658 /*
2659 * Allocating space for maxProcs xids is usually overkill; numProcs would
2660 * be sufficient. But it seems better to do the malloc while not holding
2661 * the lock, so we can't look at numProcs. Likewise, we allocate much
2662 * more subxip storage than is probably needed.
2663 *
2664 * Should only be allocated in bgwriter, since only ever executed during
2665 * checkpoints.
2666 */
2667 if (CurrentRunningXacts->xids == NULL)
2668 {
2669 /*
2670 * First call
2671 */
2672 CurrentRunningXacts->xids = (TransactionId *)
2674 if (CurrentRunningXacts->xids == NULL)
2675 ereport(ERROR,
2676 (errcode(ERRCODE_OUT_OF_MEMORY),
2677 errmsg("out of memory")));
2678 }
2679
2680 xids = CurrentRunningXacts->xids;
2681
2682 count = subcount = 0;
2683 suboverflowed = false;
2684
2685 /*
2686 * Ensure that no xids enter or leave the procarray while we obtain
2687 * snapshot.
2688 */
2689 LWLockAcquire(ProcArrayLock, LW_SHARED);
2690 LWLockAcquire(XidGenLock, LW_SHARED);
2691
2692 latestCompletedXid =
2694 oldestDatabaseRunningXid = oldestRunningXid =
2696
2697 /*
2698 * Spin over procArray collecting all xids
2699 */
2700 for (index = 0; index < arrayP->numProcs; index++)
2701 {
2702 TransactionId xid;
2703
2704 /* Fetch xid just once - see GetNewTransactionId */
2705 xid = UINT32_ACCESS_ONCE(other_xids[index]);
2706
2707 /*
2708 * We don't need to store transactions that don't have a TransactionId
2709 * yet because they will not show as running on a standby server.
2710 */
2711 if (!TransactionIdIsValid(xid))
2712 continue;
2713
2714 /*
2715 * Be careful not to exclude any xids before calculating the values of
2716 * oldestRunningXid and suboverflowed, since these are used to clean
2717 * up transaction information held on standbys.
2718 */
2719 if (TransactionIdPrecedes(xid, oldestRunningXid))
2720 oldestRunningXid = xid;
2721
2722 /*
2723 * Also, update the oldest running xid within the current database. As
2724 * fetching pgprocno and PGPROC could cause cache misses, we do cheap
2725 * TransactionId comparison first.
2726 */
2727 if (TransactionIdPrecedes(xid, oldestDatabaseRunningXid))
2728 {
2729 int pgprocno = arrayP->pgprocnos[index];
2730 PGPROC *proc = &allProcs[pgprocno];
2731
2732 if (proc->databaseId == MyDatabaseId)
2733 oldestDatabaseRunningXid = xid;
2734 }
2735
2737 suboverflowed = true;
2738
2739 /*
2740 * If we wished to exclude xids this would be the right place for it.
2741 * Procs with the PROC_IN_VACUUM flag set don't usually assign xids,
2742 * but they do during truncation at the end when they get the lock and
2743 * truncate, so it is not much of a problem to include them if they
2744 * are seen and it is cleaner to include them.
2745 */
2746
2747 xids[count++] = xid;
2748 }
2749
2750 /*
2751 * Spin over procArray collecting all subxids, but only if there hasn't
2752 * been a suboverflow.
2753 */
2754 if (!suboverflowed)
2755 {
2756 XidCacheStatus *other_subxidstates = ProcGlobal->subxidStates;
2757
2758 for (index = 0; index < arrayP->numProcs; index++)
2759 {
2760 int pgprocno = arrayP->pgprocnos[index];
2761 PGPROC *proc = &allProcs[pgprocno];
2762 int nsubxids;
2763
2764 /*
2765 * Save subtransaction XIDs. Other backends can't add or remove
2766 * entries while we're holding XidGenLock.
2767 */
2768 nsubxids = other_subxidstates[index].count;
2769 if (nsubxids > 0)
2770 {
2771 /* barrier not really required, as XidGenLock is held, but ... */
2772 pg_read_barrier(); /* pairs with GetNewTransactionId */
2773
2774 memcpy(&xids[count], proc->subxids.xids,
2775 nsubxids * sizeof(TransactionId));
2776 count += nsubxids;
2777 subcount += nsubxids;
2778
2779 /*
2780 * Top-level XID of a transaction is always less than any of
2781 * its subxids, so we don't need to check if any of the
2782 * subxids are smaller than oldestRunningXid
2783 */
2784 }
2785 }
2786 }
2787
2788 /*
2789 * It's important *not* to include the limits set by slots here because
2790 * snapbuild.c uses oldestRunningXid to manage its xmin horizon. If those
2791 * were to be included here the initial value could never increase because
2792 * of a circular dependency where slots only increase their limits when
2793 * running xacts increases oldestRunningXid and running xacts only
2794 * increases if slots do.
2795 */
2796
2797 CurrentRunningXacts->xcnt = count - subcount;
2798 CurrentRunningXacts->subxcnt = subcount;
2799 CurrentRunningXacts->subxid_status = suboverflowed ? SUBXIDS_IN_SUBTRANS : SUBXIDS_IN_ARRAY;
2801 CurrentRunningXacts->oldestRunningXid = oldestRunningXid;
2802 CurrentRunningXacts->oldestDatabaseRunningXid = oldestDatabaseRunningXid;
2803 CurrentRunningXacts->latestCompletedXid = latestCompletedXid;
2804
2805 Assert(TransactionIdIsValid(CurrentRunningXacts->nextXid));
2806 Assert(TransactionIdIsValid(CurrentRunningXacts->oldestRunningXid));
2807 Assert(TransactionIdIsNormal(CurrentRunningXacts->latestCompletedXid));
2808
2809 /* We don't release the locks here, the caller is responsible for that */
2810
2811 return CurrentRunningXacts;
2812}
#define pg_read_barrier()
Definition: atomics.h:154
@ SUBXIDS_IN_SUBTRANS
Definition: standby.h:82
@ SUBXIDS_IN_ARRAY
Definition: standby.h:80
struct XidCache subxids
Definition: proc.h:282
XidCacheStatus * subxidStates
Definition: proc.h:397
TransactionId oldestRunningXid
Definition: standby.h:92
TransactionId nextXid
Definition: standby.h:91
TransactionId oldestDatabaseRunningXid
Definition: standby.h:93
TransactionId latestCompletedXid
Definition: standby.h:95
subxids_array_status subxid_status
Definition: standby.h:90
TransactionId * xids
Definition: standby.h:97
bool overflowed
Definition: proc.h:46
uint8 count
Definition: proc.h:44
TransactionId xids[PGPROC_MAX_CACHED_SUBXIDS]
Definition: proc.h:51

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

Referenced by GetStrictOldestNonRemovableTransactionId(), and LogStandbySnapshot().

◆ GetSnapshotData()

Snapshot GetSnapshotData ( Snapshot  snapshot)

Definition at line 2125 of file procarray.c.

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

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

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

◆ GetSnapshotDataReuse()

static bool GetSnapshotDataReuse ( Snapshot  snapshot)
static

Definition at line 2045 of file procarray.c.

2046{
2047 uint64 curXactCompletionCount;
2048
2049 Assert(LWLockHeldByMe(ProcArrayLock));
2050
2051 if (unlikely(snapshot->snapXactCompletionCount == 0))
2052 return false;
2053
2054 curXactCompletionCount = TransamVariables->xactCompletionCount;
2055 if (curXactCompletionCount != snapshot->snapXactCompletionCount)
2056 return false;
2057
2058 /*
2059 * If the current xactCompletionCount is still the same as it was at the
2060 * time the snapshot was built, we can be sure that rebuilding the
2061 * contents of the snapshot the hard way would result in the same snapshot
2062 * contents:
2063 *
2064 * As explained in transam/README, the set of xids considered running by
2065 * GetSnapshotData() cannot change while ProcArrayLock is held. Snapshot
2066 * contents only depend on transactions with xids and xactCompletionCount
2067 * is incremented whenever a transaction with an xid finishes (while
2068 * holding ProcArrayLock exclusively). Thus the xactCompletionCount check
2069 * ensures we would detect if the snapshot would have changed.
2070 *
2071 * As the snapshot contents are the same as it was before, it is safe to
2072 * re-enter the snapshot's xmin into the PGPROC array. None of the rows
2073 * visible under the snapshot could already have been removed (that'd
2074 * require the set of running transactions to change) and it fulfills the
2075 * requirement that concurrent GetSnapshotData() calls yield the same
2076 * xmin.
2077 */
2079 MyProc->xmin = TransactionXmin = snapshot->xmin;
2080
2081 RecentXmin = snapshot->xmin;
2083
2084 snapshot->curcid = GetCurrentCommandId(false);
2085 snapshot->active_count = 0;
2086 snapshot->regd_count = 0;
2087 snapshot->copied = false;
2088
2089 return true;
2090}
#define unlikely(x)
Definition: c.h:418

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

Referenced by GetSnapshotData().

◆ GetVirtualXIDsDelayingChkpt()

VirtualTransactionId * GetVirtualXIDsDelayingChkpt ( int *  nvxids,
int  type 
)

Definition at line 3007 of file procarray.c.

3008{
3009 VirtualTransactionId *vxids;
3010 ProcArrayStruct *arrayP = procArray;
3011 int count = 0;
3012 int index;
3013
3014 Assert(type != 0);
3015
3016 /* allocate what's certainly enough result space */
3017 vxids = palloc_array(VirtualTransactionId, arrayP->maxProcs);
3018
3019 LWLockAcquire(ProcArrayLock, LW_SHARED);
3020
3021 for (index = 0; index < arrayP->numProcs; index++)
3022 {
3023 int pgprocno = arrayP->pgprocnos[index];
3024 PGPROC *proc = &allProcs[pgprocno];
3025
3026 if ((proc->delayChkptFlags & type) != 0)
3027 {
3029
3030 GET_VXID_FROM_PGPROC(vxid, *proc);
3032 vxids[count++] = vxid;
3033 }
3034 }
3035
3036 LWLockRelease(ProcArrayLock);
3037
3038 *nvxids = count;
3039 return vxids;
3040}
const char * type

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

Referenced by CreateCheckPoint().

◆ GlobalVisCheckRemovableFullXid()

bool GlobalVisCheckRemovableFullXid ( Relation  rel,
FullTransactionId  fxid 
)

Definition at line 4265 of file procarray.c.

4266{
4268
4269 state = GlobalVisTestFor(rel);
4270
4272}
bool GlobalVisTestIsRemovableFullXid(GlobalVisState *state, FullTransactionId fxid)
Definition: procarray.c:4201
GlobalVisState * GlobalVisTestFor(Relation rel)
Definition: procarray.c:4086
Definition: regguts.h:323

References GlobalVisTestFor(), and GlobalVisTestIsRemovableFullXid().

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

◆ GlobalVisCheckRemovableXid()

bool GlobalVisCheckRemovableXid ( Relation  rel,
TransactionId  xid 
)

Definition at line 4279 of file procarray.c.

4280{
4282
4283 state = GlobalVisTestFor(rel);
4284
4286}
bool GlobalVisTestIsRemovableXid(GlobalVisState *state, TransactionId xid)
Definition: procarray.c:4243

References GlobalVisTestFor(), and GlobalVisTestIsRemovableXid().

Referenced by GinPageIsRecyclable().

◆ GlobalVisHorizonKindForRel()

static GlobalVisHorizonKind GlobalVisHorizonKindForRel ( Relation  rel)
inlinestatic

Definition at line 1921 of file procarray.c.

1922{
1923 /*
1924 * Other relkinds currently don't contain xids, nor always the necessary
1925 * logical decoding markers.
1926 */
1927 Assert(!rel ||
1928 rel->rd_rel->relkind == RELKIND_RELATION ||
1929 rel->rd_rel->relkind == RELKIND_MATVIEW ||
1930 rel->rd_rel->relkind == RELKIND_TOASTVALUE);
1931
1932 if (rel == NULL || rel->rd_rel->relisshared || RecoveryInProgress())
1933 return VISHORIZON_SHARED;
1934 else if (IsCatalogRelation(rel) ||
1936 return VISHORIZON_CATALOG;
1937 else if (!RELATION_IS_LOCAL(rel))
1938 return VISHORIZON_DATA;
1939 else
1940 return VISHORIZON_TEMP;
1941}
bool IsCatalogRelation(Relation relation)
Definition: catalog.c:104
#define RELATION_IS_LOCAL(relation)
Definition: rel.h:658
#define RelationIsAccessibleInLogicalDecoding(relation)
Definition: rel.h:694
Form_pg_class rd_rel
Definition: rel.h:111

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

Referenced by GetOldestNonRemovableTransactionId(), and GlobalVisTestFor().

◆ GlobalVisTestFor()

GlobalVisState * GlobalVisTestFor ( Relation  rel)

◆ GlobalVisTestIsRemovableFullXid()

bool GlobalVisTestIsRemovableFullXid ( GlobalVisState state,
FullTransactionId  fxid 
)

Definition at line 4201 of file procarray.c.

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

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

Referenced by GlobalVisCheckRemovableFullXid(), and GlobalVisTestIsRemovableXid().

◆ GlobalVisTestIsRemovableXid()

bool GlobalVisTestIsRemovableXid ( GlobalVisState state,
TransactionId  xid 
)

Definition at line 4243 of file procarray.c.

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

References FullXidRelativeTo(), and GlobalVisTestIsRemovableFullXid().

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

◆ GlobalVisTestShouldUpdate()

static bool GlobalVisTestShouldUpdate ( GlobalVisState state)
static

Definition at line 4126 of file procarray.c.

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

References ComputeXidHorizonsResultLastXmin, FullTransactionIdFollowsOrEquals, RecentXmin, and TransactionIdIsValid.

Referenced by GlobalVisTestIsRemovableFullXid().

◆ GlobalVisUpdate()

static void GlobalVisUpdate ( void  )
static

Definition at line 4184 of file procarray.c.

4185{
4186 ComputeXidHorizonsResult horizons;
4187
4188 /* updates the horizons as a side-effect */
4189 ComputeXidHorizons(&horizons);
4190}

References ComputeXidHorizons().

Referenced by GlobalVisTestIsRemovableFullXid().

◆ GlobalVisUpdateApply()

static void GlobalVisUpdateApply ( ComputeXidHorizonsResult horizons)
static

Definition at line 4145 of file procarray.c.

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

Referenced by ComputeXidHorizons().

◆ HaveVirtualXIDsDelayingChkpt()

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

Definition at line 3052 of file procarray.c.

3053{
3054 bool result = false;
3055 ProcArrayStruct *arrayP = procArray;
3056 int index;
3057
3058 Assert(type != 0);
3059
3060 LWLockAcquire(ProcArrayLock, LW_SHARED);
3061
3062 for (index = 0; index < arrayP->numProcs; index++)
3063 {
3064 int pgprocno = arrayP->pgprocnos[index];
3065 PGPROC *proc = &allProcs[pgprocno];
3067
3068 GET_VXID_FROM_PGPROC(vxid, *proc);
3069
3070 if ((proc->delayChkptFlags & type) != 0 &&
3072 {
3073 int i;
3074
3075 for (i = 0; i < nvxids; i++)
3076 {
3077 if (VirtualTransactionIdEquals(vxid, vxids[i]))
3078 {
3079 result = true;
3080 break;
3081 }
3082 }
3083 if (result)
3084 break;
3085 }
3086 }
3087
3088 LWLockRelease(ProcArrayLock);
3089
3090 return result;
3091}
int i
Definition: isn.c:77
#define VirtualTransactionIdEquals(vxid1, vxid2)
Definition: lock.h:73

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

Referenced by CreateCheckPoint().

◆ IsBackendPid()

bool IsBackendPid ( int  pid)

Definition at line 3254 of file procarray.c.

3255{
3256 return (BackendPidGetProc(pid) != NULL);
3257}
PGPROC * BackendPidGetProc(int pid)
Definition: procarray.c:3159

References BackendPidGetProc().

Referenced by pg_stat_get_subscription().

◆ KnownAssignedTransactionIdsIdleMaintenance()

void KnownAssignedTransactionIdsIdleMaintenance ( void  )

Definition at line 4543 of file procarray.c.

4544{
4546}
static void KnownAssignedXidsCompress(KAXCompressReason reason, bool haveLock)
Definition: procarray.c:4644

References KAX_STARTUP_PROCESS_IDLE, and KnownAssignedXidsCompress().

Referenced by WaitForWALToBecomeAvailable().

◆ KnownAssignedXidExists()

static bool KnownAssignedXidExists ( TransactionId  xid)
static

Definition at line 4953 of file procarray.c.

4954{
4956
4957 return KnownAssignedXidsSearch(xid, false);
4958}
static bool KnownAssignedXidsSearch(TransactionId xid, bool remove)
Definition: procarray.c:4865

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

Referenced by TransactionIdIsInProgress().

◆ KnownAssignedXidsAdd()

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

Definition at line 4761 of file procarray.c.

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

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

Referenced by ProcArrayApplyRecoveryInfo(), and RecordKnownAssignedTransactionIds().

◆ KnownAssignedXidsCompress()

static void KnownAssignedXidsCompress ( KAXCompressReason  reason,
bool  haveLock 
)
static

Definition at line 4644 of file procarray.c.

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

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

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

◆ KnownAssignedXidsDisplay()

static void KnownAssignedXidsDisplay ( int  trace_level)
static

Definition at line 5197 of file procarray.c.

5198{
5199 ProcArrayStruct *pArray = procArray;
5201 int head,
5202 tail,
5203 i;
5204 int nxids = 0;
5205
5206 tail = pArray->tailKnownAssignedXids;
5207 head = pArray->headKnownAssignedXids;
5208
5210
5211 for (i = tail; i < head; i++)
5212 {
5214 {
5215 nxids++;
5216 appendStringInfo(&buf, "[%d]=%u ", i, KnownAssignedXids[i]);
5217 }
5218 }
5219
5220 elog(trace_level, "%d KnownAssignedXids (num=%d tail=%d head=%d) %s",
5221 nxids,
5222 pArray->numKnownAssignedXids,
5223 pArray->tailKnownAssignedXids,
5224 pArray->headKnownAssignedXids,
5225 buf.data);
5226
5227 pfree(buf.data);
5228}
void pfree(void *pointer)
Definition: mcxt.c:1616
static char buf[DEFAULT_XLOG_SEG_SIZE]
Definition: pg_test_fsync.c:71
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:145
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97

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

Referenced by KnownAssignedXidsAdd(), and ProcArrayApplyRecoveryInfo().

◆ KnownAssignedXidsGet()

static int KnownAssignedXidsGet ( TransactionId xarray,
TransactionId  xmax 
)
static

Definition at line 5092 of file procarray.c.

5093{
5095
5096 return KnownAssignedXidsGetAndSetXmin(xarray, &xtmp, xmax);
5097}

References InvalidTransactionId, and KnownAssignedXidsGetAndSetXmin().

Referenced by TransactionIdIsInProgress().

◆ KnownAssignedXidsGetAndSetXmin()

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

Definition at line 5106 of file procarray.c.

5108{
5109 int count = 0;
5110 int head,
5111 tail;
5112 int i;
5113
5114 /*
5115 * Fetch head just once, since it may change while we loop. We can stop
5116 * once we reach the initially seen head, since we are certain that an xid
5117 * cannot enter and then leave the array while we hold ProcArrayLock. We
5118 * might miss newly-added xids, but they should be >= xmax so irrelevant
5119 * anyway.
5120 */
5123
5124 pg_read_barrier(); /* pairs with KnownAssignedXidsAdd */
5125
5126 for (i = tail; i < head; i++)
5127 {
5128 /* Skip any gaps in the array */
5130 {
5131 TransactionId knownXid = KnownAssignedXids[i];
5132
5133 /*
5134 * Update xmin if required. Only the first XID need be checked,
5135 * since the array is sorted.
5136 */
5137 if (count == 0 &&
5138 TransactionIdPrecedes(knownXid, *xmin))
5139 *xmin = knownXid;
5140
5141 /*
5142 * Filter out anything >= xmax, again relying on sorted property
5143 * of array.
5144 */
5145 if (TransactionIdIsValid(xmax) &&
5146 TransactionIdFollowsOrEquals(knownXid, xmax))
5147 break;
5148
5149 /* Add knownXid into output array */
5150 xarray[count++] = knownXid;
5151 }
5152 }
5153
5154 return count;
5155}

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

Referenced by GetSnapshotData(), and KnownAssignedXidsGet().

◆ KnownAssignedXidsGetOldestXmin()

static TransactionId KnownAssignedXidsGetOldestXmin ( void  )
static

Definition at line 5162 of file procarray.c.

5163{
5164 int head,
5165 tail;
5166 int i;
5167
5168 /*
5169 * Fetch head just once, since it may change while we loop.
5170 */
5173
5174 pg_read_barrier(); /* pairs with KnownAssignedXidsAdd */
5175
5176 for (i = tail; i < head; i++)
5177 {
5178 /* Skip any gaps in the array */
5180 return KnownAssignedXids[i];
5181 }
5182
5183 return InvalidTransactionId;
5184}

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

Referenced by ComputeXidHorizons().

◆ KnownAssignedXidsRemove()

static void KnownAssignedXidsRemove ( TransactionId  xid)
static

Definition at line 4966 of file procarray.c.

4967{
4969
4970 elog(DEBUG4, "remove KnownAssignedXid %u", xid);
4971
4972 /*
4973 * Note: we cannot consider it an error to remove an XID that's not
4974 * present. We intentionally remove subxact IDs while processing
4975 * XLOG_XACT_ASSIGNMENT, to avoid array overflow. Then those XIDs will be
4976 * removed again when the top-level xact commits or aborts.
4977 *
4978 * It might be possible to track such XIDs to distinguish this case from
4979 * actual errors, but it would be complicated and probably not worth it.
4980 * So, just ignore the search result.
4981 */
4982 (void) KnownAssignedXidsSearch(xid, true);
4983}
#define DEBUG4
Definition: elog.h:27

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

Referenced by KnownAssignedXidsRemoveTree().

◆ KnownAssignedXidsRemovePreceding()

static void KnownAssignedXidsRemovePreceding ( TransactionId  removeXid)
static

Definition at line 5014 of file procarray.c.

5015{
5016 ProcArrayStruct *pArray = procArray;
5017 int count = 0;
5018 int head,
5019 tail,
5020 i;
5021
5022 if (!TransactionIdIsValid(removeXid))
5023 {
5024 elog(DEBUG4, "removing all KnownAssignedXids");
5025 pArray->numKnownAssignedXids = 0;
5026 pArray->headKnownAssignedXids = pArray->tailKnownAssignedXids = 0;
5027 return;
5028 }
5029
5030 elog(DEBUG4, "prune KnownAssignedXids to %u", removeXid);
5031
5032 /*
5033 * Mark entries invalid starting at the tail. Since array is sorted, we
5034 * can stop as soon as we reach an entry >= removeXid.
5035 */
5036 tail = pArray->tailKnownAssignedXids;
5037 head = pArray->headKnownAssignedXids;
5038
5039 for (i = tail; i < head; i++)
5040 {
5042 {
5043 TransactionId knownXid = KnownAssignedXids[i];
5044
5045 if (TransactionIdFollowsOrEquals(knownXid, removeXid))
5046 break;
5047
5048 if (!StandbyTransactionIdIsPrepared(knownXid))
5049 {
5050 KnownAssignedXidsValid[i] = false;
5051 count++;
5052 }
5053 }
5054 }
5055
5056 pArray->numKnownAssignedXids -= count;
5057 Assert(pArray->numKnownAssignedXids >= 0);
5058
5059 /*
5060 * Advance the tail pointer if we've marked the tail item invalid.
5061 */
5062 for (i = tail; i < head; i++)
5063 {
5065 break;
5066 }
5067 if (i >= head)
5068 {
5069 /* Array is empty, so we can reset both pointers */
5070 pArray->headKnownAssignedXids = 0;
5071 pArray->tailKnownAssignedXids = 0;
5072 }
5073 else
5074 {
5075 pArray->tailKnownAssignedXids = i;
5076 }
5077
5078 /* Opportunistically compress the array */
5080}
bool StandbyTransactionIdIsPrepared(TransactionId xid)
Definition: twophase.c:1467

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

Referenced by ExpireAllKnownAssignedTransactionIds(), and ExpireOldKnownAssignedTransactionIds().

◆ KnownAssignedXidsRemoveTree()

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

Definition at line 4992 of file procarray.c.

4994{
4995 int i;
4996
4997 if (TransactionIdIsValid(xid))
4999
5000 for (i = 0; i < nsubxids; i++)
5001 KnownAssignedXidsRemove(subxids[i]);
5002
5003 /* Opportunistically compress the array */
5005}
static void KnownAssignedXidsRemove(TransactionId xid)
Definition: procarray.c:4966

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

Referenced by ExpireTreeKnownAssignedTransactionIds(), and ProcArrayApplyXidAssignment().

◆ KnownAssignedXidsReset()

static void KnownAssignedXidsReset ( void  )
static

Definition at line 5235 of file procarray.c.

5236{
5237 ProcArrayStruct *pArray = procArray;
5238
5239 LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
5240
5241 pArray->numKnownAssignedXids = 0;
5242 pArray->tailKnownAssignedXids = 0;
5243 pArray->headKnownAssignedXids = 0;
5244
5245 LWLockRelease(ProcArrayLock);
5246}

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

Referenced by ProcArrayApplyRecoveryInfo().

◆ KnownAssignedXidsSearch()

static bool KnownAssignedXidsSearch ( TransactionId  xid,
bool  remove 
)
static

Definition at line 4865 of file procarray.c.

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

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

Referenced by KnownAssignedXidExists(), and KnownAssignedXidsRemove().

◆ MaintainLatestCompletedXid()

◆ MaintainLatestCompletedXidRecovery()

static void MaintainLatestCompletedXidRecovery ( TransactionId  latestXid)
static

Definition at line 991 of file procarray.c.

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

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

Referenced by ExpireOldKnownAssignedTransactionIds(), ExpireTreeKnownAssignedTransactionIds(), and ProcArrayApplyRecoveryInfo().

◆ MinimumActiveBackends()

bool MinimumActiveBackends ( int  min)

Definition at line 3508 of file procarray.c.

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

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

Referenced by XLogFlush().

◆ ProcArrayAdd()

void ProcArrayAdd ( PGPROC proc)

Definition at line 470 of file procarray.c.

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

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

Referenced by InitProcessPhase2(), and MarkAsPrepared().

◆ ProcArrayApplyRecoveryInfo()

void ProcArrayApplyRecoveryInfo ( RunningTransactions  running)

Definition at line 1056 of file procarray.c.

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

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

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

◆ ProcArrayApplyXidAssignment()

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

Definition at line 1320 of file procarray.c.

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

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

Referenced by xact_redo().

◆ ProcArrayClearTransaction()

void ProcArrayClearTransaction ( PGPROC proc)

Definition at line 909 of file procarray.c.

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

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

Referenced by PrepareTransaction().

◆ ProcArrayEndTransaction()

void ProcArrayEndTransaction ( PGPROC proc,
TransactionId  latestXid 
)

Definition at line 669 of file procarray.c.

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

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

Referenced by AbortTransaction(), and CommitTransaction().

◆ ProcArrayEndTransactionInternal()

static void ProcArrayEndTransactionInternal ( PGPROC proc,
TransactionId  latestXid 
)
inlinestatic

Definition at line 733 of file procarray.c.

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

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

Referenced by ProcArrayEndTransaction(), and ProcArrayGroupClearXid().

◆ ProcArrayGetReplicationSlotXmin()

void ProcArrayGetReplicationSlotXmin ( TransactionId xmin,
TransactionId catalog_xmin 
)

Definition at line 3947 of file procarray.c.

3949{
3950 LWLockAcquire(ProcArrayLock, LW_SHARED);
3951
3952 if (xmin != NULL)
3954
3955 if (catalog_xmin != NULL)
3957
3958 LWLockRelease(ProcArrayLock);
3959}

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

Referenced by logical_begin_heap_rewrite().

◆ ProcArrayGroupClearXid()

static void ProcArrayGroupClearXid ( PGPROC proc,
TransactionId  latestXid 
)
static

Definition at line 794 of file procarray.c.

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

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

Referenced by ProcArrayEndTransaction().

◆ ProcArrayInitRecovery()

void ProcArrayInitRecovery ( TransactionId  initializedUptoXID)

Definition at line 1025 of file procarray.c.

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

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

Referenced by StartupXLOG().

◆ ProcArrayInstallImportedXmin()

bool ProcArrayInstallImportedXmin ( TransactionId  xmin,
VirtualTransactionId sourcevxid 
)

Definition at line 2482 of file procarray.c.

2484{
2485 bool result = false;
2486 ProcArrayStruct *arrayP = procArray;
2487 int index;
2488
2490 if (!sourcevxid)
2491 return false;
2492
2493 /* Get lock so source xact can't end while we're doing this */
2494 LWLockAcquire(ProcArrayLock, LW_SHARED);
2495
2496 /*
2497 * Find the PGPROC entry of the source transaction. (This could use
2498 * GetPGProcByNumber(), unless it's a prepared xact. But this isn't
2499 * performance critical.)
2500 */
2501 for (index = 0; index < arrayP->numProcs; index++)
2502 {
2503 int pgprocno = arrayP->pgprocnos[index];
2504 PGPROC *proc = &allProcs[pgprocno];
2505 int statusFlags = ProcGlobal->statusFlags[index];
2506 TransactionId xid;
2507
2508 /* Ignore procs running LAZY VACUUM */
2509 if (statusFlags & PROC_IN_VACUUM)
2510 continue;
2511
2512 /* We are only interested in the specific virtual transaction. */
2513 if (proc->vxid.procNumber != sourcevxid->procNumber)
2514 continue;
2515 if (proc->vxid.lxid != sourcevxid->localTransactionId)
2516 continue;
2517
2518 /*
2519 * We check the transaction's database ID for paranoia's sake: if it's
2520 * in another DB then its xmin does not cover us. Caller should have
2521 * detected this already, so we just treat any funny cases as
2522 * "transaction not found".
2523 */
2524 if (proc->databaseId != MyDatabaseId)
2525 continue;
2526
2527 /*
2528 * Likewise, let's just make real sure its xmin does cover us.
2529 */
2530 xid = UINT32_ACCESS_ONCE(proc->xmin);
2531 if (!TransactionIdIsNormal(xid) ||
2533 continue;
2534
2535 /*
2536 * We're good. Install the new xmin. As in GetSnapshotData, set
2537 * TransactionXmin too. (Note that because snapmgr.c called
2538 * GetSnapshotData first, we'll be overwriting a valid xmin here, so
2539 * we don't check that.)
2540 */
2541 MyProc->xmin = TransactionXmin = xmin;
2542
2543 result = true;
2544 break;
2545 }
2546
2547 LWLockRelease(ProcArrayLock);
2548
2549 return result;
2550}
ProcNumber procNumber
Definition: proc.h:212

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

Referenced by GetSerializableTransactionSnapshotInt(), and SetTransactionSnapshot().

◆ ProcArrayInstallRestoredXmin()

bool ProcArrayInstallRestoredXmin ( TransactionId  xmin,
PGPROC proc 
)

Definition at line 2566 of file procarray.c.

2567{
2568 bool result = false;
2569 TransactionId xid;
2570
2572 Assert(proc != NULL);
2573
2574 /*
2575 * Get an exclusive lock so that we can copy statusFlags from source proc.
2576 */
2577 LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
2578
2579 /*
2580 * Be certain that the referenced PGPROC has an advertised xmin which is
2581 * no later than the one we're installing, so that the system-wide xmin
2582 * can't go backwards. Also, make sure it's running in the same database,
2583 * so that the per-database xmin cannot go backwards.
2584 */
2585 xid = UINT32_ACCESS_ONCE(proc->xmin);
2586 if (proc->databaseId == MyDatabaseId &&
2587 TransactionIdIsNormal(xid) &&
2589 {
2590 /*
2591 * Install xmin and propagate the statusFlags that affect how the
2592 * value is interpreted by vacuum.
2593 */
2594 MyProc->xmin = TransactionXmin = xmin;
2595 MyProc->statusFlags = (MyProc->statusFlags & ~PROC_XMIN_FLAGS) |
2596 (proc->statusFlags & PROC_XMIN_FLAGS);
2598
2599 result = true;
2600 }
2601
2602 LWLockRelease(ProcArrayLock);
2603
2604 return result;
2605}
#define PROC_XMIN_FLAGS
Definition: proc.h:72

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

Referenced by SetTransactionSnapshot().

◆ ProcArrayRemove()

void ProcArrayRemove ( PGPROC proc,
TransactionId  latestXid 
)

Definition at line 567 of file procarray.c.

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

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

Referenced by FinishPreparedTransaction(), and RemoveProcFromArray().

◆ ProcArraySetReplicationSlotXmin()

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

Definition at line 3922 of file procarray.c.

3924{
3925 Assert(!already_locked || LWLockHeldByMe(ProcArrayLock));
3926
3927 if (!already_locked)
3928 LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3929
3932
3933 if (!already_locked)
3934 LWLockRelease(ProcArrayLock);
3935
3936 elog(DEBUG1, "xmin required by slots: data %u, catalog %u",
3937 xmin, catalog_xmin);
3938}

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

Referenced by ReplicationSlotsComputeRequiredXmin().

◆ ProcArrayShmemInit()

void ProcArrayShmemInit ( void  )

Definition at line 420 of file procarray.c.

421{
422 bool found;
423
424 /* Create or attach to the ProcArray shared structure */
426 ShmemInitStruct("Proc Array",
427 add_size(offsetof(ProcArrayStruct, pgprocnos),
428 mul_size(sizeof(int),
430 &found);
431
432 if (!found)
433 {
434 /*
435 * We're the first - initialize.
436 */
437 procArray->numProcs = 0;
447 }
448
450
451 /* Create or attach to the KnownAssignedXids arrays too, if needed */
453 {
455 ShmemInitStruct("KnownAssignedXids",
456 mul_size(sizeof(TransactionId),
458 &found);
459 KnownAssignedXidsValid = (bool *)
460 ShmemInitStruct("KnownAssignedXidsValid",
461 mul_size(sizeof(bool), TOTAL_MAX_CACHED_SUBXIDS),
462 &found);
463 }
464}
#define PROCARRAY_MAXPROCS
Size add_size(Size s1, Size s2)
Definition: shmem.c:495
Size mul_size(Size s1, Size s2)
Definition: shmem.c:510
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:389
bool EnableHotStandby
Definition: xlog.c:124

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

Referenced by CreateOrAttachShmemStructs().

◆ ProcArrayShmemSize()

Size ProcArrayShmemSize ( void  )

Definition at line 378 of file procarray.c.

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

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

Referenced by CalculateShmemSize().

◆ ProcNumberGetProc()

PGPROC * ProcNumberGetProc ( ProcNumber  procNumber)

Definition at line 3101 of file procarray.c.

3102{
3103 PGPROC *result;
3104
3105 if (procNumber < 0 || procNumber >= ProcGlobal->allProcCount)
3106 return NULL;
3107 result = GetPGProcByNumber(procNumber);
3108
3109 if (result->pid == 0)
3110 return NULL;
3111
3112 return result;
3113}
#define GetPGProcByNumber(n)
Definition: proc.h:440
uint32 allProcCount
Definition: proc.h:406

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

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

◆ ProcNumberGetTransactionIds()

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

Definition at line 3123 of file procarray.c.

3125{
3126 PGPROC *proc;
3127
3128 *xid = InvalidTransactionId;
3129 *xmin = InvalidTransactionId;
3130 *nsubxid = 0;
3131 *overflowed = false;
3132
3133 if (procNumber < 0 || procNumber >= ProcGlobal->allProcCount)
3134 return;
3135 proc = GetPGProcByNumber(procNumber);
3136
3137 /* Need to lock out additions/removals of backends */
3138 LWLockAcquire(ProcArrayLock, LW_SHARED);
3139
3140 if (proc->pid != 0)
3141 {
3142 *xid = proc->xid;
3143 *xmin = proc->xmin;
3144 *nsubxid = proc->subxidStatus.count;
3145 *overflowed = proc->subxidStatus.overflowed;
3146 }
3147
3148 LWLockRelease(ProcArrayLock);
3149}

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

Referenced by pgstat_read_current_status().

◆ RecordKnownAssignedTransactionIds()

void RecordKnownAssignedTransactionIds ( TransactionId  xid)

Definition at line 4382 of file procarray.c.

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

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

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

◆ SignalVirtualTransaction()

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

Definition at line 3459 of file procarray.c.

3461{
3462 ProcArrayStruct *arrayP = procArray;
3463 int index;
3464 pid_t pid = 0;
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 VirtualTransactionId procvxid;
3473
3474 GET_VXID_FROM_PGPROC(procvxid, *proc);
3475
3476 if (procvxid.procNumber == vxid.procNumber &&
3477 procvxid.localTransactionId == vxid.localTransactionId)
3478 {
3479 proc->recoveryConflictPending = conflictPending;
3480 pid = proc->pid;
3481 if (pid != 0)
3482 {
3483 /*
3484 * Kill the pid if it's still here. If not, that's what we
3485 * wanted so ignore any errors.
3486 */
3487 (void) SendProcSignal(pid, sigmode, vxid.procNumber);
3488 }
3489 break;
3490 }
3491 }
3492
3493 LWLockRelease(ProcArrayLock);
3494
3495 return pid;
3496}

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

Referenced by CancelVirtualTransaction(), and ResolveRecoveryConflictWithLock().

◆ TerminateOtherDBBackends()

void TerminateOtherDBBackends ( Oid  databaseId)

Definition at line 3807 of file procarray.c.

3808{
3809 ProcArrayStruct *arrayP = procArray;
3810 List *pids = NIL;
3811 int nprepared = 0;
3812 int i;
3813
3814 LWLockAcquire(ProcArrayLock, LW_SHARED);
3815
3816 for (i = 0; i < procArray->numProcs; i++)
3817 {
3818 int pgprocno = arrayP->pgprocnos[i];
3819 PGPROC *proc = &allProcs[pgprocno];
3820
3821 if (proc->databaseId != databaseId)
3822 continue;
3823 if (proc == MyProc)
3824 continue;
3825
3826 if (proc->pid != 0)
3827 pids = lappend_int(pids, proc->pid);
3828 else
3829 nprepared++;
3830 }
3831
3832 LWLockRelease(ProcArrayLock);
3833
3834 if (nprepared > 0)
3835 ereport(ERROR,
3836 (errcode(ERRCODE_OBJECT_IN_USE),
3837 errmsg("database \"%s\" is being used by prepared transactions",
3838 get_database_name(databaseId)),
3839 errdetail_plural("There is %d prepared transaction using the database.",
3840 "There are %d prepared transactions using the database.",
3841 nprepared,
3842 nprepared)));
3843
3844 if (pids)
3845 {
3846 ListCell *lc;
3847
3848 /*
3849 * Permissions checks relax the pg_terminate_backend checks in two
3850 * ways, both by omitting the !OidIsValid(proc->roleId) check:
3851 *
3852 * - Accept terminating autovacuum workers, since DROP DATABASE
3853 * without FORCE terminates them.
3854 *
3855 * - Accept terminating bgworkers. For bgworker authors, it's
3856 * convenient to be able to recommend FORCE if a worker is blocking
3857 * DROP DATABASE unexpectedly.
3858 *
3859 * Unlike pg_terminate_backend, we don't raise some warnings - like
3860 * "PID %d is not a PostgreSQL server process", because for us already
3861 * finished session is not a problem.
3862 */
3863 foreach(lc, pids)
3864 {
3865 int pid = lfirst_int(lc);
3866 PGPROC *proc = BackendPidGetProc(pid);
3867
3868 if (proc != NULL)
3869 {
3870 if (superuser_arg(proc->roleId) && !superuser())
3871 ereport(ERROR,
3872 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3873 errmsg("permission denied to terminate process"),
3874 errdetail("Only roles with the %s attribute may terminate processes of roles with the %s attribute.",
3875 "SUPERUSER", "SUPERUSER")));
3876
3877 if (!has_privs_of_role(GetUserId(), proc->roleId) &&
3878 !has_privs_of_role(GetUserId(), ROLE_PG_SIGNAL_BACKEND))
3879 ereport(ERROR,
3880 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3881 errmsg("permission denied to terminate process"),
3882 errdetail("Only roles with privileges of the role whose process is being terminated or with privileges of the \"%s\" role may terminate this process.",
3883 "pg_signal_backend")));
3884 }
3885 }
3886
3887 /*
3888 * There's a race condition here: once we release the ProcArrayLock,
3889 * it's possible for the session to exit before we issue kill. That
3890 * race condition possibility seems too unlikely to worry about. See
3891 * pg_signal_backend.
3892 */
3893 foreach(lc, pids)
3894 {
3895 int pid = lfirst_int(lc);
3896 PGPROC *proc = BackendPidGetProc(pid);
3897
3898 if (proc != NULL)
3899 {
3900 /*
3901 * If we have setsid(), signal the backend's whole process
3902 * group
3903 */
3904#ifdef HAVE_SETSID
3905 (void) kill(-pid, SIGTERM);
3906#else
3907 (void) kill(pid, SIGTERM);
3908#endif
3909 }
3910 }
3911 }
3912}
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:5284
int errdetail(const char *fmt,...)
Definition: elog.c:1216
int errdetail_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1308
List * lappend_int(List *list, int datum)
Definition: list.c:357
char * get_database_name(Oid dbid)
Definition: lsyscache.c:1242
Oid GetUserId(void)
Definition: miscinit.c:469
#define NIL
Definition: pg_list.h:68
#define lfirst_int(lc)
Definition: pg_list.h:173
Definition: pg_list.h:54
bool superuser_arg(Oid roleid)
Definition: superuser.c:56
bool superuser(void)
Definition: superuser.c:46

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

Referenced by dropdb().

◆ TransactionIdIsInProgress()

bool TransactionIdIsInProgress ( TransactionId  xid)

Definition at line 1404 of file procarray.c.

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

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

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

◆ XidCacheRemoveRunningXids()

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

Definition at line 3970 of file procarray.c.

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

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

Referenced by RecordTransactionAbort().

Variable Documentation

◆ allProcs

◆ cachedXidIsNotInProgress

TransactionId cachedXidIsNotInProgress = InvalidTransactionId
static

Definition at line 278 of file procarray.c.

Referenced by TransactionIdIsInProgress().

◆ ComputeXidHorizonsResultLastXmin

TransactionId ComputeXidHorizonsResultLastXmin
static

Definition at line 309 of file procarray.c.

Referenced by GlobalVisTestShouldUpdate(), and GlobalVisUpdateApply().

◆ GlobalVisCatalogRels

GlobalVisState GlobalVisCatalogRels
static

Definition at line 300 of file procarray.c.

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

◆ GlobalVisDataRels

GlobalVisState GlobalVisDataRels
static

Definition at line 301 of file procarray.c.

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

◆ GlobalVisSharedRels

GlobalVisState GlobalVisSharedRels
static

Definition at line 299 of file procarray.c.

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

◆ GlobalVisTempRels

GlobalVisState GlobalVisTempRels
static

Definition at line 302 of file procarray.c.

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

◆ KnownAssignedXids

◆ KnownAssignedXidsValid

◆ latestObservedXid

◆ procArray

◆ standbySnapshotPendingXmin

TransactionId standbySnapshotPendingXmin
static

Definition at line 292 of file procarray.c.

Referenced by ProcArrayApplyRecoveryInfo().