PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
procarray.c File Reference
#include "postgres.h"
#include <signal.h>
#include "access/subtrans.h"
#include "access/transam.h"
#include "access/twophase.h"
#include "access/xact.h"
#include "access/xlogutils.h"
#include "catalog/catalog.h"
#include "catalog/pg_authid.h"
#include "commands/dbcommands.h"
#include "miscadmin.h"
#include "pgstat.h"
#include "port/pg_lfind.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
Include dependency graph for procarray.c:

Go to the source code of this file.

Data Structures

struct  ProcArrayStruct
 
struct  GlobalVisState
 
struct  ComputeXidHorizonsResult
 

Macros

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

Typedefs

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

Enumerations

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

Functions

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

Variables

static ProcArrayStructprocArray
 
static PGPROCallProcs
 
static TransactionId cachedXidIsNotInProgress = InvalidTransactionId
 
static TransactionIdKnownAssignedXids
 
static 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 68 of file procarray.c.

◆ xc_by_child_xid_inc

#define xc_by_child_xid_inc ( )    ((void) 0)

Definition at line 340 of file procarray.c.

◆ xc_by_known_assigned_inc

#define xc_by_known_assigned_inc ( )    ((void) 0)

Definition at line 341 of file procarray.c.

◆ xc_by_known_xact_inc

#define xc_by_known_xact_inc ( )    ((void) 0)

Definition at line 336 of file procarray.c.

◆ xc_by_latest_xid_inc

#define xc_by_latest_xid_inc ( )    ((void) 0)

Definition at line 338 of file procarray.c.

◆ xc_by_main_xid_inc

#define xc_by_main_xid_inc ( )    ((void) 0)

Definition at line 339 of file procarray.c.

◆ xc_by_my_xact_inc

#define xc_by_my_xact_inc ( )    ((void) 0)

Definition at line 337 of file procarray.c.

◆ xc_by_recent_xmin_inc

#define xc_by_recent_xmin_inc ( )    ((void) 0)

Definition at line 335 of file procarray.c.

◆ xc_no_overflow_inc

#define xc_no_overflow_inc ( )    ((void) 0)

Definition at line 342 of file procarray.c.

◆ xc_slow_answer_inc

#define xc_slow_answer_inc ( )    ((void) 0)

Definition at line 343 of file procarray.c.

Typedef Documentation

◆ ComputeXidHorizonsResult

◆ GlobalVisHorizonKind

◆ KAXCompressReason

◆ ProcArrayStruct

Enumeration Type Documentation

◆ GlobalVisHorizonKind

Enumerator
VISHORIZON_SHARED 
VISHORIZON_CATALOG 
VISHORIZON_DATA 
VISHORIZON_TEMP 

Definition at line 249 of file procarray.c.

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

◆ KAXCompressReason

Enumerator
KAX_NO_SPACE 
KAX_PRUNE 
KAX_TRANSACTION_END 
KAX_STARTUP_PROCESS_IDLE 

Definition at line 260 of file procarray.c.

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

Function Documentation

◆ BackendPidGetProc()

PGPROC * BackendPidGetProc ( int  pid)

Definition at line 3196 of file procarray.c.

3197{
3198 PGPROC *result;
3199
3200 if (pid == 0) /* never match dummy PGPROCs */
3201 return NULL;
3202
3203 LWLockAcquire(ProcArrayLock, LW_SHARED);
3204
3205 result = BackendPidGetProcWithLock(pid);
3206
3207 LWLockRelease(ProcArrayLock);
3208
3209 return result;
3210}
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1168
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1781
@ LW_SHARED
Definition: lwlock.h:115
PGPROC * BackendPidGetProcWithLock(int pid)
Definition: procarray.c:3219
Definition: proc.h:162

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_io(), pg_stat_get_backend_wait_event(), pg_stat_get_backend_wait_event_type(), pg_stat_reset_backend_stats(), TerminateOtherDBBackends(), and test_shm_mq_main().

◆ BackendPidGetProcWithLock()

PGPROC * BackendPidGetProcWithLock ( int  pid)

Definition at line 3219 of file procarray.c.

