PostgreSQL Source Code  git master
procarray.h File Reference
#include "storage/lock.h"
#include "storage/standby.h"
#include "utils/relcache.h"
#include "utils/snapshot.h"
Include dependency graph for procarray.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

Size ProcArrayShmemSize (void)
 
void CreateSharedProcArray (void)
 
void ProcArrayAdd (PGPROC *proc)
 
void ProcArrayRemove (PGPROC *proc, TransactionId latestXid)
 
void ProcArrayEndTransaction (PGPROC *proc, TransactionId latestXid)
 
void ProcArrayClearTransaction (PGPROC *proc)
 
void ProcArrayInitRecovery (TransactionId initializedUptoXID)
 
void ProcArrayApplyRecoveryInfo (RunningTransactions running)
 
void ProcArrayApplyXidAssignment (TransactionId topxid, int nsubxids, TransactionId *subxids)
 
void RecordKnownAssignedTransactionIds (TransactionId xid)
 
void ExpireTreeKnownAssignedTransactionIds (TransactionId xid, int nsubxids, TransactionId *subxids, TransactionId max_xid)
 
void ExpireAllKnownAssignedTransactionIds (void)
 
void ExpireOldKnownAssignedTransactionIds (TransactionId xid)
 
int GetMaxSnapshotXidCount (void)
 
int GetMaxSnapshotSubxidCount (void)
 
Snapshot GetSnapshotData (Snapshot snapshot)
 
bool ProcArrayInstallImportedXmin (TransactionId xmin, VirtualTransactionId *sourcevxid)
 
bool ProcArrayInstallRestoredXmin (TransactionId xmin, PGPROC *proc)
 
RunningTransactions GetRunningTransactionData (void)
 
bool TransactionIdIsInProgress (TransactionId xid)
 
bool TransactionIdIsActive (TransactionId xid)
 
TransactionId GetOldestNonRemovableTransactionId (Relation rel)
 
TransactionId GetOldestTransactionIdConsideredRunning (void)
 
TransactionId GetOldestActiveTransactionId (void)
 
TransactionId GetOldestSafeDecodingTransactionId (bool catalogOnly)
 
void GetReplicationHorizons (TransactionId *slot_xmin, TransactionId *catalog_xmin)
 
VirtualTransactionIdGetVirtualXIDsDelayingChkpt (int *nvxids, int type)
 
bool HaveVirtualXIDsDelayingChkpt (VirtualTransactionId *vxids, int nvxids, int type)
 
PGPROCBackendPidGetProc (int pid)
 
PGPROCBackendPidGetProcWithLock (int pid)
 
int BackendXidGetPid (TransactionId xid)
 
bool IsBackendPid (int pid)
 
VirtualTransactionIdGetCurrentVirtualXIDs (TransactionId limitXmin, bool excludeXmin0, bool allDbs, int excludeVacuum, int *nvxids)
 
VirtualTransactionIdGetConflictingVirtualXIDs (TransactionId limitXmin, Oid dbOid)
 
pid_t CancelVirtualTransaction (VirtualTransactionId vxid, ProcSignalReason sigmode)
 
pid_t SignalVirtualTransaction (VirtualTransactionId vxid, ProcSignalReason sigmode, bool conflictPending)
 
bool MinimumActiveBackends (int min)
 
int CountDBBackends (Oid databaseid)
 
int CountDBConnections (Oid databaseid)
 
void CancelDBBackends (Oid databaseid, ProcSignalReason sigmode, bool conflictPending)
 
int CountUserBackends (Oid roleid)
 
bool CountOtherDBBackends (Oid databaseId, int *nbackends, int *nprepared)
 
void TerminateOtherDBBackends (Oid databaseId)
 
void XidCacheRemoveRunningXids (TransactionId xid, int nxids, const TransactionId *xids, TransactionId latestXid)
 
void ProcArraySetReplicationSlotXmin (TransactionId xmin, TransactionId catalog_xmin, bool already_locked)
 
void ProcArrayGetReplicationSlotXmin (TransactionId *xmin, TransactionId *catalog_xmin)
 

Function Documentation

◆ BackendPidGetProc()

PGPROC* BackendPidGetProc ( int  pid)

Definition at line 3170 of file procarray.c.

