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)
 
void KnownAssignedTransactionIdsIdleMaintenance (void)
 
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 *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 3102 of file procarray.c.

3103 {
3104  PGPROC *result;
3105 
3106  if (pid == 0) /* never match dummy PGPROCs */
3107  return NULL;
3108 
3109  LWLockAcquire(ProcArrayLock, LW_SHARED);
3110 
3111  result = BackendPidGetProcWithLock(pid);
3112 
3113  LWLockRelease(ProcArrayLock);
3114 
3115  return result;
3116 }
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1195
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
@ LW_SHARED
Definition: lwlock.h:117
PGPROC * BackendPidGetProcWithLock(int pid)
Definition: procarray.c:3125
Definition: proc.h:162

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

3126 {
3127  PGPROC *result = NULL;
3128  ProcArrayStruct *arrayP = procArray;
3129  int index;
3130 
3131  if (pid == 0) /* never match dummy PGPROCs */
3132  return NULL;
3133 
3134  for (index = 0; index < arrayP->numProcs; index++)
3135  {
3136  PGPROC *proc = &allProcs[arrayP->pgprocnos[index]];
3137 
3138  if (proc->pid == pid)
3139  {
3140  result = proc;
3141  break;
3142  }
3143  }
3144 
3145  return result;
3146 }
static PGPROC * allProcs
Definition: procarray.c:272
static ProcArrayStruct * procArray
Definition: procarray.c:270
int pid
Definition: proc.h:186
int pgprocnos[FLEXIBLE_ARRAY_MEMBER]
Definition: procarray.c:100
Definition: type.h:95

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

Referenced by BackendPidGetProc(), and GetBlockerStatusData().

◆ BackendXidGetPid()

int BackendXidGetPid ( TransactionId  xid)

Definition at line 3162 of file procarray.c.

3163 {
3164  int result = 0;
3165  ProcArrayStruct *arrayP = procArray;
3166  TransactionId *other_xids = ProcGlobal->xids;
3167  int index;
3168 
3169  if (xid == InvalidTransactionId) /* never match invalid xid */
3170  return 0;
3171 
3172  LWLockAcquire(ProcArrayLock, LW_SHARED);
3173 
3174  for (index = 0; index < arrayP->numProcs; index++)
3175  {
3176  if (other_xids[index] == xid)
3177  {
3178  int pgprocno = arrayP->pgprocnos[index];
3179  PGPROC *proc = &allProcs[pgprocno];
3180 
3181  result = proc->pid;
3182  break;
3183  }
3184  }
3185 
3186  LWLockRelease(ProcArrayLock);
3187 
3188  return result;
3189 }
uint32 TransactionId
Definition: c.h:641
PROC_HDR * ProcGlobal
Definition: proc.c:78
TransactionId * xids
Definition: proc.h:365
#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 3566 of file procarray.c.

3567 {
3568  ProcArrayStruct *arrayP = procArray;
3569  int index;
3570 
3571  /* tell all backends to die */
3572  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3573 
3574  for (index = 0; index < arrayP->numProcs; index++)
3575  {
3576  int pgprocno = arrayP->pgprocnos[index];
3577  PGPROC *proc = &allProcs[pgprocno];
3578 
3579  if (databaseid == InvalidOid || proc->databaseId == databaseid)
3580  {
3581  VirtualTransactionId procvxid;
3582  pid_t pid;
3583 
3584  GET_VXID_FROM_PGPROC(procvxid, *proc);
3585 
3586  proc->recoveryConflictPending = conflictPending;
3587  pid = proc->pid;
3588  if (pid != 0)
3589  {
3590  /*
3591  * Kill the pid if it's still here. If not, that's what we
3592  * wanted so ignore any errors.
3593  */
3594  (void) SendProcSignal(pid, sigmode, procvxid.backendId);
3595  }
3596  }
3597  }
3598 
3599  LWLockRelease(ProcArrayLock);
3600 }
#define GET_VXID_FROM_PGPROC(vxid, proc)
Definition: lock.h:77
@ LW_EXCLUSIVE
Definition: lwlock.h:116
#define InvalidOid
Definition: postgres_ext.h:36
int SendProcSignal(pid_t pid, ProcSignalReason reason, BackendId backendId)
Definition: procsignal.c:262
bool recoveryConflictPending
Definition: proc.h:211
Oid databaseId
Definition: proc.h:198
BackendId backendId
Definition: lock.h:61

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

3398 {
3399  return SignalVirtualTransaction(vxid, sigmode, true);
3400 }
pid_t SignalVirtualTransaction(VirtualTransactionId vxid, ProcSignalReason sigmode, bool conflictPending)
Definition: procarray.c:3403

References SignalVirtualTransaction().

Referenced by ResolveRecoveryConflictWithVirtualXIDs().

◆ CountDBBackends()

int CountDBBackends ( Oid  databaseid)

Definition at line 3505 of file procarray.c.

3506 {
3507  ProcArrayStruct *arrayP = procArray;
3508  int count = 0;
3509  int index;
3510 
3511  LWLockAcquire(ProcArrayLock, LW_SHARED);
3512 
3513  for (index = 0; index < arrayP->numProcs; index++)
3514  {
3515  int pgprocno = arrayP->pgprocnos[index];
3516  PGPROC *proc = &allProcs[pgprocno];
3517 
3518  if (proc->pid == 0)
3519  continue; /* do not count prepared xacts */
3520  if (!OidIsValid(databaseid) ||
3521  proc->databaseId == databaseid)
3522  count++;
3523  }
3524 
3525  LWLockRelease(ProcArrayLock);
3526 
3527  return count;
3528 }
#define OidIsValid(objectId)
Definition: c.h:764

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

3536 {
3537  ProcArrayStruct *arrayP = procArray;
3538  int count = 0;
3539  int index;
3540 
3541  LWLockAcquire(ProcArrayLock, LW_SHARED);
3542 
3543  for (index = 0; index < arrayP->numProcs; index++)
3544  {
3545  int pgprocno = arrayP->pgprocnos[index];
3546  PGPROC *proc = &allProcs[pgprocno];
3547 
3548  if (proc->pid == 0)
3549  continue; /* do not count prepared xacts */
3550  if (proc->isBackgroundWorker)
3551  continue; /* do not count background workers */
3552  if (!OidIsValid(databaseid) ||
3553  proc->databaseId == databaseid)
3554  count++;
3555  }
3556 
3557  LWLockRelease(ProcArrayLock);
3558 
3559  return count;
3560 }
bool isBackgroundWorker
Definition: proc.h:204

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

