Skip to content

Commit 5788e25

Browse files
committed
snapshot scalability: Move PGXACT->vacuumFlags to ProcGlobal->vacuumFlags.
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. Author: Andres Freund <[email protected]> Reviewed-By: Robert Haas <[email protected]> Reviewed-By: Thomas Munro <[email protected]> Reviewed-By: David Rowley <[email protected]> Discussion: https://postgr.es/m/[email protected]
1 parent 941697c commit 5788e25

File tree

9 files changed

+75
-42
lines changed

9 files changed

+75
-42
lines changed

src/backend/access/transam/twophase.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ MarkAsPreparingGuts(GlobalTransaction gxact, TransactionId xid, const char *gid,
466466
proc->xid = xid;
467467
Assert(proc->xmin == InvalidTransactionId);
468468
proc->delayChkpt = false;
469-
pgxact->vacuumFlags = 0;
469+
proc->vacuumFlags = 0;
470470
proc->pid = 0;
471471
proc->backendId = InvalidBackendId;
472472
proc->databaseId = databaseid;

src/backend/commands/vacuum.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1728,9 +1728,10 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
17281728
* might appear to go backwards, which is probably Not Good.
17291729
*/
17301730
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
1731-
MyPgXact->vacuumFlags |= PROC_IN_VACUUM;
1731+
MyProc->vacuumFlags |= PROC_IN_VACUUM;
17321732
if (params->is_wraparound)
1733-
MyPgXact->vacuumFlags |= PROC_VACUUM_FOR_WRAPAROUND;
1733+
MyProc->vacuumFlags |= PROC_VACUUM_FOR_WRAPAROUND;
1734+
ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags;
17341735
LWLockRelease(ProcArrayLock);
17351736
}
17361737

src/backend/postmaster/autovacuum.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2493,7 +2493,7 @@ do_autovacuum(void)
24932493
tab->at_datname, tab->at_nspname, tab->at_relname);
24942494
EmitErrorReport();
24952495

2496-
/* this resets the PGXACT flags too */
2496+
/* this resets ProcGlobal->vacuumFlags[i] too */
24972497
AbortOutOfAnyTransaction();
24982498
FlushErrorState();
24992499
MemoryContextResetAndDeleteChildren(PortalContext);
@@ -2509,7 +2509,7 @@ do_autovacuum(void)
25092509

25102510
did_vacuum = true;
25112511

2512-
/* the PGXACT flags are reset at the next end of transaction */
2512+
/* ProcGlobal->vacuumFlags[i] are reset at the next end of xact */
25132513

25142514
/* be tidy */
25152515
deleted:
@@ -2686,7 +2686,7 @@ perform_work_item(AutoVacuumWorkItem *workitem)
26862686
cur_datname, cur_nspname, cur_relname);
26872687
EmitErrorReport();
26882688

2689-
/* this resets the PGXACT flags too */
2689+
/* this resets ProcGlobal->vacuumFlags[i] too */
26902690
AbortOutOfAnyTransaction();
26912691
FlushErrorState();
26922692
MemoryContextResetAndDeleteChildren(PortalContext);

src/backend/replication/logical/logical.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,8 @@ StartupDecodingContext(List *output_plugin_options,
181181
if (!IsTransactionOrTransactionBlock())
182182
{
183183
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
184-
MyPgXact->vacuumFlags |= PROC_IN_LOGICAL_DECODING;
184+
MyProc->vacuumFlags |= PROC_IN_LOGICAL_DECODING;
185+
ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags;
185186
LWLockRelease(ProcArrayLock);
186187
}
187188

src/backend/replication/slot.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,8 @@ ReplicationSlotRelease(void)
520520

521521
/* might not have been set when we've been a plain slot */
522522
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
523-
MyPgXact->vacuumFlags &= ~PROC_IN_LOGICAL_DECODING;
523+
MyProc->vacuumFlags &= ~PROC_IN_LOGICAL_DECODING;
524+
ProcGlobal->vacuumFlags[MyProc->pgxactoff] = MyProc->vacuumFlags;
524525
LWLockRelease(ProcArrayLock);
525526
}
526527