3171 {
3172  PGPROC *result;
3173 
3174  if (pid == 0) /* never match dummy PGPROCs */
3175  return NULL;
3176 
3177  LWLockAcquire(ProcArrayLock, LW_SHARED);
3178 
3179  result = BackendPidGetProcWithLock(pid);
3180 
3181  LWLockRelease(ProcArrayLock);
3182 
3183  return result;
3184 }
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1196
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1800
@ LW_SHARED
Definition: lwlock.h:105
PGPROC * BackendPidGetProcWithLock(int pid)
Definition: procarray.c:3193
Definition: proc.h:160

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

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

◆ BackendPidGetProcWithLock()

PGPROC* BackendPidGetProcWithLock ( int  pid)

Definition at line 3193 of file procarray.c.

3194 {
3195  PGPROC *result = NULL;
3196  ProcArrayStruct *arrayP = procArray;
3197  int index;
3198 
3199  if (pid == 0) /* never match dummy PGPROCs */
3200  return NULL;
3201 
3202  for (index = 0; index < arrayP->numProcs; index++)
3203  {
3204  PGPROC *proc = &allProcs[arrayP->pgprocnos[index]];
3205 
3206  if (proc->pid == pid)
3207  {
3208  result = proc;
3209  break;
3210  }
3211  }
3212 
3213  return result;
3214 }
static PGPROC * allProcs
Definition: procarray.c:262
static ProcArrayStruct * procArray
Definition: procarray.c:260
int pid
Definition: proc.h:184
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:101
Definition: type.h:90

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

Referenced by BackendPidGetProc(), and GetBlockerStatusData().

◆ BackendXidGetPid()

int BackendXidGetPid ( TransactionId  xid)

Definition at line 3230 of file procarray.c.

3231 {
3232  int result = 0;
3233  ProcArrayStruct *arrayP = procArray;
3234  TransactionId *other_xids = ProcGlobal->xids;
3235  int index;
3236 
3237  if (xid == InvalidTransactionId) /* never match invalid xid */
3238  return 0;
3239 
3240  LWLockAcquire(ProcArrayLock, LW_SHARED);
3241 
3242  for (index = 0; index < arrayP->numProcs; index++)
3243  {
3244  int pgprocno = arrayP->pgprocnos[index];
3245  PGPROC *proc = &allProcs[pgprocno];
3246 
3247  if (other_xids[index] == xid)
3248  {
3249  result = proc->pid;
3250  break;
3251  }
3252  }
3253 
3254  LWLockRelease(ProcArrayLock);
3255 
3256  return result;
3257 }
uint32 TransactionId
Definition: c.h:587
PROC_HDR * ProcGlobal
Definition: proc.c:80
TransactionId * xids
Definition: proc.h:359
#define InvalidTransactionId
Definition: transam.h:31

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

Referenced by pgrowlocks().

◆ CancelDBBackends()

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

Definition at line 3629 of file procarray.c.

3630 {
3631  ProcArrayStruct *arrayP = procArray;
3632  int index;
3633 
3634  /* tell all backends to die */
3635  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3636 
3637  for (index = 0; index < arrayP->numProcs; index++)
3638  {
3639  int pgprocno = arrayP->pgprocnos[index];
3640  PGPROC *proc = &allProcs[pgprocno];
3641 
3642  if (databaseid == InvalidOid || proc->databaseId == databaseid)
3643  {
3644  VirtualTransactionId procvxid;
3645  pid_t pid;
3646 
3647  GET_VXID_FROM_PGPROC(procvxid, *proc);
3648 
3649  proc->recoveryConflictPending = conflictPending;
3650  pid = proc->pid;
3651  if (pid != 0)
3652  {
3653  /*
3654  * Kill the pid if it's still here. If not, that's what we
3655  * wanted so ignore any errors.
3656  */
3657  (void) SendProcSignal(pid, sigmode, procvxid.backendId);
3658  }
3659  }
3660  }
3661 
3662  LWLockRelease(ProcArrayLock);
3663 }
#define GET_VXID_FROM_PGPROC(vxid, proc)
Definition: lock.h:82
@ LW_EXCLUSIVE
Definition: lwlock.h:104
#define InvalidOid
Definition: postgres_ext.h:36
int SendProcSignal(pid_t pid, ProcSignalReason reason, BackendId backendId)
Definition: procsignal.c:261
bool recoveryConflictPending
Definition: proc.h:205
Oid databaseId
Definition: proc.h:192
BackendId backendId
Definition: lock.h:66

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