3657 {
3658  ProcArrayStruct *arrayP = procArray;
3659 
3660 #define MAXAUTOVACPIDS 10 /* max autovacs to SIGTERM per iteration */
3661  int autovac_pids[MAXAUTOVACPIDS];
3662  int tries;
3663 
3664  /* 50 tries with 100ms sleep between tries makes 5 sec total wait */
3665  for (tries = 0; tries < 50; tries++)
3666  {
3667  int nautovacs = 0;
3668  bool found = false;
3669  int index;
3670 
3672 
3673  *nbackends = *nprepared = 0;
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  uint8 statusFlags = ProcGlobal->statusFlags[index];
3682 
3683  if (proc->databaseId != databaseId)
3684  continue;
3685  if (proc == MyProc)
3686  continue;
3687 
3688  found = true;
3689 
3690  if (proc->pid == 0)
3691  (*nprepared)++;
3692  else
3693  {
3694  (*nbackends)++;
3695  if ((statusFlags & PROC_IS_AUTOVACUUM) &&
3696  nautovacs < MAXAUTOVACPIDS)
3697  autovac_pids[nautovacs++] = proc->pid;
3698  }
3699  }
3700 
3701  LWLockRelease(ProcArrayLock);
3702 
3703  if (!found)
3704  return false; /* no conflicting backends, so done */
3705 
3706  /*
3707  * Send SIGTERM to any conflicting autovacuums before sleeping. We
3708  * postpone this step until after the loop because we don't want to
3709  * hold ProcArrayLock while issuing kill(). We have no idea what might
3710  * block kill() inside the kernel...
3711  */
3712  for (index = 0; index < nautovacs; index++)
3713  (void) kill(autovac_pids[index], SIGTERM); /* ignore any error */
3714 
3715  /* sleep, then try again */
3716  pg_usleep(100 * 1000L); /* 100ms */
3717  }
3718 
3719  return true; /* timed out, still conflicts */
3720 }
unsigned char uint8
Definition: c.h:493
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121
#define PROC_IS_AUTOVACUUM
Definition: proc.h:56
#define MAXAUTOVACPIDS
void pg_usleep(long microsec)
Definition: signal.c:53
PGPROC * MyProc
Definition: proc.c:66
uint8 * statusFlags
Definition: proc.h:377
#define kill(pid, sig)
Definition: win32_port.h:485

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

3607 {
3608  ProcArrayStruct *arrayP = procArray;
3609  int count = 0;
3610  int index;
3611 
3612  LWLockAcquire(ProcArrayLock, LW_SHARED);
3613 
3614  for (index = 0; index < arrayP->numProcs; index++)
3615  {
3616  int pgprocno = arrayP->pgprocnos[index];
3617  PGPROC *proc = &allProcs[pgprocno];
3618 
3619  if (proc->pid == 0)
3620  continue; /* do not count prepared xacts */
3621  if (proc->isBackgroundWorker)
3622  continue; /* do not count background workers */
3623  if (proc->roleId == roleid)
3624  count++;
3625  }
3626 
3627  LWLockRelease(ProcArrayLock);
3628 
3629  return count;
3630 }
Oid roleId
Definition: proc.h:199

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