3220{
3221 PGPROC *result = NULL;
3222 ProcArrayStruct *arrayP = procArray;
3223 int index;
3224
3225 if (pid == 0) /* never match dummy PGPROCs */
3226 return NULL;
3227
3228 for (index = 0; index < arrayP->numProcs; index++)
3229 {
3230 PGPROC *proc = &allProcs[arrayP->pgprocnos[index]];
3231
3232 if (proc->pid == pid)
3233 {
3234 result = proc;
3235 break;
3236 }
3237 }
3238
3239 return result;
3240}
static PGPROC * allProcs
Definition: procarray.c:271
static ProcArrayStruct * procArray
Definition: procarray.c:269
int pid
Definition: proc.h:182
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:99
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 3256 of file procarray.c.

3257{
3258 int result = 0;
3259 ProcArrayStruct *arrayP = procArray;
3260 TransactionId *other_xids = ProcGlobal->xids;
3261 int index;
3262
3263 if (xid == InvalidTransactionId) /* never match invalid xid */
3264 return 0;
3265
3266 LWLockAcquire(ProcArrayLock, LW_SHARED);
3267
3268 for (index = 0; index < arrayP->numProcs; index++)
3269 {
3270 if (other_xids[index] == xid)
3271 {
3272 int pgprocno = arrayP->pgprocnos[index];
3273 PGPROC *proc = &allProcs[pgprocno];
3274
3275 result = proc->pid;
3276 break;
3277 }
3278 }
3279
3280 LWLockRelease(ProcArrayLock);
3281
3282 return result;
3283}
uint32 TransactionId
Definition: c.h:606
PROC_HDR * ProcGlobal
Definition: proc.c:78
TransactionId * xids
Definition: proc.h:374
#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 3659 of file procarray.c.

3660{
3661 ProcArrayStruct *arrayP = procArray;
3662 int index;
3663
3664 /* tell all backends to die */
3665 LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3666
3667 for (index = 0; index < arrayP->numProcs; index++)
3668 {
3669 int pgprocno = arrayP->pgprocnos[index];
3670 PGPROC *proc = &allProcs[pgprocno];
3671
3672 if (databaseid == InvalidOid || proc->databaseId == databaseid)
3673 {
3674 VirtualTransactionId procvxid;
3675 pid_t pid;
3676
3677 GET_VXID_FROM_PGPROC(procvxid, *proc);
3678
3679 proc->recoveryConflictPending = conflictPending;
3680 pid = proc->pid;
3681 if (pid != 0)
3682 {
3683 /*
3684 * Kill the pid if it's still here. If not, that's what we
3685 * wanted so ignore any errors.
3686 */
3687 (void) SendProcSignal(pid, sigmode, procvxid.procNumber);
3688 }
3689 }
3690 }
3691
3692 LWLockRelease(ProcArrayLock);
3693}
#define GET_VXID_FROM_PGPROC(vxid_dst, proc)
Definition: lock.h:77
@ LW_EXCLUSIVE
Definition: lwlock.h:114
#define InvalidOid
Definition: postgres_ext.h:36
int SendProcSignal(pid_t pid, ProcSignalReason reason, ProcNumber procNumber)
Definition: procsignal.c:281
bool recoveryConflictPending
Definition: proc.h:220
Oid databaseId
Definition: proc.h:207
ProcNumber procNumber
Definition: lock.h:61

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

Referenced by ResolveRecoveryConflictWithDatabase(), and SendRecoveryConflictWithBufferPin().

◆ CancelVirtualTransaction()

pid_t CancelVirtualTransaction ( VirtualTransactionId  vxid,
ProcSignalReason  sigmode 
)

Definition at line 3491 of file procarray.c.

3492{
3493 return SignalVirtualTransaction(vxid, sigmode, true);
3494}
pid_t SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode, bool conflictPending)
Definition: procarray.c:3497

References SignalVirtualTransaction().

Referenced by ResolveRecoveryConflictWithVirtualXIDs().

◆ ComputeXidHorizons()

static void ComputeXidHorizons ( ComputeXidHorizonsResult h)
static

Definition at line 1735 of file procarray.c.

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

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

3600{
3601 ProcArrayStruct *arrayP = procArray;
3602 int count = 0;
3603 int index;
3604
3605 LWLockAcquire(ProcArrayLock, LW_SHARED);
3606
3607 for (index = 0; index < arrayP->numProcs; index++)
3608 {
3609 int pgprocno = arrayP->pgprocnos[index];
3610 PGPROC *proc = &allProcs[pgprocno];
3611
3612 if (proc->pid == 0)
3613 continue; /* do not count prepared xacts */
3614 if (!OidIsValid(databaseid) ||
3615 proc->databaseId == databaseid)
3616 count++;
3617 }
3618
3619 LWLockRelease(ProcArrayLock);
3620
3621 return count;
3622}
#define OidIsValid(objectId)
Definition: c.h:729

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

