(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++;
}
Assert(TransactionIdIsValid(ProcGlobal->xids[proc->pgxactoff] == 0));
+ ProcGlobal->vacuumFlags[proc->pgxactoff] = 0;
for (index = 0; index < arrayP->numProcs; index++)
{
(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--;
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);
+
+ /* 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);
+ }
}
}
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;
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;
{
int pgprocno = arrayP->pgprocnos[index];
PGPROC *proc = &allProcs[pgprocno];
- PGXACT *pgxact = &allPgXact[pgprocno];
+ int8 vacuumFlags = ProcGlobal->vacuumFlags[index];
TransactionId xid;
TransactionId xmin;
*/
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;
/*
* 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 */
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
{
/* 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);
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;
*/
if (!suboverflowed)
{
+ int pgprocno = pgprocnos[pgxactoff];
+ PGXACT *pgxact = &allPgXact[pgprocno];
+
if (pgxact->overflowed)
suboverflowed = true;
else
{
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. */
{
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)
{
int pgprocno = arrayP->pgprocnos[index];
PGPROC *proc = &allProcs[pgprocno];
- PGXACT *pgxact = &allPgXact[pgprocno];
+ uint8 vacuumFlags = ProcGlobal->vacuumFlags[index];
if (proc->databaseId != databaseId)
continue;
else
{
(*nbackends)++;
- if ((pgxact->vacuumFlags & PROC_IS_AUTOVACUUM) &&
+ if ((vacuumFlags & PROC_IS_AUTOVACUUM) &&
nautovacs < MAXAUTOVACPIDS)
autovac_pids[nautovacs++] = proc->pid;
}
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;
}
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++)
{
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;
MyProc->tempNamespaceId = InvalidOid;
MyProc->isBackgroundWorker = IsBackgroundWorker;
MyProc->delayChkpt = false;
- MyPgXact->vacuumFlags = 0;
+ MyProc->vacuumFlags = 0;
MyProc->lwWaiting = false;
MyProc->lwWaitMode = 0;
MyProc->waitLock = NULL;
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);
* 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;