420 {
421  bool found;
422 
423  /* Create or attach to the ProcArray shared structure */
425  ShmemInitStruct("Proc Array",
426  add_size(offsetof(ProcArrayStruct, pgprocnos),
427  mul_size(sizeof(int),
429  &found);
430 
431  if (!found)
432  {
433  /*
434  * We're the first - initialize.
435  */
436  procArray->numProcs = 0;
446  }
447 
449 
450  /* Create or attach to the KnownAssignedXids arrays too, if needed */
451  if (EnableHotStandby)
452  {
454  ShmemInitStruct("KnownAssignedXids",
455  mul_size(sizeof(TransactionId),
457  &found);
458  KnownAssignedXidsValid = (bool *)
459  ShmemInitStruct("KnownAssignedXidsValid",
460  mul_size(sizeof(bool), TOTAL_MAX_CACHED_SUBXIDS),
461  &found);
462  }
463 }
#define TOTAL_MAX_CACHED_SUBXIDS
#define PROCARRAY_MAXPROCS
static TransactionId * KnownAssignedXids
Definition: procarray.c:282
static bool * KnownAssignedXidsValid
Definition: procarray.c:283
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
PGPROC * allProcs
Definition: proc.h:362
TransactionId replication_slot_xmin
Definition: procarray.c:95
int maxKnownAssignedXids
Definition: procarray.c:80
TransactionId replication_slot_catalog_xmin
Definition: procarray.c:97
int numKnownAssignedXids
Definition: procarray.c:81
TransactionId lastOverflowedXid
Definition: procarray.c:92
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:124

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

Referenced by CreateOrAttachShmemStructs().

◆ ExpireAllKnownAssignedTransactionIds()

void ExpireAllKnownAssignedTransactionIds ( void  )

Definition at line 4431 of file procarray.c.

4432 {
4433  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4435 
4436  /*
4437  * Reset lastOverflowedXid. Currently, lastOverflowedXid has no use after
4438  * the call of this function. But do this for unification with what
4439  * ExpireOldKnownAssignedTransactionIds() do.
4440  */
4442  LWLockRelease(ProcArrayLock);
4443 }
static void KnownAssignedXidsRemovePreceding(TransactionId removeXid)
Definition: procarray.c:4944

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

Referenced by ShutdownRecoveryTransactionEnvironment().

◆ ExpireOldKnownAssignedTransactionIds()

void ExpireOldKnownAssignedTransactionIds ( TransactionId  xid)

Definition at line 4451 of file procarray.c.

4452 {
4453  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4454 
4455  /*
4456  * Reset lastOverflowedXid if we know all transactions that have been
4457  * possibly running are being gone. Not doing so could cause an incorrect
4458  * lastOverflowedXid value, which makes extra snapshots be marked as
4459  * suboverflowed.
4460  */
4464  LWLockRelease(ProcArrayLock);
4465 }
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:280

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

Referenced by ProcArrayApplyRecoveryInfo().

◆ ExpireTreeKnownAssignedTransactionIds()

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

Definition at line 4405 of file procarray.c.

4407 {
4409 
4410  /*
4411  * Uses same locking as transaction commit
4412  */
4413  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
4414 
4415  KnownAssignedXidsRemoveTree(xid, nsubxids, subxids);
4416 
4417  /* As in ProcArrayEndTransaction, advance latestCompletedXid */
4419 
4420  /* ... and xactCompletionCount */
4422 
4423  LWLockRelease(ProcArrayLock);
4424 }
Assert(fmt[strlen(fmt) - 1] !='\n')
static void KnownAssignedXidsRemoveTree(TransactionId xid, int nsubxids, TransactionId *subxids)
Definition: procarray.c:4922
static void MaintainLatestCompletedXidRecovery(TransactionId latestXid)
Definition: procarray.c:988
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 3323 of file procarray.c.

3324 {
3325  static VirtualTransactionId *vxids;
3326  ProcArrayStruct *arrayP = procArray;
3327  int count = 0;
3328  int index;
3329 
3330  /*
3331  * If first time through, get workspace to remember main XIDs in. We
3332  * malloc it permanently to avoid repeated palloc/pfree overhead. Allow
3333  * result space, remembering room for a terminator.
3334  */
3335  if (vxids == NULL)
3336  {
3337  vxids = (VirtualTransactionId *)
3338  malloc(sizeof(VirtualTransactionId) * (arrayP->maxProcs + 1));
3339  if (vxids == NULL)
3340  ereport(ERROR,
3341  (errcode(ERRCODE_OUT_OF_MEMORY),
3342  errmsg("out of memory")));
3343  }
3344 
3345  LWLockAcquire(ProcArrayLock, LW_SHARED);
3346 
3347  for (index = 0; index < arrayP->numProcs; index++)
3348  {
3349  int pgprocno = arrayP->pgprocnos[index];
3350  PGPROC *proc = &allProcs[pgprocno];
3351 
3352  /* Exclude prepared transactions */
3353  if (proc->pid == 0)
3354  continue;
3355 
3356  if (!OidIsValid(dbOid) ||
3357  proc->databaseId == dbOid)
3358  {
3359  /* Fetch xmin just once - can't change on us, but good coding */
3360  TransactionId pxmin = UINT32_ACCESS_ONCE(proc->xmin);
3361 
3362  /*
3363  * We ignore an invalid pxmin because this means that backend has
3364  * no snapshot currently. We hold a Share lock to avoid contention
3365  * with users taking snapshots. That is not a problem because the
3366  * current xmin is always at least one higher than the latest
3367  * removed xid, so any new snapshot would never conflict with the
3368  * test here.
3369  */
3370  if (!TransactionIdIsValid(limitXmin) ||
3371  (TransactionIdIsValid(pxmin) && !TransactionIdFollows(pxmin, limitXmin)))
3372  {
3373  VirtualTransactionId vxid;
3374 
3375  GET_VXID_FROM_PGPROC(vxid, *proc);
3376  if (VirtualTransactionIdIsValid(vxid))
3377  vxids[count++] = vxid;
3378  }
3379  }
3380  }
3381 
3382  LWLockRelease(ProcArrayLock);
3383 
3384  /* add the terminator */
3385  vxids[count].backendId = InvalidBackendId;
3387 
3388  return vxids;
3389 }
#define InvalidBackendId
Definition: backendid.h:23
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#define malloc(a)
Definition: header.h:50
#define VirtualTransactionIdIsValid(vxid)
Definition: lock.h:67
#define InvalidLocalTransactionId
Definition: lock.h:65
#define UINT32_ACCESS_ONCE(var)
Definition: procarray.c:69
TransactionId xmin
Definition: proc.h:178
LocalTransactionId localTransactionId
Definition: lock.h:62
bool TransactionIdFollows(TransactionId id1, TransactionId id2)
Definition: transam.c:314
#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 3230 of file procarray.c.

3233 {
3234  VirtualTransactionId *vxids;
3235  ProcArrayStruct *arrayP = procArray;
3236  int count = 0;
3237  int index;
3238 
3239  /* allocate what's certainly enough result space */
3240  vxids = (VirtualTransactionId *)
3241  palloc(sizeof(VirtualTransactionId) * arrayP->maxProcs);
3242 
3243  LWLockAcquire(ProcArrayLock, LW_SHARED);
3244 
3245  for (index = 0; index < arrayP->numProcs; index++)
3246  {
3247  int pgprocno = arrayP->pgprocnos[index];
3248  PGPROC *proc = &allProcs[pgprocno];
3249  uint8 statusFlags = ProcGlobal->statusFlags[index];
3250 
3251  if (proc == MyProc)
3252  continue;
3253 
3254  if (excludeVacuum & statusFlags)
3255  continue;
3256 
3257  if (allDbs || proc->databaseId == MyDatabaseId)
3258  {
3259  /* Fetch xmin just once - might change on us */
3260  TransactionId pxmin = UINT32_ACCESS_ONCE(proc->xmin);
3261 
3262  if (excludeXmin0 && !TransactionIdIsValid(pxmin))
3263  continue;
3264 
3265  /*
3266  * InvalidTransactionId precedes all other XIDs, so a proc that
3267  * hasn't set xmin yet will not be rejected by this test.
3268  */
3269  if (!TransactionIdIsValid(limitXmin) ||
3270  TransactionIdPrecedesOrEquals(pxmin, limitXmin))
3271  {
3272  VirtualTransactionId vxid;
3273 
3274  GET_VXID_FROM_PGPROC(vxid, *proc);
3275  if (VirtualTransactionIdIsValid(vxid))
3276  vxids[count++] = vxid;
3277  }
3278  }
3279  }
3280 
3281  LWLockRelease(ProcArrayLock);
3282 
3283  *nvxids = count;
3284  return vxids;
3285 }
Oid MyDatabaseId
Definition: globals.c:89
void * palloc(Size size)
Definition: mcxt.c:1226
bool TransactionIdPrecedesOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:299

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

2062 {
2063  return TOTAL_MAX_CACHED_SUBXIDS;
2064 }

References TOTAL_MAX_CACHED_SUBXIDS.

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

◆ GetMaxSnapshotXidCount()

int GetMaxSnapshotXidCount ( void  )

Definition at line 2050 of file procarray.c.

2051 {
2052  return procArray->maxProcs;
2053 }

References ProcArrayStruct::maxProcs, and procArray.

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

◆ GetOldestActiveTransactionId()

TransactionId GetOldestActiveTransactionId ( void  )

Definition at line 2844 of file procarray.c.

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

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

1987 {
1988  ComputeXidHorizonsResult horizons;
1989 
1990  ComputeXidHorizons(&horizons);
1991 
1992  switch (GlobalVisHorizonKindForRel(rel))
1993  {
1994  case VISHORIZON_SHARED:
1995  return horizons.shared_oldest_nonremovable;
1996  case VISHORIZON_CATALOG:
1997  return horizons.catalog_oldest_nonremovable;
1998  case VISHORIZON_DATA:
1999  return horizons.data_oldest_nonremovable;
2000  case VISHORIZON_TEMP:
2001  return horizons.temp_oldest_nonremovable;
2002  }
2003 
2004  /* just to prevent compiler warnings */
2005  return InvalidTransactionId;
2006 }
static void ComputeXidHorizons(ComputeXidHorizonsResult *h)
Definition: procarray.c:1716
@ VISHORIZON_SHARED
Definition: procarray.c:252
@ VISHORIZON_DATA
Definition: procarray.c:254
@ VISHORIZON_CATALOG
Definition: procarray.c:253
@ VISHORIZON_TEMP
Definition: procarray.c:255
static GlobalVisHorizonKind GlobalVisHorizonKindForRel(Relation rel)
Definition: procarray.c:1952
TransactionId data_oldest_nonremovable
Definition: procarray.c:238
TransactionId temp_oldest_nonremovable
Definition: procarray.c:244
TransactionId shared_oldest_nonremovable
Definition: procarray.c:215
TransactionId catalog_oldest_nonremovable
Definition: procarray.c:232

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_get_cutoffs().

◆ GetOldestSafeDecodingTransactionId()

TransactionId GetOldestSafeDecodingTransactionId ( bool  catalogOnly)

Definition at line 2909 of file procarray.c.

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

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

2016 {
2017  ComputeXidHorizonsResult horizons;
2018 
2019  ComputeXidHorizons(&horizons);
2020 
2021  return horizons.oldest_considered_running;
2022 }
TransactionId oldest_considered_running
Definition: procarray.c:206

References ComputeXidHorizons(), and ComputeXidHorizonsResult::oldest_considered_running.

Referenced by CreateCheckPoint(), and CreateRestartPoint().

◆ GetReplicationHorizons()

void GetReplicationHorizons ( TransactionId xmin,
TransactionId catalog_xmin 
)

Definition at line 2028 of file procarray.c.

2029 {
2030  ComputeXidHorizonsResult horizons;
2031 
2032  ComputeXidHorizons(&horizons);
2033 
2034  /*
2035  * Don't want to use shared_oldest_nonremovable here, as that contains the
2036  * effect of replication slot's catalog_xmin. We want to send a separate
2037  * feedback for the catalog horizon, so the primary can remove data table
2038  * contents more aggressively.
2039  */
2040  *xmin = horizons.shared_oldest_nonremovable_raw;
2041  *catalog_xmin = horizons.slot_catalog_xmin;
2042 }
TransactionId slot_catalog_xmin
Definition: procarray.c:193
TransactionId shared_oldest_nonremovable_raw
Definition: procarray.c:226

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

Referenced by XLogWalRcvSendHSFeedback().

◆ GetRunningTransactionData()

RunningTransactions GetRunningTransactionData ( void  )

Definition at line 2669 of file procarray.c.

2670 {
2671  /* result workspace */
2672  static RunningTransactionsData CurrentRunningXactsData;
2673 
2674  ProcArrayStruct *arrayP = procArray;
2675  TransactionId *other_xids = ProcGlobal->xids;
2676  RunningTransactions CurrentRunningXacts = &CurrentRunningXactsData;
2677  TransactionId latestCompletedXid;
2678  TransactionId oldestRunningXid;
2679  TransactionId *xids;
2680  int index;
2681  int count;
2682  int subcount;
2683  bool suboverflowed;
2684 
2686 
2687  /*
2688  * Allocating space for maxProcs xids is usually overkill; numProcs would
2689  * be sufficient. But it seems better to do the malloc while not holding
2690  * the lock, so we can't look at numProcs. Likewise, we allocate much
2691  * more subxip storage than is probably needed.
2692  *
2693  * Should only be allocated in bgwriter, since only ever executed during
2694  * checkpoints.
2695  */
2696  if (CurrentRunningXacts->xids == NULL)
2697  {
2698  /*
2699  * First call
2700  */
2701  CurrentRunningXacts->xids = (TransactionId *)
2703  if (CurrentRunningXacts->xids == NULL)
2704  ereport(ERROR,
2705  (errcode(ERRCODE_OUT_OF_MEMORY),
2706  errmsg("out of memory")));
2707  }
2708 
2709  xids = CurrentRunningXacts->xids;
2710 
2711  count = subcount = 0;
2712  suboverflowed = false;
2713 
2714  /*
2715  * Ensure that no xids enter or leave the procarray while we obtain
2716  * snapshot.
2717  */
2718  LWLockAcquire(ProcArrayLock, LW_SHARED);
2719  LWLockAcquire(XidGenLock, LW_SHARED);
2720 
2721  latestCompletedXid =
2723  oldestRunningXid =
2725 
2726  /*
2727  * Spin over procArray collecting all xids
2728  */
2729  for (index = 0; index < arrayP->numProcs; index++)
2730  {
2731  TransactionId xid;
2732 
2733  /* Fetch xid just once - see GetNewTransactionId */
2734  xid = UINT32_ACCESS_ONCE(other_xids[index]);
2735 
2736  /*
2737  * We don't need to store transactions that don't have a TransactionId
2738  * yet because they will not show as running on a standby server.
2739  */
2740  if (!TransactionIdIsValid(xid))
2741  continue;
2742 
2743  /*
2744  * Be careful not to exclude any xids before calculating the values of
2745  * oldestRunningXid and suboverflowed, since these are used to clean
2746  * up transaction information held on standbys.
2747  */
2748  if (TransactionIdPrecedes(xid, oldestRunningXid))
2749  oldestRunningXid = xid;
2750 
2752  suboverflowed = true;
2753 
2754  /*
2755  * If we wished to exclude xids this would be the right place for it.
2756  * Procs with the PROC_IN_VACUUM flag set don't usually assign xids,
2757  * but they do during truncation at the end when they get the lock and
2758  * truncate, so it is not much of a problem to include them if they
2759  * are seen and it is cleaner to include them.
2760  */
2761 
2762  xids[count++] = xid;
2763  }
2764 
2765  /*
2766  * Spin over procArray collecting all subxids, but only if there hasn't
2767  * been a suboverflow.
2768  */
2769  if (!suboverflowed)
2770  {
2771  XidCacheStatus *other_subxidstates = ProcGlobal->subxidStates;
2772 
2773  for (index = 0; index < arrayP->numProcs; index++)
2774  {
2775  int pgprocno = arrayP->pgprocnos[index];
2776  PGPROC *proc = &allProcs[pgprocno];
2777  int nsubxids;
2778 
2779  /*
2780  * Save subtransaction XIDs. Other backends can't add or remove
2781  * entries while we're holding XidGenLock.
2782  */
2783  nsubxids = other_subxidstates[index].count;
2784  if (nsubxids > 0)
2785  {
2786  /* barrier not really required, as XidGenLock is held, but ... */
2787  pg_read_barrier(); /* pairs with GetNewTransactionId */
2788 
2789  memcpy(&xids[count], proc->subxids.xids,
2790  nsubxids * sizeof(TransactionId));
2791  count += nsubxids;
2792  subcount += nsubxids;
2793 
2794  /*
2795  * Top-level XID of a transaction is always less than any of
2796  * its subxids, so we don't need to check if any of the
2797  * subxids are smaller than oldestRunningXid
2798  */
2799  }
2800  }
2801  }
2802 
2803  /*
2804  * It's important *not* to include the limits set by slots here because
2805  * snapbuild.c uses oldestRunningXid to manage its xmin horizon. If those
2806  * were to be included here the initial value could never increase because
2807  * of a circular dependency where slots only increase their limits when
2808  * running xacts increases oldestRunningXid and running xacts only
2809  * increases if slots do.
2810  */
2811 
2812  CurrentRunningXacts->xcnt = count - subcount;
2813  CurrentRunningXacts->subxcnt = subcount;
2814  CurrentRunningXacts->subxid_overflow = suboverflowed;
2816  CurrentRunningXacts->oldestRunningXid = oldestRunningXid;
2817  CurrentRunningXacts->latestCompletedXid = latestCompletedXid;
2818 
2819  Assert(TransactionIdIsValid(CurrentRunningXacts->nextXid));
2820  Assert(TransactionIdIsValid(CurrentRunningXacts->oldestRunningXid));
2821  Assert(TransactionIdIsNormal(CurrentRunningXacts->latestCompletedXid));
2822 
2823  /* We don't release the locks here, the caller is responsible for that */
2824 
2825  return CurrentRunningXacts;
2826 }
#define pg_read_barrier()
Definition: atomics.h:153
struct XidCache subxids
Definition: proc.h:256
XidCacheStatus * subxidStates
Definition: proc.h:371
TransactionId oldestRunningXid
Definition: standby.h:84
TransactionId nextXid
Definition: standby.h:83
TransactionId latestCompletedXid
Definition: standby.h:85
TransactionId * xids
Definition: standby.h:87
FullTransactionId latestCompletedXid
Definition: transam.h:238
bool overflowed
Definition: proc.h:45
uint8 count
Definition: proc.h:43
TransactionId xids[PGPROC_MAX_CACHED_SUBXIDS]
Definition: proc.h:50

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

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

References SnapshotData::active_count, allProcs, Assert(), SnapshotData::copied, XidCacheStatus::count, SnapshotData::curcid, GlobalVisState::definitely_needed, ereport, errcode(), errmsg(), ERROR, FullTransactionIdAdvance(), FullTransactionIdNewer(), FullXidRelativeTo(), GetCurrentCommandId(), GetMaxSnapshotSubxidCount(), GetMaxSnapshotXidCount(), GetSnapshotDataReuse(), GlobalVisCatalogRels, GlobalVisDataRels, GlobalVisSharedRels, GlobalVisTempRels, InvalidTransactionId, InvalidXLogRecPtr, KnownAssignedXidsGetAndSetXmin(), ProcArrayStruct::lastOverflowedXid, VariableCacheData::latestCompletedXid, likely, SnapshotData::lsn, 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(), TransactionXmin, UINT32_ACCESS_ONCE, SnapshotData::whenTaken, 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 3007 of file procarray.c.

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

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

Referenced by CreateCheckPoint().

◆ HaveVirtualXIDsDelayingChkpt()

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

Definition at line 3053 of file procarray.c.

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

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

Referenced by CreateCheckPoint().

◆ IsBackendPid()

bool IsBackendPid ( int  pid)

Definition at line 3197 of file procarray.c.

3198 {
3199  return (BackendPidGetProc(pid) != NULL);
3200 }
PGPROC * BackendPidGetProc(int pid)
Definition: procarray.c:3102

References BackendPidGetProc().

Referenced by pg_stat_get_subscription().

◆ KnownAssignedTransactionIdsIdleMaintenance()

void KnownAssignedTransactionIdsIdleMaintenance ( void  )

Definition at line 4473 of file procarray.c.

4474 {
4476 }
@ KAX_STARTUP_PROCESS_IDLE
Definition: procarray.c:266
static void KnownAssignedXidsCompress(KAXCompressReason reason, bool haveLock)
Definition: procarray.c:4574

References KAX_STARTUP_PROCESS_IDLE, and KnownAssignedXidsCompress().

Referenced by WaitForWALToBecomeAvailable().

◆ MinimumActiveBackends()

bool MinimumActiveBackends ( int  min)

Definition at line 3452 of file procarray.c.

3453 {
3454  ProcArrayStruct *arrayP = procArray;
3455  int count = 0;
3456  int index;
3457 
3458  /* Quick short-circuit if no minimum is specified */
3459  if (min == 0)
3460  return true;
3461 
3462  /*
3463  * Note: for speed, we don't acquire ProcArrayLock. This is a little bit
3464  * bogus, but since we are only testing fields for zero or nonzero, it
3465  * should be OK. The result is only used for heuristic purposes anyway...
3466  */
3467  for (index = 0; index < arrayP->numProcs; index++)
3468  {
3469  int pgprocno = arrayP->pgprocnos[index];
3470  PGPROC *proc = &allProcs[pgprocno];
3471 
3472  /*
3473  * Since we're not holding a lock, need to be prepared to deal with
3474  * garbage, as someone could have incremented numProcs but not yet
3475  * filled the structure.
3476  *
3477  * If someone just decremented numProcs, 'proc' could also point to a
3478  * PGPROC entry that's no longer in the array. It still points to a
3479  * PGPROC struct, though, because freed PGPROC entries just go to the
3480  * free list and are recycled. Its contents are nonsense in that case,
3481  * but that's acceptable for this function.
3482  */
3483  if (pgprocno == -1)
3484  continue; /* do not count deleted entries */
3485  if (proc == MyProc)
3486  continue; /* do not count myself */
3487  if (proc->xid == InvalidTransactionId)
3488  continue; /* do not count if no XID assigned */
3489  if (proc->pid == 0)
3490  continue; /* do not count prepared xacts */
3491  if (proc->waitLock != NULL)
3492  continue; /* do not count if blocked on a lock */
3493  count++;
3494  if (count >= min)
3495  break;
3496  }
3497 
3498  return count >= min;
3499 }
LOCK * waitLock
Definition: proc.h:223

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

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

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

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

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

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

Referenced by xact_redo().

◆ ProcArrayClearTransaction()

void ProcArrayClearTransaction ( PGPROC proc)

Definition at line 906 of file procarray.c.

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

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

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

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

Referenced by AbortTransaction(), and CommitTransaction().

◆ ProcArrayGetReplicationSlotXmin()

void ProcArrayGetReplicationSlotXmin ( TransactionId xmin,
TransactionId catalog_xmin 
)

Definition at line 3871 of file procarray.c.

3873 {
3874  LWLockAcquire(ProcArrayLock, LW_SHARED);
3875 
3876  if (xmin != NULL)
3878 
3879  if (catalog_xmin != NULL)
3880  *catalog_xmin = procArray->replication_slot_catalog_xmin;
3881 
3882  LWLockRelease(ProcArrayLock);
3883 }

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

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

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

Referenced by StartupXLOG().

◆ ProcArrayInstallImportedXmin()

bool ProcArrayInstallImportedXmin ( TransactionId  xmin,
VirtualTransactionId sourcevxid 
)

Definition at line 2517 of file procarray.c.

2519 {
2520  bool result = false;
2521  ProcArrayStruct *arrayP = procArray;
2522  int index;
2523 
2525  if (!sourcevxid)
2526  return false;
2527 
2528  /* Get lock so source xact can't end while we're doing this */
2529  LWLockAcquire(ProcArrayLock, LW_SHARED);
2530 
2531  for (index = 0; index < arrayP->numProcs; index++)
2532  {
2533  int pgprocno = arrayP->pgprocnos[index];
2534  PGPROC *proc = &allProcs[pgprocno];
2535  int statusFlags = ProcGlobal->statusFlags[index];
2536  TransactionId xid;
2537 
2538  /* Ignore procs running LAZY VACUUM */
2539  if (statusFlags & PROC_IN_VACUUM)
2540  continue;
2541 
2542  /* We are only interested in the specific virtual transaction. */
2543  if (proc->backendId != sourcevxid->backendId)
2544  continue;
2545  if (proc->lxid != sourcevxid->localTransactionId)
2546  continue;
2547 
2548  /*
2549  * We check the transaction's database ID for paranoia's sake: if it's
2550  * in another DB then its xmin does not cover us. Caller should have
2551  * detected this already, so we just treat any funny cases as
2552  * "transaction not found".
2553  */
2554  if (proc->databaseId != MyDatabaseId)
2555  continue;
2556 
2557  /*
2558  * Likewise, let's just make real sure its xmin does cover us.
2559  */
2560  xid = UINT32_ACCESS_ONCE(proc->xmin);
2561  if (!TransactionIdIsNormal(xid) ||
2562  !TransactionIdPrecedesOrEquals(xid, xmin))
2563  continue;
2564 
2565  /*
2566  * We're good. Install the new xmin. As in GetSnapshotData, set
2567  * TransactionXmin too. (Note that because snapmgr.c called
2568  * GetSnapshotData first, we'll be overwriting a valid xmin here, so
2569  * we don't check that.)
2570  */
2571  MyProc->xmin = TransactionXmin = xmin;
2572 
2573  result = true;
2574  break;
2575  }
2576 
2577  LWLockRelease(ProcArrayLock);
2578 
2579  return result;
2580 }
BackendId backendId
Definition: proc.h:197

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

2597 {
2598  bool result = false;
2599  TransactionId xid;
2600 
2602  Assert(proc != NULL);
2603 
2604  /*
2605  * Get an exclusive lock so that we can copy statusFlags from source proc.
2606  */
2607  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
2608 
2609  /*
2610  * Be certain that the referenced PGPROC has an advertised xmin which is
2611  * no later than the one we're installing, so that the system-wide xmin
2612  * can't go backwards. Also, make sure it's running in the same database,
2613  * so that the per-database xmin cannot go backwards.
2614  */
2615  xid = UINT32_ACCESS_ONCE(proc->xmin);
2616  if (proc->databaseId == MyDatabaseId &&
2617  TransactionIdIsNormal(xid) &&
2618  TransactionIdPrecedesOrEquals(xid, xmin))
2619  {
2620  /*
2621  * Install xmin and propagate the statusFlags that affect how the
2622  * value is interpreted by vacuum.
2623  */
2624  MyProc->xmin = TransactionXmin = xmin;
2626  (proc->statusFlags & PROC_XMIN_FLAGS);
2628 
2629  result = true;
2630  }
2631 
2632  LWLockRelease(ProcArrayLock);
2633 
2634  return result;
2635 }
#define PROC_XMIN_FLAGS
Definition: proc.h:71

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

Referenced by SetTransactionSnapshot().

◆ ProcArrayRemove()

void ProcArrayRemove ( PGPROC proc,
TransactionId  latestXid 
)

Definition at line 565 of file procarray.c.

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

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

3848 {
3849  Assert(!already_locked || LWLockHeldByMe(ProcArrayLock));
3850 
3851  if (!already_locked)
3852  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3853 
3855  procArray->replication_slot_catalog_xmin = catalog_xmin;
3856 
3857  if (!already_locked)
3858  LWLockRelease(ProcArrayLock);
3859 
3860  elog(DEBUG1, "xmin required by slots: data %u, catalog %u",
3861  xmin, catalog_xmin);
3862 }

References Assert(), DEBUG1, elog(), 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 377 of file procarray.c.

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

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

Referenced by CalculateShmemSize().

◆ RecordKnownAssignedTransactionIds()

void RecordKnownAssignedTransactionIds ( TransactionId  xid)

Definition at line 4336 of file procarray.c.

4337 {
4341 
4342  elog(trace_recovery(DEBUG4), "record known xact %u latestObservedXid %u",
4343  xid, latestObservedXid);
4344 
4345  /*
4346  * When a newly observed xid arrives, it is frequently the case that it is
4347  * *not* the next xid in sequence. When this occurs, we must treat the
4348  * intervening xids as running also.
4349  */
4351  {
4352  TransactionId next_expected_xid;
4353 
4354  /*
4355  * Extend subtrans like we do in GetNewTransactionId() during normal
4356  * operation using individual extend steps. Note that we do not need
4357  * to extend clog since its extensions are WAL logged.
4358  *
4359  * This part has to be done regardless of standbyState since we
4360  * immediately start assigning subtransactions to their toplevel
4361  * transactions.
4362  */
4363  next_expected_xid = latestObservedXid;
4364  while (TransactionIdPrecedes(next_expected_xid, xid))
4365  {
4366  TransactionIdAdvance(next_expected_xid);
4367  ExtendSUBTRANS(next_expected_xid);
4368  }
4369  Assert(next_expected_xid == xid);
4370 
4371  /*
4372  * If the KnownAssignedXids machinery isn't up yet, there's nothing
4373  * more to do since we don't track assigned xids yet.
4374  */
4376  {
4377  latestObservedXid = xid;
4378  return;
4379  }
4380 
4381  /*
4382  * Add (latestObservedXid, xid] onto the KnownAssignedXids array.
4383  */
4384  next_expected_xid = latestObservedXid;
4385  TransactionIdAdvance(next_expected_xid);
4386  KnownAssignedXidsAdd(next_expected_xid, xid, false);
4387 
4388  /*
4389  * Now we can advance latestObservedXid
4390  */
4391  latestObservedXid = xid;
4392 
4393  /* ShmemVariableCache->nextXid must be beyond any observed xid */
4395  }
4396 }
#define DEBUG4
Definition: elog.h:27

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

3405 {
3406  ProcArrayStruct *arrayP = procArray;
3407  int index;
3408  pid_t pid = 0;
3409 
3410  LWLockAcquire(ProcArrayLock, LW_SHARED);
3411 
3412  for (index = 0; index < arrayP->numProcs; index++)
3413  {
3414  int pgprocno = arrayP->pgprocnos[index];
3415  PGPROC *proc = &allProcs[pgprocno];
3416  VirtualTransactionId procvxid;
3417 
3418  GET_VXID_FROM_PGPROC(procvxid, *proc);
3419 
3420  if (procvxid.backendId == vxid.backendId &&
3421  procvxid.localTransactionId == vxid.localTransactionId)
3422  {
3423  proc->recoveryConflictPending = conflictPending;
3424  pid = proc->pid;
3425  if (pid != 0)
3426  {
3427  /*
3428  * Kill the pid if it's still here. If not, that's what we
3429  * wanted so ignore any errors.
3430  */
3431  (void) SendProcSignal(pid, sigmode, vxid.backendId);
3432  }
3433  break;
3434  }
3435  }
3436 
3437  LWLockRelease(ProcArrayLock);
3438 
3439  return pid;
3440 }

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

3735 {
3736  ProcArrayStruct *arrayP = procArray;
3737  List *pids = NIL;
3738  int nprepared = 0;
3739  int i;
3740 
3741  LWLockAcquire(ProcArrayLock, LW_SHARED);
3742 
3743  for (i = 0; i < procArray->numProcs; i++)
3744  {
3745  int pgprocno = arrayP->pgprocnos[i];
3746  PGPROC *proc = &allProcs[pgprocno];
3747 
3748  if (proc->databaseId != databaseId)
3749  continue;
3750  if (proc == MyProc)
3751  continue;
3752 
3753  if (proc->pid != 0)
3754  pids = lappend_int(pids, proc->pid);
3755  else
3756  nprepared++;
3757  }
3758 
3759  LWLockRelease(ProcArrayLock);
3760 
3761  if (nprepared > 0)
3762  ereport(ERROR,
3763  (errcode(ERRCODE_OBJECT_IN_USE),
3764  errmsg("database \"%s\" is being used by prepared transactions",
3765  get_database_name(databaseId)),
3766  errdetail_plural("There is %d prepared transaction using the database.",
3767  "There are %d prepared transactions using the database.",
3768  nprepared,
3769  nprepared)));
3770 
3771  if (pids)
3772  {
3773  ListCell *lc;
3774 
3775  /*
3776  * Check whether we have the necessary rights to terminate other
3777  * sessions. We don't terminate any session until we ensure that we
3778  * have rights on all the sessions to be terminated. These checks are
3779  * the same as we do in pg_terminate_backend.
3780  *
3781  * In this case we don't raise some warnings - like "PID %d is not a
3782  * PostgreSQL server process", because for us already finished session
3783  * is not a problem.
3784  */
3785  foreach(lc, pids)
3786  {
3787  int pid = lfirst_int(lc);
3788  PGPROC *proc = BackendPidGetProc(pid);
3789 
3790  if (proc != NULL)
3791  {
3792  /* Only allow superusers to signal superuser-owned backends. */
3793  if (superuser_arg(proc->roleId) && !superuser())
3794  ereport(ERROR,
3795  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3796  errmsg("permission denied to terminate process"),
3797  errdetail("Only roles with the %s attribute may terminate processes of roles with the %s attribute.",
3798  "SUPERUSER", "SUPERUSER")));
3799 
3800  /* Users can signal backends they have role membership in. */
3801  if (!has_privs_of_role(GetUserId(), proc->roleId) &&
3802  !has_privs_of_role(GetUserId(), ROLE_PG_SIGNAL_BACKEND))
3803  ereport(ERROR,
3804  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
3805  errmsg("permission denied to terminate process"),
3806  errdetail("Only roles with privileges of the role whose process is being terminated or with privileges of the \"%s\" role may terminate this process.",
3807  "pg_signal_backend")));
3808  }
3809  }
3810 
3811  /*
3812  * There's a race condition here: once we release the ProcArrayLock,
3813  * it's possible for the session to exit before we issue kill. That
3814  * race condition possibility seems too unlikely to worry about. See
3815  * pg_signal_backend.
3816  */
3817  foreach(lc, pids)
3818  {
3819  int pid = lfirst_int(lc);
3820  PGPROC *proc = BackendPidGetProc(pid);
3821 
3822  if (proc != NULL)
3823  {
3824  /*
3825  * If we have setsid(), signal the backend's whole process
3826  * group
3827  */
3828 #ifdef HAVE_SETSID
3829  (void) kill(-pid, SIGTERM);
3830 #else
3831  (void) kill(pid, SIGTERM);
3832 #endif
3833  }
3834  }
3835  }
3836 }
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:5060
char * get_database_name(Oid dbid)
Definition: dbcommands.c:3089
int errdetail(const char *fmt,...)
Definition: elog.c:1202
int errdetail_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition: elog.c:1294
List * lappend_int(List *list, int datum)
Definition: list.c:356
Oid GetUserId(void)
Definition: miscinit.c:508
#define NIL
Definition: pg_list.h:68
#define lfirst_int(lc)
Definition: pg_list.h:173
Definition: pg_list.h:54
bool superuser_arg(Oid roleid)
Definition: superuser.c:56
bool superuser(void)
Definition: superuser.c:46

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

Referenced by dropdb().

◆ TransactionIdIsActive()

bool TransactionIdIsActive ( TransactionId  xid)

Definition at line 1615 of file procarray.c.

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

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

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

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

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

◆ XidCacheRemoveRunningXids()

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

Definition at line 3894 of file procarray.c.

3897 {
3898  int i,
3899  j;
3900  XidCacheStatus *mysubxidstat;
3901 
3903 
3904  /*
3905  * We must hold ProcArrayLock exclusively in order to remove transactions
3906  * from the PGPROC array. (See src/backend/access/transam/README.) It's
3907  * possible this could be relaxed since we know this routine is only used
3908  * to abort subtransactions, but pending closer analysis we'd best be
3909  * conservative.
3910  *
3911  * Note that we do not have to be careful about memory ordering of our own
3912  * reads wrt. GetNewTransactionId() here - only this process can modify
3913  * relevant fields of MyProc/ProcGlobal->xids[]. But we do have to be
3914  * careful about our own writes being well ordered.
3915  */
3916  LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
3917 
3918  mysubxidstat = &ProcGlobal->subxidStates[MyProc->pgxactoff];
3919 
3920  /*
3921  * Under normal circumstances xid and xids[] will be in increasing order,
3922  * as will be the entries in subxids. Scan backwards to avoid O(N^2)
3923  * behavior when removing a lot of xids.
3924  */
3925  for (i = nxids - 1; i >= 0; i--)
3926  {
3927  TransactionId anxid = xids[i];
3928 
3929  for (j = MyProc->subxidStatus.count - 1; j >= 0; j--)
3930  {
3931  if (TransactionIdEquals(MyProc->subxids.xids[j], anxid))
3932  {
3934  pg_write_barrier();
3935  mysubxidstat->count--;
3937  break;
3938  }
3939  }
3940 
3941  /*
3942  * Ordinarily we should have found it, unless the cache has
3943  * overflowed. However it's also possible for this routine to be
3944  * invoked multiple times for the same subtransaction, in case of an
3945  * error during AbortSubTransaction. So instead of Assert, emit a
3946  * debug warning.
3947  */
3948  if (j < 0 && !MyProc->subxidStatus.overflowed)
3949  elog(WARNING, "did not find subXID %u in MyProc", anxid);
3950  }
3951 
3952  for (j = MyProc->subxidStatus.count - 1; j >= 0; j--)
3953  {
3954  if (TransactionIdEquals(MyProc->subxids.xids[j], xid))
3955  {
3957  pg_write_barrier();
3958  mysubxidstat->count--;
3960  break;
3961  }
3962  }
3963  /* Ordinarily we should have found it, unless the cache has overflowed */
3964  if (j < 0 && !MyProc->subxidStatus.overflowed)
3965  elog(WARNING, "did not find subXID %u in MyProc", xid);
3966 
3967  /* Also advance global latestCompletedXid while holding the lock */
3968  MaintainLatestCompletedXid(latestXid);
3969 
3970  /* ... and xactCompletionCount */
3972 
3973  LWLockRelease(ProcArrayLock);
3974 }
#define pg_write_barrier()
Definition: atomics.h:154
#define WARNING
Definition: elog.h:36

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

Referenced by RecordTransactionAbort().