3629{
3630 ProcArrayStruct *arrayP = procArray;
3631 int count = 0;
3632 int index;
3633
3634 LWLockAcquire(ProcArrayLock, LW_SHARED);
3635
3636 for (index = 0; index < arrayP->numProcs; index++)
3637 {
3638 int pgprocno = arrayP->pgprocnos[index];
3639 PGPROC *proc = &allProcs[pgprocno];
3640
3641 if (proc->pid == 0)
3642 continue; /* do not count prepared xacts */
3643 if (!proc->isRegularBackend)
3644 continue; /* count only regular backend processes */
3645 if (!OidIsValid(databaseid) ||
3646 proc->databaseId == databaseid)
3647 count++;
3648 }
3649
3650 LWLockRelease(ProcArrayLock);
3651
3652 return count;
3653}
bool isRegularBackend
Definition: proc.h:213

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

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

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

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

◆ CountUserBackends()

int CountUserBackends ( Oid  roleid)

Definition at line 3700 of file procarray.c.

3701{
3702 ProcArrayStruct *arrayP = procArray;
3703 int count = 0;
3704 int index;
3705
3706 LWLockAcquire(ProcArrayLock, LW_SHARED);
3707
3708 for (index = 0; index < arrayP->numProcs; index++)
3709 {
3710 int pgprocno = arrayP->pgprocnos[index];
3711 PGPROC *proc = &allProcs[pgprocno];
3712
3713 if (proc->pid == 0)
3714 continue; /* do not count prepared xacts */
3715 if (!proc->isRegularBackend)
3716 continue; /* count only regular backend processes */
3717 if (proc->roleId == roleid)
3718 count++;
3719 }
3720
3721 LWLockRelease(ProcArrayLock);
3722
3723 return count;
3724}
Oid roleId
Definition: proc.h:208

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

4499{
4500 LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4502
4503 /*
4504 * Reset lastOverflowedXid. Currently, lastOverflowedXid has no use after
4505 * the call of this function. But do this for unification with what
4506 * ExpireOldKnownAssignedTransactionIds() do.
4507 */
4509 LWLockRelease(ProcArrayLock);
4510}
static void KnownAssignedXidsRemovePreceding(TransactionId removeXid)
Definition: procarray.c:5011
TransactionId lastOverflowedXid
Definition: procarray.c:91

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

Referenced by ShutdownRecoveryTransactionEnvironment().

◆ ExpireOldKnownAssignedTransactionIds()

void ExpireOldKnownAssignedTransactionIds ( TransactionId  xid)

Definition at line 4518 of file procarray.c.

4519{
4520 LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4521
4522 /*
4523 * Reset lastOverflowedXid if we know all transactions that have been
4524 * possibly running are being gone. Not doing so could cause an incorrect
4525 * lastOverflowedXid value, which makes extra snapshots be marked as
4526 * suboverflowed.
4527 */
4531 LWLockRelease(ProcArrayLock);
4532}
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:280

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

Referenced by ProcArrayApplyRecoveryInfo().

◆ ExpireTreeKnownAssignedTransactionIds()

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

Definition at line 4472 of file procarray.c.

4474{
4476
4477 /*
4478 * Uses same locking as transaction commit
4479 */
4480 LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4481
4482 KnownAssignedXidsRemoveTree(xid, nsubxids, subxids);
4483
4484 /* As in ProcArrayEndTransaction, advance latestCompletedXid */
4486
4487 /* ... and xactCompletionCount */
4489
4490 LWLockRelease(ProcArrayLock);
4491}
static void KnownAssignedXidsRemoveTree(TransactionId xid, int nsubxids, TransactionId *subxids)
Definition: procarray.c:4989
static void MaintainLatestCompletedXidRecovery(TransactionId latestXid)
Definition: procarray.c:989
uint64 xactCompletionCount
Definition: transam.h:248
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 4321 of file procarray.c.

4322{
4324
4326 Assert(TransactionIdIsValid(rel_xid));
4327
4328 /* not guaranteed to find issues, but likely to catch mistakes */
4330
4332 + (int32) (xid - rel_xid));
4333}
int32_t int32
Definition: c.h:481
#define U64FromFullTransactionId(x)
Definition: transam.h:49
static FullTransactionId FullTransactionIdFromU64(uint64 value)
Definition: transam.h:81
#define AssertTransactionIdInAllowableRange(xid)
Definition: transam.h:301

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

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