src/backend/storage/ipc/procarray.c

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -476,9 +476,12 @@ ProcArrayAdd(PGPROC *proc)
476476
(arrayP->numProcs - index) * sizeof(*arrayP->pgprocnos));
477477
memmove(&ProcGlobal->xids[index + 1], &ProcGlobal->xids[index],
478478
(arrayP->numProcs - index) * sizeof(*ProcGlobal->xids));
479+
memmove(&ProcGlobal->vacuumFlags[index + 1], &ProcGlobal->vacuumFlags[index],
480+
(arrayP->numProcs - index) * sizeof(*ProcGlobal->vacuumFlags));
479481

480482
arrayP->pgprocnos[index] = proc->pgprocno;
481483
ProcGlobal->xids[index] = proc->xid;
484+
ProcGlobal->vacuumFlags[index] = proc->vacuumFlags;
482485

483486
arrayP->numProcs++;
484487

@@ -539,6 +542,7 @@ ProcArrayRemove(PGPROC *proc, TransactionId latestXid)
539542
}
540543

541544
Assert(TransactionIdIsValid(ProcGlobal->xids[proc->pgxactoff] == 0));
545+
ProcGlobal->vacuumFlags[proc->pgxactoff] = 0;
542546

543547
for (index = 0; index < arrayP->numProcs; index++)
544548
{
@@ -549,6 +553,8 @@ ProcArrayRemove(PGPROC *proc, TransactionId latestXid)
549553
(arrayP->numProcs - index - 1) * sizeof(*arrayP->pgprocnos));
550554
memmove(&ProcGlobal->xids[index], &ProcGlobal->xids[index + 1],
551555
(arrayP->numProcs - index - 1) * sizeof(*ProcGlobal->xids));
556+
memmove(&ProcGlobal->vacuumFlags[index], &ProcGlobal->vacuumFlags[index + 1],
557+
(arrayP->numProcs - index - 1) * sizeof(*ProcGlobal->vacuumFlags));
552558

553559
arrayP->pgprocnos[arrayP->numProcs - 1] = -1; /* for debugging */
554560
arrayP->numProcs--;
@@ -626,14 +632,24 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
626632
Assert(!TransactionIdIsValid(proc->xid));
627633

628634
proc->lxid = InvalidLocalTransactionId;
629-
/* must be cleared with xid/xmin: */
630-
pgxact->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
631635
proc->xmin = InvalidTransactionId;
632636
proc->delayChkpt = false; /* be sure this is cleared in abort */
633637
proc->recoveryConflictPending = false;
634638

635639
Assert(pgxact->nxids == 0);
636640
Assert(pgxact->overflowed == false);
641+
642+
/* must be cleared with xid/xmin: */
643+
/* avoid unnecessarily dirtying shared cachelines */
644+
if (proc->vacuumFlags & PROC_VACUUM_STATE_MASK)
645+
{
646+
Assert(!LWLockHeldByMe(ProcArrayLock));
647+
LWLockAcquire(ProcArrayLock, LW_SHARED);
648+
Assert(proc->vacuumFlags == ProcGlobal->vacuumFlags[proc->pgxactoff]);
649+
proc->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
650+
ProcGlobal->vacuumFlags[proc->pgxactoff] = proc->vacuumFlags;
651+
LWLockRelease(ProcArrayLock);
652+
}
637653
}
638654
}
639655