Referenced by ResolveRecoveryConflictWithDatabase(), and SendRecoveryConflictWithBufferPin().

◆ CancelVirtualTransaction()

pid_t CancelVirtualTransaction ( VirtualTransactionId  vxid,
ProcSignalReason  sigmode 
)

Definition at line 3460 of file procarray.c.

3461 {
3462  return SignalVirtualTransaction(vxid, sigmode, true);
3463 }
pid_t SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode, bool conflictPending)
Definition: procarray.c:3466

References SignalVirtualTransaction().

Referenced by ResolveRecoveryConflictWithVirtualXIDs().

◆ CountDBBackends()

int CountDBBackends ( Oid  databaseid)

Definition at line 3568 of file procarray.c.

3569 {
3570  ProcArrayStruct *arrayP = procArray;
3571  int count = 0;
3572  int index;
3573 
3574  LWLockAcquire(ProcArrayLock, LW_SHARED);
3575 
3576  for (index = 0; index < arrayP->numProcs; index++)
3577  {
3578  int pgprocno = arrayP->pgprocnos[index];
3579  PGPROC *proc = &allProcs[pgprocno];
3580 
3581  if (proc->pid == 0)
3582  continue; /* do not count prepared xacts */
3583  if (!OidIsValid(databaseid) ||
3584  proc->databaseId == databaseid)
3585  count++;
3586  }
3587 
3588  LWLockRelease(ProcArrayLock);
3589 
3590  return count;
3591 }
#define OidIsValid(objectId)
Definition: c.h:710

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

Referenced by ResolveRecoveryConflictWithDatabase().

◆ CountDBConnections()

int CountDBConnections ( Oid  databaseid)

Definition at line 3598 of file procarray.c.

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

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

Referenced by CheckMyDatabase().

◆ CountOtherDBBackends()

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

Definition at line 3719 of file procarray.c.

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

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

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

◆ CountUserBackends()

int CountUserBackends ( Oid  roleid)

Definition at line 3669 of file procarray.c.

3670 {
3671  ProcArrayStruct *arrayP = procArray;
3672  int count = 0;
3673  int index;
3674 
3675  LWLockAcquire(ProcArrayLock, LW_SHARED);
3676 
3677  for (index = 0; index < arrayP->numProcs; index++)
3678  {
3679  int pgprocno = arrayP->pgprocnos[index];
3680  PGPROC *proc = &allProcs[pgprocno];
3681 
3682  if (proc->pid == 0)
3683  continue; /* do not count prepared xacts */
3684  if (proc->isBackgroundWorker)
3685  continue; /* do not count background workers */
3686  if (proc->roleId == roleid)
3687  count++;
3688  }
3689 
3690  LWLockRelease(ProcArrayLock);
3691 
3692  return count;
3693 }
Oid roleId
Definition: proc.h:193

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

Referenced by InitializeSessionUserId().

◆ CreateSharedProcArray()

void CreateSharedProcArray ( void  )

Definition at line 404 of file procarray.c.