◆ GetConflictingVirtualXIDs()

VirtualTransactionId * GetConflictingVirtualXIDs ( TransactionId  limitXmin,
Oid  dbOid 
)

Definition at line 3417 of file procarray.c.

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

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

Referenced by ResolveRecoveryConflictWithSnapshot(), and ResolveRecoveryConflictWithTablespace().

◆ GetCurrentVirtualXIDs()

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

Definition at line 3324 of file procarray.c.

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

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

Referenced by WaitForOlderSnapshots().

◆ GetMaxSnapshotSubxidCount()

int GetMaxSnapshotSubxidCount ( void  )

Definition at line 2080 of file procarray.c.

2081{
2083}
#define TOTAL_MAX_CACHED_SUBXIDS

References TOTAL_MAX_CACHED_SUBXIDS.

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

◆ GetMaxSnapshotXidCount()

int GetMaxSnapshotXidCount ( void  )

Definition at line 2069 of file procarray.c.

2070{
2071 return procArray->maxProcs;
2072}

References ProcArrayStruct::maxProcs, and procArray.

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

◆ GetOldestActiveTransactionId()

TransactionId GetOldestActiveTransactionId ( void  )

Definition at line 2880 of file procarray.c.

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

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

Referenced by CreateCheckPoint().

◆ GetOldestNonRemovableTransactionId()

TransactionId GetOldestNonRemovableTransactionId ( Relation  rel)

◆ GetOldestSafeDecodingTransactionId()

TransactionId GetOldestSafeDecodingTransactionId ( bool  catalogOnly)

Definition at line 2945 of file procarray.c.

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

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

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

◆ GetOldestTransactionIdConsideredRunning()

TransactionId GetOldestTransactionIdConsideredRunning ( void  )

Definition at line 2034 of file procarray.c.

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

References ComputeXidHorizons(), and ComputeXidHorizonsResult::oldest_considered_running.

Referenced by CreateCheckPoint(), and CreateRestartPoint().

◆ GetReplicationHorizons()

void GetReplicationHorizons ( TransactionId xmin,
TransactionId catalog_xmin 
)

Definition at line 2047 of file procarray.c.

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

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

Referenced by XLogWalRcvSendHSFeedback().

◆ GetRunningTransactionData()

RunningTransactions GetRunningTransactionData ( void  )

Definition at line 2689 of file procarray.c.

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

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

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

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

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

3044{
3045 VirtualTransactionId *vxids;
3046 ProcArrayStruct *arrayP = procArray;
3047 int count = 0;
3048 int index;
3049
3050 Assert(type != 0);
3051
3052 /* allocate what's certainly enough result space */
3053 vxids = (VirtualTransactionId *)
3054 palloc(sizeof(VirtualTransactionId) * arrayP->maxProcs);
3055
3056 LWLockAcquire(ProcArrayLock, LW_SHARED);
3057
3058 for (index = 0; index < arrayP->numProcs; index++)
3059 {
3060 int pgprocno = arrayP->pgprocnos[index];
3061 PGPROC *proc = &allProcs[pgprocno];
3062
3063 if ((proc->delayChkptFlags & type) != 0)
3064 {
3066
3067 GET_VXID_FROM_PGPROC(vxid, *proc);
3069 vxids[count++] = vxid;
3070 }
3071 }
3072
3073 LWLockRelease(ProcArrayLock);
3074
3075 *nvxids = count;
3076 return vxids;
3077}
int delayChkptFlags
Definition: proc.h:240
const char * type

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

Referenced by CreateCheckPoint().

◆ GlobalVisCheckRemovableFullXid()

bool GlobalVisCheckRemovableFullXid ( Relation  rel,
FullTransactionId  fxid 
)

Definition at line 4286 of file procarray.c.

4287{
4289
4290 state = GlobalVisTestFor(rel);
4291
4293}
bool GlobalVisTestIsRemovableFullXid(GlobalVisState *state, FullTransactionId fxid)
Definition: procarray.c:4222
GlobalVisState * GlobalVisTestFor(Relation rel)
Definition: procarray.c:4107
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 4300 of file procarray.c.

4301{
4303
4304 state = GlobalVisTestFor(rel);
4305
4307}
bool GlobalVisTestIsRemovableXid(GlobalVisState *state, TransactionId xid)
Definition: procarray.c:4264

