PostgreSQL 14在MVCC上面有所增强,以保证在大批量客户端连接场景下性能不会出现显著下降(详细可参见参考资料中的链接)。本节介绍了提交记录“snapshot scalability: Move PGXACT->vacuumFlags to ProcGlobal->vacuumFlags.”中的修改以及涉及的相关数据结构。
一、数据结构
PROC_HDR
/*
* There is one ProcGlobal struct for the whole database cluster.
* 全局的ProcGlobal(PROC_HDR)结构体
*
* Adding/Removing an entry into the procarray requires holding *both*
* ProcArrayLock and XidGenLock in exclusive mode (in that order). Both are
* needed because the dense arrays (see below) are accessed from
* GetNewTransactionId() and GetSnapshotData(), and we don't want to add
* further contention by both using the same lock. Adding/Removing a procarray
* entry is much less frequent.
*
*
* Some fields in PGPROC are mirrored into more densely packed arrays (e.g.
* xids), with one entry for each backend. These arrays only contain entries
* for PGPROCs that have been added to the shared array with ProcArrayAdd()
* (in contrast to PGPROC array which has unused PGPROCs interspersed).
*
* The dense arrays are indexed by PGPROC->pgxactoff. Any concurrent
* ProcArrayAdd() / ProcArrayRemove() can lead to pgxactoff of a procarray
* member to change. Therefore it is only safe to use PGPROC->pgxactoff to
* access the dense array while holding either ProcArrayLock or XidGenLock.
*
* As long as a PGPROC is in the procarray, the mirrored values need to be
* maintained in both places in a coherent manner.
*
* The denser separate arrays are beneficial for three main reasons: First, to
* allow for as tight loops accessing the data as possible. Second, to prevent
* updates of frequently changing data (e.g. xmin) from invalidating
* cachelines also containing less frequently changing data (e.g. xid,
* statusFlags). Third to condense frequently accessed data into as few
* cachelines as possible.
*
* There are two main reasons to have the data mirrored between these dense
* arrays and PGPROC. First, as explained above, a PGPROC's array entries can
* only be accessed with either ProcArrayLock or XidGenLock held, whereas the
* PGPROC entries do not require that (obviously there may still be locking
* requirements around the individual field, separate from the concerns
* here). That is particularly important for a backend to efficiently checks
* it own values, which it often can safely do without locking. Second, the
* PGPROC fields allow to avoid unnecessary accesses and modification to the
* dense arrays. A backend's own PGPROC is more likely to be in a local cache,
* whereas the cachelines for the dense array will be modified by other
* backends (often removing it from the cache for other cores/sockets). At
* commit/abort time a check of the PGPROC value can avoid accessing/dirtying
* the corresponding array value.
*
* Basically it makes sense to access the PGPROC variable when checking a
* single backend's data, especially when already looking at the PGPROC for
* other reasons already. It makes sense to look at the "dense" arrays if we
* need to look at many / most entries, because we then benefit from the
* reduced indirection and better cross-process cache-ability.
*
* When entering a PGPROC for 2PC transactions with ProcArrayAdd(), the data
* in the dense arrays is initialized from the PGPROC while it already holds
* ProcArrayLock.
*/
typedef struct PROC_HDR
{
/* Array of PGPROC structures (not including dummies for prepared txns) */
PGPROC *allProcs;
/* Array mirroring PGPROC.xid for each PGPROC currently in the procarray */
TransactionId *xids;
/*
* Array mirroring PGPROC.subxidStatus for each PGPROC currently in the
* procarray.
*/
XidCacheStatus *subxidStates;
/*
* Array mirroring PGPROC.statusFlags for each PGPROC currently in the
* procarray.
*/
uint8 *statusFlags;
/* Length of allProcs array */
uint32 allProcCount;
/* Head of list of free PGPROC structures */
PGPROC *freeProcs;
/* Head of list of autovacuum's free PGPROC structures */
PGPROC *autovacFreeProcs;
/* Head of list of bgworker free PGPROC structures */
PGPROC *bgworkerFreeProcs;
/* Head of list of walsender free PGPROC structures */
PGPROC *walsenderFreeProcs;
/* First pgproc waiting for group XID clear */
pg_atomic_uint32 procArrayGroupFirst;
/* First pgproc waiting for group transaction status update */
pg_atomic_uint32 clogGroupFirst;
/* WALWriter process's latch */
Latch *walwriterLatch;
/* Checkpointer process's latch */
Latch *checkpointerLatch;
/* Current shared estimate of appropriate spins_per_delay value */
int spins_per_delay;
/* The proc of the Startup process, since not in ProcArray */
PGPROC *startupProc;
int startupProcPid;
/* Buffer id of the buffer that Startup process waits for pin on, or -1 */
int startupBufferPinWaitBufId;
} PROC_HDR;
extern PGDLLIMPORT PROC_HDR *ProcGlobal;
二、源码解读
提交说明
Similar to the previous commit this increases the chance that data
frequently needed by GetSnapshotData() stays in l2 cache. As we now
take care to not unnecessarily write to ProcGlobal->vacuumFlags, there
should be very few modifications to the ProcGlobal->vacuumFlags array.
意思是该commit跟上一个commit类似,让GetSnapshotData函数需要的数据尽可能留在CPU L2缓存中.
非必要情况下不会修改ProcGlobal->vacuumFlags.
这个commit的修改都比较好懂,具体详见代码.
/*
proc是PGPROC结构体,把pgxact中的标记vacuumFlags移至proc中.
其中:ProcGlobal是PROC_HDR结构体
*/
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index a0398bf3a3e82263c7201cdf03a5daf43d8e3963..744b8a7f39352bce409a8f08d71748e84e4b15e4 100644 (file)
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -466,7 +466,7 @@ MarkAsPreparingGuts(GlobalTransaction gxact, TransactionId xid, const char *gid,
proc->xid = xid;
Assert(proc->xmin == InvalidTransactionId);
proc->delayChkpt = false;
- pgxact->vacuumFlags = 0;
+ proc->vacuumFlags = 0;
proc->pid = 0;
proc->backendId = InvalidBackendId;
proc->databaseId = databaseid;
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 648e12c78d84e48c8ed26a576403ed76cc74b311..aba13c31d1bc2e957cb7b61bd6983b4f91389740 100644 (file)
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -1728,9 +1728,10 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
* might appear to go backwards, which is probably Not Good.
*/
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
- MyPgXact->vacuumFlags |= PROC_IN_VACUUM;
+ MyProc->vacuumFlags |= PROC_IN_VACUUM;
if (params->is_wraparound)
- MyPgXact->vacuumFlags |= PROC_VACUUM_FOR_WRAPAROUND;
+ MyProc->vacuumFlags |= PROC_VACUUM_FOR_WRAPAROUND;
+ ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags;
LWLockRelease(ProcArrayLock);
}
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index ac97e28be19c7ce904db3ce43ce85e11c959ff3f..c6ec657a9367c0e99b9be9bd729df2c9afbebd9f 100644 (file)
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -2493,7 +2493,7 @@ do_autovacuum(void)
tab->at_datname, tab->at_nspname, tab->at_relname);
EmitErrorReport();
- /* this resets the PGXACT flags too */
+ /* this resets ProcGlobal->vacuumFlags[i] too */
AbortOutOfAnyTransaction();
FlushErrorState();
MemoryContextResetAndDeleteChildren(PortalContext);
@@ -2509,7 +2509,7 @@ do_autovacuum(void)
did_vacuum = true;
- /* the PGXACT flags are reset at the next end of transaction */
+ /* ProcGlobal->vacuumFlags[i] are reset at the next end of xact */
/* be tidy */
deleted:
@@ -2686,7 +2686,7 @@ perform_work_item(AutoVacuumWorkItem *workitem)
cur_datname, cur_nspname, cur_relname);
EmitErrorReport();
- /* this resets the PGXACT flags too */
+ /* this resets ProcGlobal->vacuumFlags[i] too */
AbortOutOfAnyTransaction();
FlushErrorState();
MemoryContextResetAndDeleteChildren(PortalContext);
diff --git a/src/backend/replication/logical/logical.c b/src/backend/replication/logical/logical.c
index 57c5b513ccf848a7a8ccb8ae4cb640edbc213035..0f6af952f93940032714fb957aaadccef2e91cb4 100644 (file)
--- a/src/backend/replication/logical/logical.c
+++ b/src/backend/replication/logical/logical.c
@@ -181,7 +181,8 @@ StartupDecodingContext(List *output_plugin_options,
if (!IsTransactionOrTransactionBlock())
{
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
- MyPgXact->vacuumFlags |= PROC_IN_LOGICAL_DECODING;
+ MyProc->vacuumFlags |= PROC_IN_LOGICAL_DECODING;
+ ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags;
LWLockRelease(ProcArrayLock);
}
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 3dc01b6df22a966ccbab2ef9a5d144d48c86d7d7..42c78eabd4eb9ef805991d56a18ea7a4a63742cc 100644 (file)
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -520,7 +520,8 @@ ReplicationSlotRelease(void)
/* might not have been set when we've been a plain slot */
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
- MyPgXact->vacuumFlags &= ~PROC_IN_LOGICAL_DECODING;
+ MyProc->vacuumFlags &= ~PROC_IN_LOGICAL_DECODING;
+ ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags;
LWLockRelease(ProcArrayLock);
}
diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c
index 0bf20a49375d0434fdb883b1fc69c836e70e20ca..224da4f9510b8985317276d0fc611a96872d9c39 100644 (file)
--- a/src/backend/storage/ipc/procarray.c
+++ b/src/backend/storage/ipc/procarray.c
@@ -476,9 +476,12 @@ ProcArrayAdd(PGPROC *proc)
(arrayP->numProcs - index) * sizeof(*arrayP->pgprocnos));
memmove(&ProcGlobal->xids[index + 1], &ProcGlobal->xids[index],
(arrayP->numProcs - index) * sizeof(*ProcGlobal->xids));
+ memmove(&ProcGlobal->vacuumFlags[index + 1], &ProcGlobal->vacuumFlags[index],
+ (arrayP->numProcs - index) * sizeof(*ProcGlobal->vacuumFlags));
arrayP->pgprocnos[index] = proc->pgprocno;
ProcGlobal->xids[index] = proc->xid;
+ ProcGlobal->vacuumFlags[index] = proc->vacuumFlags;
arrayP->numProcs++;
@@ -539,6 +542,7 @@ ProcArrayRemove(PGPROC *proc, TransactionId latestXid)
}
Assert(TransactionIdIsValid(ProcGlobal->xids[proc->pgxactoff] == 0));
+ ProcGlobal->vacuumFlags[proc->pgxactoff] = 0;
for (index = 0; index < arrayP->numProcs; index++)
{
@@ -549,6 +553,8 @@ ProcArrayRemove(PGPROC *proc, TransactionId latestXid)
(arrayP->numProcs - index - 1) * sizeof(*arrayP->pgprocnos));
memmove(&ProcGlobal->xids[index], &ProcGlobal->xids[index + 1],
(arrayP->numProcs - index - 1) * sizeof(*ProcGlobal->xids));
+ memmove(&ProcGlobal->vacuumFlags[index], &ProcGlobal->vacuumFlags[index + 1],
+ (arrayP->numProcs - index - 1) * sizeof(*ProcGlobal->vacuumFlags));
arrayP->pgprocnos[arrayP->numProcs - 1] = -1; /* for debugging */
arrayP->numProcs--;
@@ -626,14 +632,24 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
Assert(!TransactionIdIsValid(proc->xid));
proc->lxid = InvalidLocalTransactionId;
- /* must be cleared with xid/xmin: */
- pgxact->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
proc->xmin = InvalidTransactionId;
proc->delayChkpt = false; /* be sure this is cleared in abort */
proc->recoveryConflictPending = false;
Assert(pgxact->nxids == 0);
Assert(pgxact->overflowed == false);
/*
没有必要,不要把CPU cache弄脏!
需判断vacuumFlags标志
*/
+
+ /* must be cleared with xid/xmin: */
+ /* avoid unnecessarily dirtying shared cachelines */
+ if (proc->vacuumFlags & PROC_VACUUM_STATE_MASK)
+ {
+ Assert(!LWLockHeldByMe(ProcArrayLock));
+ LWLockAcquire(ProcArrayLock, LW_SHARED);
+ Assert(proc->vacuumFlags == ProcGlobal->vacuumFlags[proc->pgxactoff]);
+ proc->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
+ ProcGlobal->vacuumFlags[proc->pgxactoff] = proc->vacuumFlags;
+ LWLockRelease(ProcArrayLock);
+ }
}
}
@@ -654,12 +670,18 @@ ProcArrayEndTransactionInternal(PGPROC *proc, PGXACT *pgxact,
ProcGlobal->xids[pgxactoff] = InvalidTransactionId;
proc->xid = InvalidTransactionId;
proc->lxid = InvalidLocalTransactionId;
- /* must be cleared with xid/xmin: */
- pgxact->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
proc->xmin = InvalidTransactionId;
proc->delayChkpt = false; /* be sure this is cleared in abort */
proc->recoveryConflictPending = false;
+ /* must be cleared with xid/xmin: */
+ /* avoid unnecessarily dirtying shared cachelines */
+ if (proc->vacuumFlags & PROC_VACUUM_STATE_MASK)
+ {
+ proc->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
+ ProcGlobal->vacuumFlags[proc->pgxactoff] = proc->vacuumFlags;
+ }
+
/* Clear the subtransaction-XID cache too while holding the lock */
pgxact->nxids = 0;
pgxact->overflowed = false;
@@ -819,9 +841,8 @@ ProcArrayClearTransaction(PGPROC *proc)
proc->xmin = InvalidTransactionId;
proc->recoveryConflictPending = false;
- /* redundant, but just in case */
- pgxact->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
- proc->delayChkpt = false;
+ Assert(!(proc->vacuumFlags & PROC_VACUUM_STATE_MASK));
+ Assert(!proc->delayChkpt);
/* Clear the subtransaction-XID cache too */
pgxact->nxids = 0;
@@ -1623,7 +1644,7 @@ ComputeXidHorizons(ComputeXidHorizonsResult *h)
{
int pgprocno = arrayP->pgprocnos[index];
PGPROC *proc = &allProcs[pgprocno];
- PGXACT *pgxact = &allPgXact[pgprocno];
+ int8 vacuumFlags = ProcGlobal->vacuumFlags[index];
TransactionId xid;
TransactionId xmin;
@@ -1640,8 +1661,8 @@ ComputeXidHorizons(ComputeXidHorizonsResult *h)
*/
xmin = TransactionIdOlder(xmin, xid);
- /* if neither is set, this proc doesn't influence the horizon */
- if (!TransactionIdIsValid(xmin))
+ /* if neither is set, this proc doesn't influence the horizon */
+ if (!TransactionIdIsValid(xmin))
continue;
/*
@@ -1658,7 +1679,7 @@ ComputeXidHorizons(ComputeXidHorizonsResult *h)
* removed, as long as pg_subtrans is not truncated) or doing logical
* decoding (which manages xmin separately, check below).
*/
- if (pgxact->vacuumFlags & (PROC_IN_VACUUM | PROC_IN_LOGICAL_DECODING))
+ if (vacuumFlags & (PROC_IN_VACUUM | PROC_IN_LOGICAL_DECODING))
continue;
/* shared tables need to take backends in all database into account */
@@ -1998,6 +2019,7 @@ GetSnapshotData(Snapshot snapshot)
size_t numProcs = arrayP->numProcs;
TransactionId *xip = snapshot->xip;
int *pgprocnos = arrayP->pgprocnos;
+ uint8 *allVacuumFlags = ProcGlobal->vacuumFlags;
/*
* First collect set of pgxactoff/xids that need to be included in the
@@ -2007,8 +2029,6 @@ GetSnapshotData(Snapshot snapshot)
{
/* Fetch xid just once - see GetNewTransactionId */
TransactionId xid = UINT32_ACCESS_ONCE(other_xids[pgxactoff]);
- int pgprocno;
- PGXACT *pgxact;
uint8 vacuumFlags;
Assert(allProcs[arrayP->pgprocnos[pgxactoff]].pgxactoff == pgxactoff);
@@ -2044,14 +2064,11 @@ GetSnapshotData(Snapshot snapshot)
if (!NormalTransactionIdPrecedes(xid, xmax))
continue;
- pgprocno = pgprocnos[pgxactoff];
- pgxact = &allPgXact[pgprocno];
- vacuumFlags = pgxact->vacuumFlags;
-
/*
* Skip over backends doing logical decoding which manages xmin
* separately (check below) and ones running LAZY VACUUM.
*/
+ vacuumFlags = allVacuumFlags[pgxactoff];
if (vacuumFlags & (PROC_IN_LOGICAL_DECODING | PROC_IN_VACUUM))
continue;
@@ -2078,6 +2095,9 @@ GetSnapshotData(Snapshot snapshot)
*/
if (!suboverflowed)
{
+ int pgprocno = pgprocnos[pgxactoff];
+ PGXACT *pgxact = &allPgXact[pgprocno];
+
if (pgxact->overflowed)
suboverflowed = true;
else
@@ -2296,11 +2316,11 @@ ProcArrayInstallImportedXmin(TransactionId xmin,
{
int pgprocno = arrayP->pgprocnos[index];
PGPROC *proc = &allProcs[pgprocno];
- PGXACT *pgxact = &allPgXact[pgprocno];
+ int vacuumFlags = ProcGlobal->vacuumFlags[index];
TransactionId xid;
/* Ignore procs running LAZY VACUUM */
- if (pgxact->vacuumFlags & PROC_IN_VACUUM)
+ if (vacuumFlags & PROC_IN_VACUUM)
continue;
/* We are only interested in the specific virtual transaction. */
@@ -2990,12 +3010,12 @@ GetCurrentVirtualXIDs(TransactionId limitXmin, bool excludeXmin0,
{
int pgprocno = arrayP->pgprocnos[index];
PGPROC *proc = &allProcs[pgprocno];
- PGXACT *pgxact = &allPgXact[pgprocno];
+ uint8 vacuumFlags = ProcGlobal->vacuumFlags[index];
if (proc == MyProc)
continue;
- if (excludeVacuum & pgxact->vacuumFlags)
+ if (excludeVacuum & vacuumFlags)
continue;
if (allDbs || proc->databaseId == MyDatabaseId)
@@ -3410,7 +3430,7 @@ CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared)
{
int pgprocno = arrayP->pgprocnos[index];
PGPROC *proc = &allProcs[pgprocno];
- PGXACT *pgxact = &allPgXact[pgprocno];
+ uint8 vacuumFlags = ProcGlobal->vacuumFlags[index];
if (proc->databaseId != databaseId)
continue;
@@ -3424,7 +3444,7 @@ CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared)
else
{
(*nbackends)++;
- if ((pgxact->vacuumFlags & PROC_IS_AUTOVACUUM) &&
+ if ((vacuumFlags & PROC_IS_AUTOVACUUM) &&
nautovacs < MAXAUTOVACPIDS)
autovac_pids[nautovacs++] = proc->pid;
}
diff --git a/src/backend/storage/lmgr/deadlock.c b/src/backend/storage/lmgr/deadlock.c
index beedc7947db945915e712f39f33deabce35d5303..e1246b8a4da17a29ba86394618190812b9029b2f 100644 (file)
--- a/src/backend/storage/lmgr/deadlock.c
+++ b/src/backend/storage/lmgr/deadlock.c
@@ -544,7 +544,6 @@ FindLockCycleRecurseMember(PGPROC *checkProc,
{
PGPROC *proc;
LOCK *lock = checkProc->waitLock;
- PGXACT *pgxact;
PROCLOCK *proclock;
SHM_QUEUE *procLocks;
LockMethod lockMethodTable;
@@ -582,7 +581,6 @@ FindLockCycleRecurseMember(PGPROC *checkProc,
PGPROC *leader;
proc = proclock->tag.myProc;
- pgxact = &ProcGlobal->allPgXact[proc->pgprocno];
leader = proc->lockGroupLeader == NULL ? proc : proc->lockGroupLeader;
/* A proc never blocks itself or any other lock group member */
@@ -630,7 +628,7 @@ FindLockCycleRecurseMember(PGPROC *checkProc,
* ProcArrayLock.
*/
if (checkProc == MyProc &&
- pgxact->vacuumFlags & PROC_IS_AUTOVACUUM)
+ proc->vacuumFlags & PROC_IS_AUTOVACUUM)
blocking_autovacuum_proc = proc;
/* We're done looking at this proclock */
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 7fad49544ce09c7386911ed022255d64201aa69a..f6113b2d24320573b19240a1fc7af9dee936078c 100644 (file)
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -114,6 +114,7 @@ ProcGlobalShmemSize(void)
size = add_size(size, mul_size(NUM_AUXILIARY_PROCS, sizeof(PGXACT)));
size = add_size(size, mul_size(max_prepared_xacts, sizeof(PGXACT)));
size = add_size(size, mul_size(TotalProcs, sizeof(*ProcGlobal->xids)));
+ size = add_size(size, mul_size(TotalProcs, sizeof(*ProcGlobal->vacuumFlags)));
return size;
}
@@ -223,6 +224,8 @@ InitProcGlobal(void)
ProcGlobal->xids =
(TransactionId *) ShmemAlloc(TotalProcs * sizeof(*ProcGlobal->xids));
MemSet(ProcGlobal->xids, 0, TotalProcs * sizeof(*ProcGlobal->xids));
+ ProcGlobal->vacuumFlags = (uint8 *) ShmemAlloc(TotalProcs * sizeof(*ProcGlobal->vacuumFlags));
+ MemSet(ProcGlobal->vacuumFlags, 0, TotalProcs * sizeof(*ProcGlobal->vacuumFlags));
for (i = 0; i < TotalProcs; i++)
{
@@ -405,10 +408,10 @@ InitProcess(void)
MyProc->tempNamespaceId = InvalidOid;
MyProc->isBackgroundWorker = IsBackgroundWorker;
MyProc->delayChkpt = false;
- MyPgXact->vacuumFlags = 0;
+ MyProc->vacuumFlags = 0;
/* NB -- autovac launcher intentionally does not set IS_AUTOVACUUM */
if (IsAutoVacuumWorkerProcess())
- MyPgXact->vacuumFlags |= PROC_IS_AUTOVACUUM;
+ MyProc->vacuumFlags |= PROC_IS_AUTOVACUUM;
MyProc->lwWaiting = false;
MyProc->lwWaitMode = 0;
MyProc->waitLock = NULL;
@@ -587,7 +590,7 @@ InitAuxiliaryProcess(void)
MyProc->tempNamespaceId = InvalidOid;
MyProc->isBackgroundWorker = IsBackgroundWorker;
MyProc->delayChkpt = false;
- MyPgXact->vacuumFlags = 0;
+ MyProc->vacuumFlags = 0;
MyProc->lwWaiting = false;
MyProc->lwWaitMode = 0;
MyProc->waitLock = NULL;
@@ -1323,7 +1326,7 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
if (deadlock_state == DS_BLOCKED_BY_AUTOVACUUM && allow_autovacuum_cancel)
{
PGPROC *autovac = GetBlockingAutoVacuumPgproc();
- PGXACT *autovac_pgxact = &ProcGlobal->allPgXact[autovac->pgprocno];
+ uint8 vacuumFlags;
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
@@ -1331,8 +1334,9 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
* Only do it if the worker is not working to protect against Xid
* wraparound.
*/
- if ((autovac_pgxact->vacuumFlags & PROC_IS_AUTOVACUUM) &&
- !(autovac_pgxact->vacuumFlags & PROC_VACUUM_FOR_WRAPAROUND))
+ vacuumFlags = ProcGlobal->vacuumFlags[proc->pgxactoff];
+ if ((vacuumFlags & PROC_IS_AUTOVACUUM) &&
+ !(vacuumFlags & PROC_VACUUM_FOR_WRAPAROUND))
{
int pid = autovac->pid;
StringInfoData locktagbuf;
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index e29ed85e53dbba3b05dd9949eef3af856aabc2de..9f3a8b518eb2f7ab8cc8546ce6536d1dd687022b 100644 (file)
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -41,7 +41,7 @@ struct XidCache
};
/*
- * Flags for PGXACT->vacuumFlags
+ * Flags for ProcGlobal->vacuumFlags[]
*/
#define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */
#define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */
@@ -167,6 +167,9 @@ struct PGPROC
bool delayChkpt; /* true if this proc delays checkpoint start */
+ uint8 vacuumFlags; /* this backend's vacuum flags, see PROC_*
+ * above. mirrored in
+ * ProcGlobal->vacuumFlags[pgxactoff] */
/*
* Info to allow us to wait for synchronous replication, if needed.
* waitLSN is InvalidXLogRecPtr if not waiting; set only by user backend.
@@ -244,7 +247,6 @@ extern PGDLLIMPORT struct PGXACT *MyPgXact;
*/
typedef struct PGXACT
{
- uint8 vacuumFlags; /* vacuum-related flags, see above */
bool overflowed;
uint8 nxids;
@@ -314,6 +316,12 @@ typedef struct PROC_HDR
/* Array mirroring PGPROC.xid for each PGPROC currently in the procarray */
TransactionId *xids;
+ /*
+ * Array mirroring PGPROC.vacuumFlags for each PGPROC currently in the
+ * procarray.
+ */
+ uint8 *vacuumFlags;
+
/* Length of allProcs array */
uint32 allProcCount;
/* Head of list of free PGPROC structures */
三、跟踪分析
N/A
四、参考资料
1.
Improving connection scalability: GetSnapshotData()
2.
snapshot scalability: Don’t compute global horizons while building snapshots.