405 {
406  bool found;
407 
408  /* Create or attach to the ProcArray shared structure */
410  ShmemInitStruct("Proc Array",
411  add_size(offsetof(ProcArrayStruct, pgprocnos),
412  mul_size(sizeof(int),
414  &found);
415 
416  if (!found)
417  {
418  /*
419  * We're the first - initialize.
420  */
421  procArray->numProcs = 0;
432  }
433 
435 
436  /* Create or attach to the KnownAssignedXids arrays too, if needed */
437  if (EnableHotStandby)
438  {
440  ShmemInitStruct("KnownAssignedXids",
441  mul_size(sizeof(TransactionId),
443  &found);
444  KnownAssignedXidsValid = (bool *)
445  ShmemInitStruct("KnownAssignedXidsValid",
446  mul_size(sizeof(bool), TOTAL_MAX_CACHED_SUBXIDS),
447  &found);
448  }
449 }
#define offsetof(type, field)
Definition: c.h:727
#define TOTAL_MAX_CACHED_SUBXIDS
#define PROCARRAY_MAXPROCS
static TransactionId * KnownAssignedXids
Definition: procarray.c:267
static bool * KnownAssignedXidsValid
Definition: procarray.c:268
Size add_size(Size s1, Size s2)
Definition: shmem.c:502
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:396
Size mul_size(Size s1, Size s2)
Definition: shmem.c:519
#define SpinLockInit(lock)
Definition: spin.h:60
PGPROC * allProcs
Definition: proc.h:356
TransactionId replication_slot_xmin
Definition: procarray.c:96
int maxKnownAssignedXids
Definition: procarray.c:80
TransactionId replication_slot_catalog_xmin
Definition: procarray.c:98
slock_t known_assigned_xids_lck
Definition: procarray.c:84
int numKnownAssignedXids
Definition: procarray.c:81
TransactionId lastOverflowedXid
Definition: procarray.c:93
int tailKnownAssignedXids
Definition: procarray.c:82
int headKnownAssignedXids
Definition: procarray.c:83
uint64 xactCompletionCount
Definition: transam.h:248
VariableCache ShmemVariableCache
Definition: varsup.c:34
bool EnableHotStandby
Definition: xlog.c:122

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

Referenced by CreateSharedMemoryAndSemaphores().

◆ ExpireAllKnownAssignedTransactionIds()

void ExpireAllKnownAssignedTransactionIds ( void  )

Definition at line 4487 of file procarray.c.

4488 {
4489  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4491 
4492  /*
4493  * Reset lastOverflowedXid. Currently, lastOverflowedXid has no use after
4494  * the call of this function. But do this for unification with what
4495  * ExpireOldKnownAssignedTransactionIds() do.
4496  */
4498  LWLockRelease(ProcArrayLock);
4499 }
static void KnownAssignedXidsRemovePreceding(TransactionId xid)
Definition: procarray.c:4953

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

Referenced by ShutdownRecoveryTransactionEnvironment().

◆ ExpireOldKnownAssignedTransactionIds()

void ExpireOldKnownAssignedTransactionIds ( TransactionId  xid)

Definition at line 4507 of file procarray.c.

4508 {
4509  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4510 
4511  /*
4512  * Reset lastOverflowedXid if we know all transactions that have been
4513  * possibly running are being gone. Not doing so could cause an incorrect
4514  * lastOverflowedXid value, which makes extra snapshots be marked as
4515  * suboverflowed.
4516  */
4520  LWLockRelease(ProcArrayLock);
4521 }
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300

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

4463 {
4465 
4466  /*
4467  * Uses same locking as transaction commit
4468  */
4469  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4470 
4471  KnownAssignedXidsRemoveTree(xid, nsubxids, subxids);
4472 
4473  /* As in ProcArrayEndTransaction, advance latestCompletedXid */
4475 
4476  /* ... and xactCompletionCount */
4478 
4479  LWLockRelease(ProcArrayLock);
4480 }
Assert(fmt[strlen(fmt) - 1] !='\n')
static void KnownAssignedXidsRemoveTree(TransactionId xid, int nsubxids, TransactionId *subxids)
Definition: procarray.c:4931
static void MaintainLatestCompletedXidRecovery(TransactionId latestXid)
Definition: procarray.c:974
HotStandbyState standbyState
Definition: xlogutils.c:56
@ STANDBY_INITIALIZED
Definition: xlogutils.h:50

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

Referenced by xact_redo_abort(), and xact_redo_commit().

◆ GetConflictingVirtualXIDs()

VirtualTransactionId* GetConflictingVirtualXIDs ( TransactionId  limitXmin,
Oid  dbOid 
)

Definition at line 3386 of file procarray.c.

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

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

Referenced by ResolveRecoveryConflictWithSnapshot(), and ResolveRecoveryConflictWithTablespace().

◆ GetCurrentVirtualXIDs()

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

Definition at line 3298 of file procarray.c.

3301 {
3302  VirtualTransactionId *vxids;
3303  ProcArrayStruct *arrayP = procArray;
3304  int count = 0;
3305  int index;
3306 
3307  /* allocate what's certainly enough result space */
3308  vxids = (VirtualTransactionId *)
3309  palloc(sizeof(VirtualTransactionId) * arrayP->maxProcs);
3310 
3311  LWLockAcquire(ProcArrayLock, LW_SHARED);
3312 
3313  for (index = 0; index < arrayP->numProcs; index++)
3314  {
3315  int pgprocno = arrayP->pgprocnos[index];
3316  PGPROC *proc = &allProcs[pgprocno];
3317  uint8 statusFlags = ProcGlobal->statusFlags[index];
3318 
3319  if (proc == MyProc)
3320  continue;
3321 
3322  if (excludeVacuum & statusFlags)
3323  continue;
3324 
3325  if (allDbs || proc->databaseId == MyDatabaseId)
3326  {
3327  /* Fetch xmin just once - might change on us */
3328  TransactionId pxmin = UINT32_ACCESS_ONCE(proc->xmin);
3329 
3330  if (excludeXmin0 && !TransactionIdIsValid(pxmin))
3331  continue;
3332 
3333  /*
3334  * InvalidTransactionId precedes all other XIDs, so a proc that
3335  * hasn't set xmin yet will not be rejected by this test.
3336  */
3337  if (!TransactionIdIsValid(limitXmin) ||
3338  TransactionIdPrecedesOrEquals(pxmin, limitXmin))
3339  {
3340  VirtualTransactionId vxid;
3341 
3342  GET_VXID_FROM_PGPROC(vxid, *proc);
3343  if (VirtualTransactionIdIsValid(vxid))
3344  vxids[count++] = vxid;
3345  }
3346  }
3347  }
3348 
3349  LWLockRelease(ProcArrayLock);
3350 
3351  *nvxids = count;
3352  return vxids;
3353 }
Oid MyDatabaseId
Definition: globals.c:89
void * palloc(Size size)
Definition: mcxt.c:1068
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:319

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

2097 {
2098  return TOTAL_MAX_CACHED_SUBXIDS;
2099 }

References TOTAL_MAX_CACHED_SUBXIDS.

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

◆ GetMaxSnapshotXidCount()

int GetMaxSnapshotXidCount ( void  )

Definition at line 2085 of file procarray.c.

2086 {
2087  return procArray->maxProcs;
2088 }

References ProcArrayStruct::maxProcs, and procArray.

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

◆ GetOldestActiveTransactionId()

TransactionId GetOldestActiveTransactionId ( void  )

Definition at line 2912 of file procarray.c.

2913 {
2914  ProcArrayStruct *arrayP = procArray;
2915  TransactionId *other_xids = ProcGlobal->xids;
2916  TransactionId oldestRunningXid;
2917  int index;
2918 
2920 
2921  /*
2922  * Read nextXid, as the upper bound of what's still active.
2923  *
2924  * Reading a TransactionId is atomic, but we must grab the lock to make
2925  * sure that all XIDs < nextXid are already present in the proc array (or
2926  * have already completed), when we spin over it.
2927  */
2928  LWLockAcquire(XidGenLock, LW_SHARED);
2930  LWLockRelease(XidGenLock);
2931 
2932  /*
2933  * Spin over procArray collecting all xids and subxids.
2934  */
2935  LWLockAcquire(ProcArrayLock, LW_SHARED);
2936  for (index = 0; index < arrayP->numProcs; index++)
2937  {
2938  TransactionId xid;
2939 
2940  /* Fetch xid just once - see GetNewTransactionId */
2941  xid = UINT32_ACCESS_ONCE(other_xids[index]);
2942 
2943  if (!TransactionIdIsNormal(xid))
2944  continue;
2945 
2946  if (TransactionIdPrecedes(xid, oldestRunningXid))
2947  oldestRunningXid = xid;
2948 
2949  /*
2950  * Top-level XID of a transaction is always less than any of its
2951  * subxids, so we don't need to check if any of the subxids are
2952  * smaller than oldestRunningXid
2953  */
2954  }
2955  LWLockRelease(ProcArrayLock);
2956 
2957  return oldestRunningXid;
2958 }
FullTransactionId nextXid
Definition: transam.h:220
#define XidFromFullTransactionId(x)
Definition: transam.h:48
#define TransactionIdIsNormal(xid)
Definition: transam.h:42
bool RecoveryInProgress(void)
Definition: xlog.c:5753

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

Referenced by CreateCheckPoint().

◆ GetOldestNonRemovableTransactionId()

TransactionId GetOldestNonRemovableTransactionId ( Relation  rel)

Definition at line 2021 of file procarray.c.

2022 {
2023  ComputeXidHorizonsResult horizons;
2024 
2025  ComputeXidHorizons(&horizons);
2026 
2027  switch (GlobalVisHorizonKindForRel(rel))
2028  {
2029  case VISHORIZON_SHARED:
2030  return horizons.shared_oldest_nonremovable;
2031  case VISHORIZON_CATALOG:
2032  return horizons.catalog_oldest_nonremovable;
2033  case VISHORIZON_DATA:
2034  return horizons.data_oldest_nonremovable;
2035  case VISHORIZON_TEMP:
2036  return horizons.temp_oldest_nonremovable;
2037  }
2038 
2039  /* just to prevent compiler warnings */
2040  return InvalidTransactionId;
2041 }
static void ComputeXidHorizons(ComputeXidHorizonsResult *h)
Definition: procarray.c:1711
@ VISHORIZON_SHARED
Definition: procarray.c:253
@ VISHORIZON_DATA
Definition: procarray.c:255
@ VISHORIZON_CATALOG
Definition: procarray.c:254
@ VISHORIZON_TEMP
Definition: procarray.c:256
static GlobalVisHorizonKind GlobalVisHorizonKindForRel(Relation rel)
Definition: procarray.c:1987
TransactionId data_oldest_nonremovable
Definition: procarray.c:239
TransactionId temp_oldest_nonremovable
Definition: procarray.c:245
TransactionId shared_oldest_nonremovable
Definition: procarray.c:216
TransactionId catalog_oldest_nonremovable
Definition: procarray.c:233

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

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

◆ GetOldestSafeDecodingTransactionId()

TransactionId GetOldestSafeDecodingTransactionId ( bool  catalogOnly)

Definition at line 2977 of file procarray.c.

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

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

Referenced by CreateInitDecodingContext(), and SnapBuildInitialSnapshot().

◆ GetOldestTransactionIdConsideredRunning()

TransactionId GetOldestTransactionIdConsideredRunning ( void  )

Definition at line 2050 of file procarray.c.

2051 {
2052  ComputeXidHorizonsResult horizons;
2053 
2054  ComputeXidHorizons(&horizons);
2055 
2056  return horizons.oldest_considered_running;
2057 }
TransactionId oldest_considered_running
Definition: procarray.c:207

References ComputeXidHorizons(), and ComputeXidHorizonsResult::oldest_considered_running.

Referenced by CreateCheckPoint(), and CreateRestartPoint().

◆ GetReplicationHorizons()

void GetReplicationHorizons ( TransactionId slot_xmin,
TransactionId catalog_xmin 
)

Definition at line 2063 of file procarray.c.

2064 {
2065  ComputeXidHorizonsResult horizons;
2066 
2067  ComputeXidHorizons(&horizons);
2068 
2069  /*
2070  * Don't want to use shared_oldest_nonremovable here, as that contains the
2071  * effect of replication slot's catalog_xmin. We want to send a separate
2072  * feedback for the catalog horizon, so the primary can remove data table
2073  * contents more aggressively.
2074  */
2075  *xmin = horizons.shared_oldest_nonremovable_raw;
2076  *catalog_xmin = horizons.slot_catalog_xmin;
2077 }
TransactionId slot_catalog_xmin
Definition: procarray.c:194
TransactionId shared_oldest_nonremovable_raw
Definition: procarray.c:227

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

Referenced by XLogWalRcvSendHSFeedback().

◆ GetRunningTransactionData()

RunningTransactions GetRunningTransactionData ( void  )

Definition at line 2737 of file procarray.c.

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

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

Referenced by LogStandbySnapshot().

◆ GetSnapshotData()

Snapshot GetSnapshotData ( Snapshot  snapshot)

Definition at line 2222 of file procarray.c.

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

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

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

◆ GetVirtualXIDsDelayingChkpt()

VirtualTransactionId* GetVirtualXIDsDelayingChkpt ( int *  nvxids,
int  type 
)

Definition at line 3075 of file procarray.c.

3076 {
3077  VirtualTransactionId *vxids;
3078  ProcArrayStruct *arrayP = procArray;
3079  int count = 0;
3080  int index;
3081 
3082  Assert(type != 0);
3083 
3084  /* allocate what's certainly enough result space */
3085  vxids = (VirtualTransactionId *)
3086  palloc(sizeof(VirtualTransactionId) * arrayP->maxProcs);
3087 
3088  LWLockAcquire(ProcArrayLock, LW_SHARED);
3089 
3090  for (index = 0; index < arrayP->numProcs; index++)
3091  {
3092  int pgprocno = arrayP->pgprocnos[index];
3093  PGPROC *proc = &allProcs[pgprocno];
3094 
3095  if ((proc->delayChkptFlags & type) != 0)
3096  {
3097  VirtualTransactionId vxid;
3098 
3099  GET_VXID_FROM_PGPROC(vxid, *proc);
3100  if (VirtualTransactionIdIsValid(vxid))
3101  vxids[count++] = vxid;
3102  }
3103  }
3104 
3105  LWLockRelease(ProcArrayLock);
3106 
3107  *nvxids = count;
3108  return vxids;
3109 }
int delayChkptFlags
Definition: proc.h:225

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

Referenced by CreateCheckPoint().

◆ HaveVirtualXIDsDelayingChkpt()

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

Definition at line 3121 of file procarray.c.

3122 {
3123  bool result = false;
3124  ProcArrayStruct *arrayP = procArray;
3125  int index;
3126 
3127  Assert(type != 0);
3128 
3129  LWLockAcquire(ProcArrayLock, LW_SHARED);
3130 
3131  for (index = 0; index < arrayP->numProcs; index++)
3132  {
3133  int pgprocno = arrayP->pgprocnos[index];
3134  PGPROC *proc = &allProcs[pgprocno];
3135  VirtualTransactionId vxid;
3136 
3137  GET_VXID_FROM_PGPROC(vxid, *proc);
3138 
3139  if ((proc->delayChkptFlags & type) != 0 &&
3141  {
3142  int i;
3143 
3144  for (i = 0; i < nvxids; i++)
3145  {
3146  if (VirtualTransactionIdEquals(vxid, vxids[i]))
3147  {
3148  result = true;
3149  break;
3150  }
3151  }
3152  if (result)
3153  break;
3154  }
3155  }
3156 
3157  LWLockRelease(ProcArrayLock);
3158 
3159  return result;
3160 }
int i
Definition: isn.c:73
#define VirtualTransactionIdEquals(vxid1, vxid2)
Definition: lock.h:76

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

Referenced by CreateCheckPoint().

◆ IsBackendPid()

bool IsBackendPid ( int  pid)

Definition at line 3265 of file procarray.c.

3266 {
3267  return (BackendPidGetProc(pid) != NULL);
3268 }
PGPROC * BackendPidGetProc(int pid)
Definition: procarray.c:3170

References BackendPidGetProc().

Referenced by pg_stat_get_subscription().

◆ MinimumActiveBackends()

bool MinimumActiveBackends ( int  min)

Definition at line 3515 of file procarray.c.

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

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

Referenced by XLogFlush().

◆ ProcArrayAdd()

void ProcArrayAdd ( PGPROC proc)

Definition at line 455 of file procarray.c.

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

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

Referenced by InitProcessPhase2(), and MarkAsPrepared().

◆ ProcArrayApplyRecoveryInfo()

void ProcArrayApplyRecoveryInfo ( RunningTransactions  running)

Definition at line 1039 of file procarray.c.

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

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

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

◆ ProcArrayApplyXidAssignment()

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

Definition at line 1285 of file procarray.c.

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

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

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

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

Referenced by PrepareTransaction().

◆ ProcArrayEndTransaction()

void ProcArrayEndTransaction ( PGPROC proc,
TransactionId  latestXid 
)

Definition at line 653 of file procarray.c.

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

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

Referenced by AbortTransaction(), and CommitTransaction().

◆ ProcArrayGetReplicationSlotXmin()

void ProcArrayGetReplicationSlotXmin ( TransactionId xmin,
TransactionId catalog_xmin 
)

Definition at line 3927 of file procarray.c.

3929 {
3930  LWLockAcquire(ProcArrayLock, LW_SHARED);
3931 
3932  if (xmin != NULL)
3934 
3935  if (catalog_xmin != NULL)
3936  *catalog_xmin = procArray->replication_slot_catalog_xmin;
3937 
3938  LWLockRelease(ProcArrayLock);
3939 }

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

Referenced by logical_begin_heap_rewrite().

◆ ProcArrayInitRecovery()

void ProcArrayInitRecovery ( TransactionId  initializedUptoXID)

Definition at line 1008 of file procarray.c.

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

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

Referenced by StartupXLOG().

◆ ProcArrayInstallImportedXmin()

bool ProcArrayInstallImportedXmin ( TransactionId  xmin,
VirtualTransactionId sourcevxid 
)

Definition at line 2585 of file procarray.c.

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

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

Referenced by GetSerializableTransactionSnapshotInt(), and SetTransactionSnapshot().

◆ ProcArrayInstallRestoredXmin()

bool ProcArrayInstallRestoredXmin ( TransactionId  xmin,
PGPROC proc 
)

Definition at line 2664 of file procarray.c.

2665 {
2666  bool result = false;
2667  TransactionId xid;
2668 
2670  Assert(proc != NULL);
2671 
2672  /*
2673  * Get an exclusive lock so that we can copy statusFlags from source proc.
2674  */
2675  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
2676 
2677  /*
2678  * Be certain that the referenced PGPROC has an advertised xmin which is
2679  * no later than the one we're installing, so that the system-wide xmin
2680  * can't go backwards. Also, make sure it's running in the same database,
2681  * so that the per-database xmin cannot go backwards.
2682  */
2683  xid = UINT32_ACCESS_ONCE(proc->xmin);
2684  if (proc->databaseId == MyDatabaseId &&
2685  TransactionIdIsNormal(xid) &&
2686  TransactionIdPrecedesOrEquals(xid, xmin))
2687  {
2688  /*
2689  * Install xmin and propagate the statusFlags that affect how the
2690  * value is interpreted by vacuum.
2691  */
2692  MyProc->xmin = TransactionXmin = xmin;
2694  (proc->statusFlags & PROC_XMIN_FLAGS);
2696 
2697  result = true;
2698  }
2699 
2700  LWLockRelease(ProcArrayLock);
2701 
2702  return result;
2703 }
#define PROC_XMIN_FLAGS
Definition: proc.h:69

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

Referenced by SetTransactionSnapshot().

◆ ProcArrayRemove()

void ProcArrayRemove ( PGPROC proc,
TransactionId  latestXid 
)

Definition at line 551 of file procarray.c.

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

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

Referenced by FinishPreparedTransaction(), and RemoveProcFromArray().

◆ ProcArraySetReplicationSlotXmin()

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

Definition at line 3905 of file procarray.c.

3907 {
3908  Assert(!already_locked || LWLockHeldByMe(ProcArrayLock));
3909 
3910  if (!already_locked)
3911  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3912 
3914  procArray->replication_slot_catalog_xmin = catalog_xmin;
3915 
3916  if (!already_locked)
3917  LWLockRelease(ProcArrayLock);
3918 }

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

Referenced by ReplicationSlotsComputeRequiredXmin().

◆ ProcArrayShmemSize()

Size ProcArrayShmemSize ( void  )

Definition at line 362 of file procarray.c.

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

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

Referenced by CalculateShmemSize().

◆ RecordKnownAssignedTransactionIds()

void RecordKnownAssignedTransactionIds ( TransactionId  xid)

Definition at line 4392 of file procarray.c.

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

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

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

◆ SignalVirtualTransaction()

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

Definition at line 3466 of file procarray.c.

3468 {
3469  ProcArrayStruct *arrayP = procArray;
3470  int index;
3471  pid_t pid = 0;
3472 
3473  LWLockAcquire(ProcArrayLock, LW_SHARED);
3474 
3475  for (index = 0; index < arrayP->numProcs; index++)
3476  {
3477  int pgprocno = arrayP->pgprocnos[index];
3478  PGPROC *proc = &allProcs[pgprocno];
3479  VirtualTransactionId procvxid;
3480 
3481  GET_VXID_FROM_PGPROC(procvxid, *proc);
3482 
3483  if (procvxid.backendId == vxid.backendId &&
3484  procvxid.localTransactionId == vxid.localTransactionId)
3485  {
3486  proc->recoveryConflictPending = conflictPending;
3487  pid = proc->pid;
3488  if (pid != 0)
3489  {
3490  /*
3491  * Kill the pid if it's still here. If not, that's what we
3492  * wanted so ignore any errors.
3493  */
3494  (void) SendProcSignal(pid, sigmode, vxid.backendId);
3495  }
3496  break;
3497  }
3498  }
3499 
3500  LWLockRelease(ProcArrayLock);
3501 
3502  return pid;
3503 }

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

Referenced by CancelVirtualTransaction(), and ResolveRecoveryConflictWithLock().

◆ TerminateOtherDBBackends()

void TerminateOtherDBBackends ( Oid  databaseId)

Definition at line 3797 of file procarray.c.

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

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

Referenced by dropdb().

◆ TransactionIdIsActive()

bool TransactionIdIsActive ( TransactionId  xid)

Definition at line 1601 of file procarray.c.

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

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

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

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

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

◆ XidCacheRemoveRunningXids()

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

Definition at line 3950 of file procarray.c.

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

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

Referenced by RecordTransactionAbort().