References GlobalVisTestFor(), and GlobalVisTestIsRemovableXid().

Referenced by GinPageIsRecyclable().

◆ GlobalVisHorizonKindForRel()

static GlobalVisHorizonKind GlobalVisHorizonKindForRel ( Relation  rel)
inlinestatic

Definition at line 1971 of file procarray.c.

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

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

Referenced by GetOldestNonRemovableTransactionId(), and GlobalVisTestFor().

◆ GlobalVisTestFor()

GlobalVisState * GlobalVisTestFor ( Relation  rel)

Definition at line 4107 of file procarray.c.

4108{
4109 GlobalVisState *state = NULL;
4110
4111 /* XXX: we should assert that a snapshot is pushed or registered */
4113
4114 switch (GlobalVisHorizonKindForRel(rel))
4115 {
4116 case VISHORIZON_SHARED:
4118 break;
4119 case VISHORIZON_CATALOG:
4121 break;
4122 case VISHORIZON_DATA:
4124 break;
4125 case VISHORIZON_TEMP:
4127 break;
4128 }
4129
4130 Assert(FullTransactionIdIsValid(state->definitely_needed) &&
4131 FullTransactionIdIsValid(state->maybe_needed));
4132
4133 return state;
4134}
#define FullTransactionIdIsValid(x)
Definition: transam.h:55

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

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

◆ GlobalVisTestIsRemovableFullXid()

bool GlobalVisTestIsRemovableFullXid ( GlobalVisState state,
FullTransactionId  fxid 
)

Definition at line 4222 of file procarray.c.

4224{
4225 /*
4226 * If fxid is older than maybe_needed bound, it definitely is visible to
4227 * everyone.
4228 */
4229 if (FullTransactionIdPrecedes(fxid, state->maybe_needed))
4230 return true;
4231
4232 /*
4233 * If fxid is >= definitely_needed bound, it is very likely to still be
4234 * considered running.
4235 */
4236 if (FullTransactionIdFollowsOrEquals(fxid, state->definitely_needed))
4237 return false;
4238
4239 /*
4240 * fxid is between maybe_needed and definitely_needed, i.e. there might or
4241 * might not exist a snapshot considering fxid running. If it makes sense,
4242 * update boundaries and recheck.
4243 */
4245 {
4247
4248 Assert(FullTransactionIdPrecedes(fxid, state->definitely_needed));
4249
4250 return FullTransactionIdPrecedes(fxid, state->maybe_needed);
4251 }
4252 else
4253 return false;
4254}
static bool GlobalVisTestShouldUpdate(GlobalVisState *state)
Definition: procarray.c:4147
static void GlobalVisUpdate(void)
Definition: procarray.c:4205
#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 4264 of file procarray.c.

4265{
4266 FullTransactionId fxid;
4267
4268 /*
4269 * Convert 32 bit argument to FullTransactionId. We can do so safely
4270 * because we know the xid has to, at the very least, be between
4271 * [oldestXid, nextXid), i.e. within 2 billion of xid. To avoid taking a
4272 * lock to determine either, we can just compare with
4273 * state->definitely_needed, which was based on those value at the time
4274 * the current snapshot was built.
4275 */
4276 fxid = FullXidRelativeTo(state->definitely_needed, xid);
4277
4279}

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

4148{
4149 /* hasn't been updated yet */
4151 return true;
4152
4153 /*
4154 * If the maybe_needed/definitely_needed boundaries are the same, it's
4155 * unlikely to be beneficial to refresh boundaries.
4156 */
4157 if (FullTransactionIdFollowsOrEquals(state->maybe_needed,
4158 state->definitely_needed))
4159 return false;
4160
4161 /* does the last snapshot built have a different xmin? */
4163}
static TransactionId ComputeXidHorizonsResultLastXmin
Definition: procarray.c:307

References ComputeXidHorizonsResultLastXmin, FullTransactionIdFollowsOrEquals, RecentXmin, and TransactionIdIsValid.

Referenced by GlobalVisTestIsRemovableFullXid().

◆ GlobalVisUpdate()

static void GlobalVisUpdate ( void  )
static

Definition at line 4205 of file procarray.c.

4206{
4207 ComputeXidHorizonsResult horizons;
4208
4209 /* updates the horizons as a side-effect */
4210 ComputeXidHorizons(&horizons);
4211}

References ComputeXidHorizons().

Referenced by GlobalVisTestIsRemovableFullXid().