@@ -654,12 +670,18 @@ ProcArrayEndTransactionInternal(PGPROC *proc, PGXACT *pgxact,
654670
ProcGlobal->xids[pgxactoff] = InvalidTransactionId;
655671
proc->xid = InvalidTransactionId;
656672
proc->lxid = InvalidLocalTransactionId;
657-
/* must be cleared with xid/xmin: */
658-
pgxact->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
659673
proc->xmin = InvalidTransactionId;
660674
proc->delayChkpt = false; /* be sure this is cleared in abort */
661675
proc->recoveryConflictPending = false;
662676

677+
/* must be cleared with xid/xmin: */
678+
/* avoid unnecessarily dirtying shared cachelines */
679+
if (proc->vacuumFlags & PROC_VACUUM_STATE_MASK)
680+
{
681+
proc->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
682+
ProcGlobal->vacuumFlags[proc->pgxactoff] = proc->vacuumFlags;
683+
}
684+
663685
/* Clear the subtransaction-XID cache too while holding the lock */
664686
pgxact->nxids = 0;
665687
pgxact->overflowed = false;
@@ -819,9 +841,8 @@ ProcArrayClearTransaction(PGPROC *proc)
819841
proc->xmin = InvalidTransactionId;
820842
proc->recoveryConflictPending = false;
821843

822-
/* redundant, but just in case */
823-
pgxact->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
824-
proc->delayChkpt = false;
844+
Assert(!(proc->vacuumFlags & PROC_VACUUM_STATE_MASK));
845+
Assert(!proc->delayChkpt);
825846

826847
/* Clear the subtransaction-XID cache too */
827848
pgxact->nxids = 0;
@@ -1623,7 +1644,7 @@ ComputeXidHorizons(ComputeXidHorizonsResult *h)
16231644
{
16241645
int pgprocno = arrayP->pgprocnos[index];
16251646
PGPROC *proc = &allProcs[pgprocno];
1626-
PGXACT *pgxact = &allPgXact[pgprocno];
1647+
int8 vacuumFlags = ProcGlobal->vacuumFlags[index];
16271648
TransactionId xid;
16281649
TransactionId xmin;
16291650

@@ -1640,8 +1661,8 @@ ComputeXidHorizons(ComputeXidHorizonsResult *h)
16401661
*/
16411662
xmin = TransactionIdOlder(xmin, xid);
16421663

1643-
/* if neither is set, this proc doesn't influence the horizon */
1644-
if (!TransactionIdIsValid(xmin))
1664+
/* if neither is set, this proc doesn't influence the horizon */
1665+
if (!TransactionIdIsValid(xmin))
16451666
continue;
16461667

16471668
/*
@@ -1658,7 +1679,7 @@ ComputeXidHorizons(ComputeXidHorizonsResult *h)
16581679
* removed, as long as pg_subtrans is not truncated) or doing logical
16591680
* decoding (which manages xmin separately, check below).
16601681
*/
1661-
if (pgxact->vacuumFlags & (PROC_IN_VACUUM | PROC_IN_LOGICAL_DECODING))
1682+
if (vacuumFlags & (PROC_IN_VACUUM | PROC_IN_LOGICAL_DECODING))
16621683
continue;
16631684

16641685
/* shared tables need to take backends in all database into account */
@@ -1998,6 +2019,7 @@ GetSnapshotData(Snapshot snapshot)
19982019
size_t numProcs = arrayP->numProcs;
19992020
TransactionId *xip = snapshot->xip;
20002021
int *pgprocnos = arrayP->pgprocnos;
2022+
uint8 *allVacuumFlags = ProcGlobal->vacuumFlags;
20012023

20022024
/*
20032025
* First collect set of pgxactoff/xids that need to be included in the
@@ -2007,8 +2029,6 @@ GetSnapshotData(Snapshot snapshot)
20072029
{
20082030
/* Fetch xid just once - see GetNewTransactionId */
20092031
TransactionId xid = UINT32_ACCESS_ONCE(other_xids[pgxactoff]);
2010-
int pgprocno;
2011-
PGXACT *pgxact;
20122032
uint8 vacuumFlags;
20132033

20142034
Assert(allProcs[arrayP->pgprocnos[pgxactoff]].pgxactoff == pgxactoff);
@@ -2044,14 +2064,11 @@ GetSnapshotData(Snapshot snapshot)
20442064
if (!NormalTransactionIdPrecedes(xid, xmax))
20452065
continue;
20462066

2047-
pgprocno = pgprocnos[pgxactoff];
2048-
pgxact = &allPgXact[pgprocno];
2049-
vacuumFlags = pgxact->vacuumFlags;
2050-
20512067
/*
20522068
* Skip over backends doing logical decoding which manages xmin
20532069
* separately (check below) and ones running LAZY VACUUM.
20542070
*/
2071+
vacuumFlags = allVacuumFlags[pgxactoff];
20552072
if (vacuumFlags & (PROC_IN_LOGICAL_DECODING | PROC_IN_VACUUM))
20562073
continue;
20572074

@@ -2078,6 +2095,9 @@ GetSnapshotData(Snapshot snapshot)
20782095
*/
20792096
if (!suboverflowed)
20802097
{
2098+
int pgprocno = pgprocnos[pgxactoff];
2099+
PGXACT *pgxact = &allPgXact[pgprocno];
2100+
20812101
if (pgxact->overflowed)
20822102
suboverflowed = true;
20832103
else
@@ -2296,11 +2316,11 @@ ProcArrayInstallImportedXmin(TransactionId xmin,
22962316
{
22972317
int pgprocno = arrayP->pgprocnos[index];
22982318
PGPROC *proc = &allProcs[pgprocno];
2299-
PGXACT *pgxact = &allPgXact[pgprocno];
2319+
int vacuumFlags = ProcGlobal->vacuumFlags[index];
23002320
TransactionId xid;
23012321

23022322
/* Ignore procs running LAZY VACUUM */
2303-
if (pgxact->vacuumFlags & PROC_IN_VACUUM)
2323+
if (vacuumFlags & PROC_IN_VACUUM)
23042324
continue;
23052325

23062326
/* We are only interested in the specific virtual transaction. */
@@ -2990,12 +3010,12 @@ GetCurrentVirtualXIDs(TransactionId limitXmin, bool excludeXmin0,
29903010
{
29913011
int pgprocno = arrayP->pgprocnos[index];
29923012
PGPROC *proc = &allProcs[pgprocno];
2993-
PGXACT *pgxact = &allPgXact[pgprocno];
3013+
uint8 vacuumFlags = ProcGlobal->vacuumFlags[index];
29943014

29953015
if (proc == MyProc)
29963016
continue;
29973017

2998-
if (excludeVacuum & pgxact->vacuumFlags)
3018+
if (excludeVacuum & vacuumFlags)
29993019
continue;
30003020

30013021
if (allDbs || proc->databaseId == MyDatabaseId)
@@ -3410,7 +3430,7 @@ CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared)
34103430
{
34113431
int pgprocno = arrayP->pgprocnos[index];
34123432
PGPROC *proc = &allProcs[pgprocno];
3413-
PGXACT *pgxact = &allPgXact[pgprocno];
3433+
uint8 vacuumFlags = ProcGlobal->vacuumFlags[index];
34143434

34153435
if (proc->databaseId != databaseId)
34163436
continue;
@@ -3424,7 +3444,7 @@ CountOtherDBBackends(Oid databaseId, int *nbackends, int *nprepared)
34243444
else
34253445
{
34263446
(*nbackends)++;
3427-
if ((pgxact->vacuumFlags & PROC_IS_AUTOVACUUM) &&
3447+
if ((vacuumFlags & PROC_IS_AUTOVACUUM) &&
34283448
nautovacs < MAXAUTOVACPIDS)
34293449
autovac_pids[nautovacs++] = proc->pid;
34303450
}

src/backend/storage/lmgr/deadlock.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,6 @@ FindLockCycleRecurseMember(PGPROC *checkProc,
544544
{
545545
PGPROC *proc;
546546
LOCK *lock = checkProc->waitLock;
547-
PGXACT *pgxact;
548547
PROCLOCK *proclock;
549548
SHM_QUEUE *procLocks;
550549
LockMethod lockMethodTable;
@@ -582,7 +581,6 @@ FindLockCycleRecurseMember(PGPROC *checkProc,
582581
PGPROC *leader;
583582

584583
proc = proclock->tag.myProc;
585-
pgxact = &ProcGlobal->allPgXact[proc->pgprocno];
586584
leader = proc->lockGroupLeader == NULL ? proc : proc->lockGroupLeader;
587585

588586
/* A proc never blocks itself or any other lock group member */
@@ -630,7 +628,7 @@ FindLockCycleRecurseMember(PGPROC *checkProc,
630628
* ProcArrayLock.
631629
*/
632630
if (checkProc == MyProc &&
633-
pgxact->vacuumFlags & PROC_IS_AUTOVACUUM)
631+
proc->vacuumFlags & PROC_IS_AUTOVACUUM)
634632
blocking_autovacuum_proc = proc;
635633

636634
/* We're done looking at this proclock */

src/backend/storage/lmgr/proc.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ ProcGlobalShmemSize(void)
114114
size = add_size(size, mul_size(NUM_AUXILIARY_PROCS, sizeof(PGXACT)));
115115
size = add_size(size, mul_size(max_prepared_xacts, sizeof(PGXACT)));
116116
size = add_size(size, mul_size(TotalProcs, sizeof(*ProcGlobal->xids)));
117+
size = add_size(size, mul_size(TotalProcs, sizeof(*ProcGlobal->vacuumFlags)));
117118

118119
return size;
119120
}
@@ -223,6 +224,8 @@ InitProcGlobal(void)
223224
ProcGlobal->xids =
224225
(TransactionId *) ShmemAlloc(TotalProcs * sizeof(*ProcGlobal->xids));
225226
MemSet(ProcGlobal->xids, 0, TotalProcs * sizeof(*ProcGlobal->xids));
227+
ProcGlobal->vacuumFlags = (uint8 *) ShmemAlloc(TotalProcs * sizeof(*ProcGlobal->vacuumFlags));
228+
MemSet(ProcGlobal->vacuumFlags, 0, TotalProcs * sizeof(*ProcGlobal->vacuumFlags));
226229

227230
for (i = 0; i < TotalProcs; i++)
228231
{
@@ -405,10 +408,10 @@ InitProcess(void)
405408
MyProc->tempNamespaceId = InvalidOid;
406409
MyProc->isBackgroundWorker = IsBackgroundWorker;
407410
MyProc->delayChkpt = false;
408-
MyPgXact->vacuumFlags = 0;
411+
MyProc->vacuumFlags = 0;
409412
/* NB -- autovac launcher intentionally does not set IS_AUTOVACUUM */
410413
if (IsAutoVacuumWorkerProcess())
411-
MyPgXact->vacuumFlags |= PROC_IS_AUTOVACUUM;
414+
MyProc->vacuumFlags |= PROC_IS_AUTOVACUUM;
412415
MyProc->lwWaiting = false;
413416
MyProc->lwWaitMode = 0;
414417
MyProc->waitLock = NULL;
@@ -587,7 +590,7 @@ InitAuxiliaryProcess(void)
587590
MyProc->tempNamespaceId = InvalidOid;
588591
MyProc->isBackgroundWorker = IsBackgroundWorker;
589592
MyProc->delayChkpt = false;
590-
MyPgXact->vacuumFlags = 0;
593+
MyProc->vacuumFlags = 0;
591594
MyProc->lwWaiting = false;
592595
MyProc->lwWaitMode = 0;
593596
MyProc->waitLock = NULL;
@@ -1323,16 +1326,17 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
13231326
if (deadlock_state == DS_BLOCKED_BY_AUTOVACUUM && allow_autovacuum_cancel)
13241327
{
13251328
PGPROC *autovac = GetBlockingAutoVacuumPgproc();
1326-
PGXACT *autovac_pgxact = &ProcGlobal->allPgXact[autovac->pgprocno];
1329+
uint8 vacuumFlags;
13271330

13281331
LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE);
13291332

13301333
/*
13311334
* Only do it if the worker is not working to protect against Xid
13321335
* wraparound.
13331336
*/
1334-
if ((autovac_pgxact->vacuumFlags & PROC_IS_AUTOVACUUM) &&
1335-
!(autovac_pgxact->vacuumFlags & PROC_VACUUM_FOR_WRAPAROUND))
1337+
vacuumFlags = ProcGlobal->vacuumFlags[proc->pgxactoff];
1338+
if ((vacuumFlags & PROC_IS_AUTOVACUUM) &&
1339+
!(vacuumFlags & PROC_VACUUM_FOR_WRAPAROUND))
13361340
{
13371341
int pid = autovac->pid;
13381342
StringInfoData locktagbuf;

0 commit comments

Comments
 (0)