◆ GlobalVisUpdateApply()

static void GlobalVisUpdateApply ( ComputeXidHorizonsResult horizons)
static

Definition at line 4166 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 3089 of file procarray.c.

3090{
3091 bool result = false;
3092 ProcArrayStruct *arrayP = procArray;
3093 int index;
3094
3095 Assert(type != 0);
3096
3097 LWLockAcquire(ProcArrayLock, LW_SHARED);
3098
3099 for (index = 0; index < arrayP->numProcs; index++)
3100 {
3101 int pgprocno = arrayP->pgprocnos[index];
3102 PGPROC *proc = &allProcs[pgprocno];
3104
3105 GET_VXID_FROM_PGPROC(vxid, *proc);
3106
3107 if ((proc->delayChkptFlags & type) != 0 &&
3109 {
3110 int i;
3111
3112 for (i = 0; i < nvxids; i++)
3113 {
3114 if (VirtualTransactionIdEquals(vxid, vxids[i]))
3115 {
3116 result = true;
3117 break;
3118 }
3119 }
3120 if (result)
3121 break;
3122 }
3123 }
3124
3125 LWLockRelease(ProcArrayLock);
3126
3127 return result;
3128}
int i
Definition: isn.c:72
#define VirtualTransactionIdEquals(vxid1, vxid2)
Definition: lock.h:71

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

Referenced by CreateCheckPoint().

◆ IsBackendPid()

bool IsBackendPid ( int  pid)

Definition at line 3291 of file procarray.c.

3292{
3293 return (BackendPidGetProc(pid) != NULL);
3294}
PGPROC * BackendPidGetProc(int pid)
Definition: procarray.c:3196

References BackendPidGetProc().

Referenced by pg_stat_get_subscription().

◆ KnownAssignedTransactionIdsIdleMaintenance()

void KnownAssignedTransactionIdsIdleMaintenance ( void  )

Definition at line 4540 of file procarray.c.

4541{
4543}
static void KnownAssignedXidsCompress(KAXCompressReason reason, bool haveLock)
Definition: procarray.c:4641

References KAX_STARTUP_PROCESS_IDLE, and KnownAssignedXidsCompress().

Referenced by WaitForWALToBecomeAvailable().

◆ KnownAssignedXidExists()

static bool KnownAssignedXidExists ( TransactionId  xid)
static

Definition at line 4950 of file procarray.c.

4951{
4953
4954 return KnownAssignedXidsSearch(xid, false);
4955}
static bool KnownAssignedXidsSearch(TransactionId xid, bool remove)
Definition: procarray.c:4862

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

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

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

Referenced by ProcArrayApplyRecoveryInfo(), and RecordKnownAssignedTransactionIds().

◆ KnownAssignedXidsCompress()

static void KnownAssignedXidsCompress ( KAXCompressReason  reason,
bool  haveLock 
)
static

Definition at line 4641 of file procarray.c.

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

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

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

5090{
5092
5093 return KnownAssignedXidsGetAndSetXmin(xarray, &xtmp, xmax);
5094}

References InvalidTransactionId, and KnownAssignedXidsGetAndSetXmin().

Referenced by TransactionIdIsInProgress().

◆ KnownAssignedXidsGetAndSetXmin()

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

Definition at line 5103 of file procarray.c.

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

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

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

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

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

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

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

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

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

Referenced by ExpireTreeKnownAssignedTransactionIds(), and ProcArrayApplyXidAssignment().

◆ KnownAssignedXidsReset()

static void KnownAssignedXidsReset ( void  )
static

Definition at line 5232 of file procarray.c.

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

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

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

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

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

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

Referenced by ExpireTreeKnownAssignedTransactionIds(), and ProcArrayApplyRecoveryInfo().

◆ MinimumActiveBackends()

bool MinimumActiveBackends ( int  min)

Definition at line 3546 of file procarray.c.

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

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

Referenced by XLogFlush().

◆ ProcArrayAdd()

void ProcArrayAdd ( PGPROC proc)

Definition at line 468 of file procarray.c.

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

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

Referenced by InitProcessPhase2(), and MarkAsPrepared().

◆ ProcArrayApplyRecoveryInfo()

void ProcArrayApplyRecoveryInfo ( RunningTransactions  running)

Definition at line 1054 of file procarray.c.

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

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

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

Referenced by xact_redo().

◆ ProcArrayClearTransaction()

void ProcArrayClearTransaction ( PGPROC proc)

Definition at line 907 of file procarray.c.

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

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

Referenced by PrepareTransaction().

◆ ProcArrayEndTransaction()

void ProcArrayEndTransaction ( PGPROC proc,
TransactionId  latestXid 
)

Definition at line 667 of file procarray.c.

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

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

Referenced by AbortTransaction(), and CommitTransaction().

◆ ProcArrayEndTransactionInternal()

static void ProcArrayEndTransactionInternal ( PGPROC proc,
TransactionId  latestXid 
)
inlinestatic

Definition at line 731 of file procarray.c.

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

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

Referenced by ProcArrayEndTransaction(), and ProcArrayGroupClearXid().

◆ ProcArrayGetReplicationSlotXmin()

void ProcArrayGetReplicationSlotXmin ( TransactionId xmin,
TransactionId catalog_xmin 
)

Definition at line 3968 of file procarray.c.

3970{
3971 LWLockAcquire(ProcArrayLock, LW_SHARED);
3972
3973 if (xmin != NULL)
3975
3976 if (catalog_xmin != NULL)
3978
3979 LWLockRelease(ProcArrayLock);
3980}

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

Referenced by logical_begin_heap_rewrite().

◆ ProcArrayGroupClearXid()

static void ProcArrayGroupClearXid ( PGPROC proc,
TransactionId  latestXid 
)
static

Definition at line 792 of file procarray.c.

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

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

Referenced by ProcArrayEndTransaction().

◆ ProcArrayInitRecovery()

void ProcArrayInitRecovery ( TransactionId  initializedUptoXID)

Definition at line 1023 of file procarray.c.

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

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

Referenced by StartupXLOG().

◆ ProcArrayInstallImportedXmin()

bool ProcArrayInstallImportedXmin ( TransactionId  xmin,
VirtualTransactionId sourcevxid 
)

Definition at line 2532 of file procarray.c.

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

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

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

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

Referenced by SetTransactionSnapshot().

◆ ProcArrayRemove()

void ProcArrayRemove ( PGPROC proc,
TransactionId  latestXid 
)

Definition at line 565 of file procarray.c.

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

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

3945{
3946 Assert(!already_locked || LWLockHeldByMe(ProcArrayLock));
3947
3948 if (!already_locked)
3949 LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3950
3953
3954 if (!already_locked)
3955 LWLockRelease(ProcArrayLock);
3956
3957 elog(DEBUG1, "xmin required by slots: data %u, catalog %u",
3958 xmin, catalog_xmin);
3959}

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

419{
420 bool found;
421
422 /* Create or attach to the ProcArray shared structure */
424 ShmemInitStruct("Proc Array",
425 add_size(offsetof(ProcArrayStruct, pgprocnos),
426 mul_size(sizeof(int),
428 &found);
429
430 if (!found)
431 {
432 /*
433 * We're the first - initialize.
434 */
435 procArray->numProcs = 0;
445 }
446
448
449 /* Create or attach to the KnownAssignedXids arrays too, if needed */
451 {
453 ShmemInitStruct("KnownAssignedXids",
454 mul_size(sizeof(TransactionId),
456 &found);
457 KnownAssignedXidsValid = (bool *)
458 ShmemInitStruct("KnownAssignedXidsValid",
459 mul_size(sizeof(bool), TOTAL_MAX_CACHED_SUBXIDS),
460 &found);
461 }
462}
#define PROCARRAY_MAXPROCS
Size add_size(Size s1, Size s2)
Definition: shmem.c:488
Size mul_size(Size s1, Size s2)
Definition: shmem.c:505
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:382
bool EnableHotStandby
Definition: xlog.c:121

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

Referenced by CreateOrAttachShmemStructs().

◆ ProcArrayShmemSize()

Size ProcArrayShmemSize ( void  )

Definition at line 376 of file procarray.c.

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

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

Referenced by CalculateShmemSize().

◆ ProcNumberGetProc()

PGPROC * ProcNumberGetProc ( ProcNumber  procNumber)

Definition at line 3138 of file procarray.c.

3139{
3140 PGPROC *result;
3141
3142 if (procNumber < 0 || procNumber >= ProcGlobal->allProcCount)
3143 return NULL;
3144 result = GetPGProcByNumber(procNumber);
3145
3146 if (result->pid == 0)
3147 return NULL;
3148
3149 return result;
3150}
#define GetPGProcByNumber(n)
Definition: proc.h:423
uint32 allProcCount
Definition: proc.h:389

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

3162{
3163 PGPROC *proc;
3164
3165 *xid = InvalidTransactionId;
3166 *xmin = InvalidTransactionId;
3167 *nsubxid = 0;
3168 *overflowed = false;
3169
3170 if (procNumber < 0 || procNumber >= ProcGlobal->allProcCount)
3171 return;
3172 proc = GetPGProcByNumber(procNumber);
3173
3174 /* Need to lock out additions/removals of backends */
3175 LWLockAcquire(ProcArrayLock, LW_SHARED);
3176
3177 if (proc->pid != 0)
3178 {
3179 *xid = proc->xid;
3180 *xmin = proc->xmin;
3181 *nsubxid = proc->subxidStatus.count;
3182 *overflowed = proc->subxidStatus.overflowed;
3183 }
3184
3185 LWLockRelease(ProcArrayLock);
3186}

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

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

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

3499{
3500 ProcArrayStruct *arrayP = procArray;
3501 int index;
3502 pid_t pid = 0;
3503
3504 LWLockAcquire(ProcArrayLock, LW_SHARED);
3505
3506 for (index = 0; index < arrayP->numProcs; index++)
3507 {
3508 int pgprocno = arrayP->pgprocnos[index];
3509 PGPROC *proc = &allProcs[pgprocno];
3510 VirtualTransactionId procvxid;
3511
3512 GET_VXID_FROM_PGPROC(procvxid, *proc);
3513
3514 if (procvxid.procNumber == vxid.procNumber &&
3515 procvxid.localTransactionId == vxid.localTransactionId)
3516 {
3517 proc->recoveryConflictPending = conflictPending;
3518 pid = proc->pid;
3519 if (pid != 0)
3520 {
3521 /*
3522 * Kill the pid if it's still here. If not, that's what we
3523 * wanted so ignore any errors.
3524 */
3525 (void) SendProcSignal(pid, sigmode, vxid.procNumber);
3526 }
3527 break;
3528 }
3529 }
3530
3531 LWLockRelease(ProcArrayLock);
3532
3533 return pid;
3534}

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

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

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

Referenced by dropdb().

◆ TransactionIdIsActive()

bool TransactionIdIsActive ( TransactionId  xid)

Definition at line 1634 of file procarray.c.

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

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

◆ TransactionIdIsInProgress()

bool TransactionIdIsInProgress ( TransactionId  xid)

Definition at line 1402 of file procarray.c.

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

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(), HeapTupleHeaderIsOnlyLocked(), HeapTupleSatisfiesDirty(), HeapTupleSatisfiesSelf(), HeapTupleSatisfiesToast(), HeapTupleSatisfiesUpdate(), HeapTupleSatisfiesVacuumHorizon(), MultiXactIdExpand(), MultiXactIdIsRunning(), pg_xact_status(), test_lockmode_for_conflict(), verify_heapam(), and XactLockTableWait().

◆ XidCacheRemoveRunningXids()

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

Definition at line 3991 of file procarray.c.

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

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

Referenced by RecordTransactionAbort().

Variable Documentation

◆ allProcs

◆ cachedXidIsNotInProgress

TransactionId cachedXidIsNotInProgress = InvalidTransactionId
static

Definition at line 276 of file procarray.c.

Referenced by TransactionIdIsInProgress().

◆ ComputeXidHorizonsResultLastXmin

TransactionId ComputeXidHorizonsResultLastXmin
static

Definition at line 307 of file procarray.c.

Referenced by GlobalVisTestShouldUpdate(), and GlobalVisUpdateApply().

◆ GlobalVisCatalogRels

GlobalVisState GlobalVisCatalogRels
static

Definition at line 298 of file procarray.c.

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

◆ GlobalVisDataRels

GlobalVisState GlobalVisDataRels
static

Definition at line 299 of file procarray.c.

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

◆ GlobalVisSharedRels

GlobalVisState GlobalVisSharedRels
static

Definition at line 297 of file procarray.c.

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

◆ GlobalVisTempRels

GlobalVisState GlobalVisTempRels
static

Definition at line 300 of file procarray.c.

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

◆ KnownAssignedXids

◆ KnownAssignedXidsValid

◆ latestObservedXid

◆ procArray

◆ standbySnapshotPendingXmin

TransactionId standbySnapshotPendingXmin
static

Definition at line 290 of file procarray.c.

Referenced by ProcArrayApplyRecoveryInfo().