Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 1f51c17

Browse files
committed
snapshot scalability: Move PGXACT->xmin back to PGPROC.
Now that xmin isn't needed for GetSnapshotData() anymore, it leads to unnecessary cacheline ping-pong to have it in PGXACT, as it is updated considerably more frequently than the other PGXACT members. After the changes in dc7420c, this is a very straight-forward change. For highly concurrent, snapshot acquisition heavy, workloads this change alone can significantly increase scalability. E.g. plain pgbench on a smaller 2 socket machine gains 1.07x for read-only pgbench, 1.22x for read-only pgbench when submitting queries in batches of 100, and 2.85x for batches of 100 'SELECT';. The latter numbers are obviously not to be expected in the real-world, but micro-benchmark the snapshot computation scalability (previously spending ~80% of the time in GetSnapshotData()). Author: Andres Freund <andres@anarazel.de> Reviewed-By: Robert Haas <robertmhaas@gmail.com> Reviewed-By: Thomas Munro <thomas.munro@gmail.com> Reviewed-By: David Rowley <dgrowleyml@gmail.com> Discussion: https://postgr.es/m/20200301083601.ews6hz5dduc3w2se@alap3.anarazel.de
1 parent a811ea5 commit 1f51c17

File tree

12 files changed

+52
-56
lines changed

12 files changed

+52
-56
lines changed

src/backend/access/gist/gistxlog.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ gistRedoPageReuse(XLogReaderState *record)
389389
*
390390
* latestRemovedXid was the page's deleteXid. The
391391
* GlobalVisIsRemovableFullXid(deleteXid) test in gistPageRecyclable()
392-
* conceptually mirrors the pgxact->xmin > limitXmin test in
392+
* conceptually mirrors the PGPROC->xmin > limitXmin test in
393393
* GetConflictingVirtualXIDs(). Consequently, one XID value achieves the
394394
* same exclusion effect on primary and standby.
395395
*/

src/backend/access/nbtree/nbtpage.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -2317,7 +2317,7 @@ _bt_unlink_halfdead_page(Relation rel, Buffer leafbuf, BlockNumber scanblkno,
23172317
* we're in VACUUM and would not otherwise have an XID. Having already
23182318
* updated links to the target, ReadNewTransactionId() suffices as an
23192319
* upper bound. Any scan having retained a now-stale link is advertising
2320-
* in its PGXACT an xmin less than or equal to the value we read here. It
2320+
* in its PGPROC an xmin less than or equal to the value we read here. It
23212321
* will continue to do so, holding back the xmin horizon, for the duration
23222322
* of that scan.
23232323
*/

src/backend/access/transam/README

+2-2
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,7 @@ ensure that the C compiler does exactly what you tell it to.)
296296
Another important activity that uses the shared ProcArray is
297297
ComputeXidHorizons, which must determine a lower bound for the oldest xmin
298298
of any active MVCC snapshot, system-wide. Each individual backend
299-
advertises the smallest xmin of its own snapshots in MyPgXact->xmin, or zero
299+
advertises the smallest xmin of its own snapshots in MyProc->xmin, or zero
300300
if it currently has no live snapshots (eg, if it's between transactions or
301301
hasn't yet set a snapshot for a new transaction). ComputeXidHorizons takes
302302
the MIN() of the valid xmin fields. It does this with only shared lock on
@@ -331,7 +331,7 @@ necessary.
331331
Note that while it is certain that two concurrent executions of
332332
GetSnapshotData will compute the same xmin for their own snapshots, there is
333333
no such guarantee for the horizons computed by ComputeXidHorizons. This is
334-
because we allow XID-less transactions to clear their MyPgXact->xmin
334+
because we allow XID-less transactions to clear their MyProc->xmin
335335
asynchronously (without taking ProcArrayLock), so one execution might see
336336
what had been the oldest xmin, and another not. This is OK since the
337337
thresholds need only be a valid lower bound. As noted above, we are already

src/backend/access/transam/twophase.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -464,7 +464,7 @@ MarkAsPreparingGuts(GlobalTransaction gxact, TransactionId xid, const char *gid,
464464
/* We set up the gxact's VXID as InvalidBackendId/XID */
465465
proc->lxid = (LocalTransactionId) xid;
466466
pgxact->xid = xid;
467-
pgxact->xmin = InvalidTransactionId;
467+
Assert(proc->xmin == InvalidTransactionId);
468468
proc->delayChkpt = false;
469469
pgxact->vacuumFlags = 0;
470470
proc->pid = 0;

src/backend/commands/indexcmds.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1535,7 +1535,7 @@ DefineIndex(Oid relationId,
15351535
StartTransactionCommand();
15361536

15371537
/* We should now definitely not be advertising any xmin. */
1538-
Assert(MyPgXact->xmin == InvalidTransactionId);
1538+
Assert(MyProc->xmin == InvalidTransactionId);
15391539

15401540
/*
15411541
* The index is now valid in the sense that it contains all currently

src/backend/replication/logical/snapbuild.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -553,8 +553,8 @@ SnapBuildInitialSnapshot(SnapBuild *builder)
553553
elog(ERROR, "cannot build an initial slot snapshot, not all transactions are monitored anymore");
554554

555555
/* so we don't overwrite the existing value */
556-
if (TransactionIdIsValid(MyPgXact->xmin))
557-
elog(ERROR, "cannot build an initial slot snapshot when MyPgXact->xmin already is valid");
556+
if (TransactionIdIsValid(MyProc->xmin))
557+
elog(ERROR, "cannot build an initial slot snapshot when MyProc->xmin already is valid");
558558

559559
snap = SnapBuildBuildSnapshot(builder);
560560

@@ -575,7 +575,7 @@ SnapBuildInitialSnapshot(SnapBuild *builder)
575575
}
576576
#endif
577577

578-
MyPgXact->xmin = snap->xmin;
578+
MyProc->xmin = snap->xmin;
579579

580580
/* allocate in transaction context */
581581
newxip = (TransactionId *)

src/backend/replication/walsender.c

+5-5
Original file line numberDiff line numberDiff line change
@@ -1964,7 +1964,7 @@ PhysicalReplicationSlotNewXmin(TransactionId feedbackXmin, TransactionId feedbac
19641964
ReplicationSlot *slot = MyReplicationSlot;
19651965

19661966
SpinLockAcquire(&slot->mutex);
1967-
MyPgXact->xmin = InvalidTransactionId;
1967+
MyProc->xmin = InvalidTransactionId;
19681968

19691969
/*
19701970
* For physical replication we don't need the interlock provided by xmin
@@ -2093,7 +2093,7 @@ ProcessStandbyHSFeedbackMessage(void)
20932093
if (!TransactionIdIsNormal(feedbackXmin)
20942094
&& !TransactionIdIsNormal(feedbackCatalogXmin))
20952095
{
2096-
MyPgXact->xmin = InvalidTransactionId;
2096+
MyProc->xmin = InvalidTransactionId;
20972097
if (MyReplicationSlot != NULL)
20982098
PhysicalReplicationSlotNewXmin(feedbackXmin, feedbackCatalogXmin);
20992099
return;
@@ -2135,7 +2135,7 @@ ProcessStandbyHSFeedbackMessage(void)
21352135
* risk already since a VACUUM could already have determined the horizon.)
21362136
*
21372137
* If we're using a replication slot we reserve the xmin via that,
2138-
* otherwise via the walsender's PGXACT entry. We can only track the
2138+
* otherwise via the walsender's PGPROC entry. We can only track the
21392139
* catalog xmin separately when using a slot, so we store the least of the
21402140
* two provided when not using a slot.
21412141
*
@@ -2148,9 +2148,9 @@ ProcessStandbyHSFeedbackMessage(void)
21482148
{
21492149
if (TransactionIdIsNormal(feedbackCatalogXmin)
21502150
&& TransactionIdPrecedes(feedbackCatalogXmin, feedbackXmin))
2151-
MyPgXact->xmin = feedbackCatalogXmin;
2151+
MyProc->xmin = feedbackCatalogXmin;
21522152
else
2153-
MyPgXact->xmin = feedbackXmin;
2153+
MyProc->xmin = feedbackXmin;
21542154
}
21552155
}
21562156

src/backend/storage/ipc/procarray.c

+16-20
Original file line numberDiff line numberDiff line change
@@ -587,9 +587,9 @@ ProcArrayEndTransaction(PGPROC *proc, TransactionId latestXid)
587587
Assert(!TransactionIdIsValid(allPgXact[proc->pgprocno].xid));
588588

589589
proc->lxid = InvalidLocalTransactionId;
590-
pgxact->xmin = InvalidTransactionId;
591590
/* must be cleared with xid/xmin: */
592591
pgxact->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
592+
proc->xmin = InvalidTransactionId;
593593
proc->delayChkpt = false; /* be sure this is cleared in abort */
594594
proc->recoveryConflictPending = false;
595595

@@ -609,9 +609,9 @@ ProcArrayEndTransactionInternal(PGPROC *proc, PGXACT *pgxact,
609609
{
610610
pgxact->xid = InvalidTransactionId;
611611
proc->lxid = InvalidLocalTransactionId;
612-
pgxact->xmin = InvalidTransactionId;
613612
/* must be cleared with xid/xmin: */
614613
pgxact->vacuumFlags &= ~PROC_VACUUM_STATE_MASK;
614+
proc->xmin = InvalidTransactionId;
615615
proc->delayChkpt = false; /* be sure this is cleared in abort */
616616
proc->recoveryConflictPending = false;
617617

@@ -763,7 +763,7 @@ ProcArrayClearTransaction(PGPROC *proc)
763763
*/
764764
pgxact->xid = InvalidTransactionId;
765765
proc->lxid = InvalidLocalTransactionId;
766-
pgxact->xmin = InvalidTransactionId;
766+
proc->xmin = InvalidTransactionId;
767767
proc->recoveryConflictPending = false;
768768

769769
/* redundant, but just in case */
@@ -1563,7 +1563,7 @@ ComputeXidHorizons(ComputeXidHorizonsResult *h)
15631563

15641564
/* Fetch xid just once - see GetNewTransactionId */
15651565
xid = UINT32_ACCESS_ONCE(pgxact->xid);
1566-
xmin = UINT32_ACCESS_ONCE(pgxact->xmin);
1566+
xmin = UINT32_ACCESS_ONCE(proc->xmin);
15671567

15681568
/*
15691569
* Consider both the transaction's Xmin, and its Xid.
@@ -1838,7 +1838,7 @@ GetMaxSnapshotSubxidCount(void)
18381838
*
18391839
* We also update the following backend-global variables:
18401840
* TransactionXmin: the oldest xmin of any snapshot in use in the
1841-
* current transaction (this is the same as MyPgXact->xmin).
1841+
* current transaction (this is the same as MyProc->xmin).
18421842
* RecentXmin: the xmin computed for the most recent snapshot. XIDs
18431843
* older than this are known not running any more.
18441844
*
@@ -1899,7 +1899,7 @@ GetSnapshotData(Snapshot snapshot)
18991899

19001900
/*
19011901
* It is sufficient to get shared lock on ProcArrayLock, even if we are
1902-
* going to set MyPgXact->xmin.
1902+
* going to set MyProc->xmin.
19031903
*/
19041904
LWLockAcquire(ProcArrayLock, LW_SHARED);
19051905

@@ -2051,8 +2051,8 @@ GetSnapshotData(Snapshot snapshot)
20512051
replication_slot_xmin = procArray->replication_slot_xmin;
20522052
replication_slot_catalog_xmin = procArray->replication_slot_catalog_xmin;
20532053

2054-
if (!TransactionIdIsValid(MyPgXact->xmin))
2055-
MyPgXact->xmin = TransactionXmin = xmin;
2054+
if (!TransactionIdIsValid(MyProc->xmin))
2055+
MyProc->xmin = TransactionXmin = xmin;
20562056

20572057
LWLockRelease(ProcArrayLock);
20582058

@@ -2172,7 +2172,7 @@ GetSnapshotData(Snapshot snapshot)
21722172
}
21732173

21742174
/*
2175-
* ProcArrayInstallImportedXmin -- install imported xmin into MyPgXact->xmin
2175+
* ProcArrayInstallImportedXmin -- install imported xmin into MyProc->xmin
21762176
*
21772177
* This is called when installing a snapshot imported from another
21782178
* transaction. To ensure that OldestXmin doesn't go backwards, we must
@@ -2225,7 +2225,7 @@ ProcArrayInstallImportedXmin(TransactionId xmin,
22252225
/*
22262226
* Likewise, let's just make real sure its xmin does cover us.
22272227
*/
2228-
xid = UINT32_ACCESS_ONCE(pgxact->xmin);
2228+
xid = UINT32_ACCESS_ONCE(proc->xmin);
22292229
if (!TransactionIdIsNormal(xid) ||
22302230
!TransactionIdPrecedesOrEquals(xid, xmin))
22312231
continue;
@@ -2236,7 +2236,7 @@ ProcArrayInstallImportedXmin(TransactionId xmin,
22362236
* GetSnapshotData first, we'll be overwriting a valid xmin here, so
22372237
* we don't check that.)
22382238
*/
2239-
MyPgXact->xmin = TransactionXmin = xmin;
2239+
MyProc->xmin = TransactionXmin = xmin;
22402240

22412241
result = true;
22422242
break;
@@ -2248,7 +2248,7 @@ ProcArrayInstallImportedXmin(TransactionId xmin,
22482248
}
22492249

22502250
/*
2251-
* ProcArrayInstallRestoredXmin -- install restored xmin into MyPgXact->xmin
2251+
* ProcArrayInstallRestoredXmin -- install restored xmin into MyProc->xmin
22522252
*
22532253
* This is like ProcArrayInstallImportedXmin, but we have a pointer to the
22542254
* PGPROC of the transaction from which we imported the snapshot, rather than
@@ -2261,28 +2261,25 @@ ProcArrayInstallRestoredXmin(TransactionId xmin, PGPROC *proc)
22612261
{
22622262
bool result = false;
22632263
TransactionId xid;
2264-
PGXACT *pgxact;
22652264

22662265
Assert(TransactionIdIsNormal(xmin));
22672266
Assert(proc != NULL);
22682267

22692268
/* Get lock so source xact can't end while we're doing this */
22702269
LWLockAcquire(ProcArrayLock, LW_SHARED);
22712270

2272-
pgxact = &allPgXact[proc->pgprocno];
2273-
22742271
/*
22752272
* Be certain that the referenced PGPROC has an advertised xmin which is
22762273
* no later than the one we're installing, so that the system-wide xmin
22772274
* can't go backwards. Also, make sure it's running in the same database,
22782275
* so that the per-database xmin cannot go backwards.
22792276
*/
2280-
xid = UINT32_ACCESS_ONCE(pgxact->xmin);
2277+
xid = UINT32_ACCESS_ONCE(proc->xmin);
22812278
if (proc->databaseId == MyDatabaseId &&
22822279
TransactionIdIsNormal(xid) &&
22832280
TransactionIdPrecedesOrEquals(xid, xmin))
22842281
{
2285-
MyPgXact->xmin = TransactionXmin = xmin;
2282+
MyProc->xmin = TransactionXmin = xmin;
22862283
result = true;
22872284
}
22882285

@@ -2908,7 +2905,7 @@ GetCurrentVirtualXIDs(TransactionId limitXmin, bool excludeXmin0,
29082905
if (allDbs || proc->databaseId == MyDatabaseId)
29092906
{
29102907
/* Fetch xmin just once - might change on us */
2911-
TransactionId pxmin = UINT32_ACCESS_ONCE(pgxact->xmin);
2908+
TransactionId pxmin = UINT32_ACCESS_ONCE(proc->xmin);
29122909

29132910
if (excludeXmin0 && !TransactionIdIsValid(pxmin))
29142911
continue;
@@ -2994,7 +2991,6 @@ GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid)
29942991
{
29952992
int pgprocno = arrayP->pgprocnos[index];
29962993
PGPROC *proc = &allProcs[pgprocno];
2997-
PGXACT *pgxact = &allPgXact[pgprocno];
29982994

29992995
/* Exclude prepared transactions */
30002996
if (proc->pid == 0)
@@ -3004,7 +3000,7 @@ GetConflictingVirtualXIDs(TransactionId limitXmin, Oid dbOid)
30043000
proc->databaseId == dbOid)
30053001
{
30063002
/* Fetch xmin just once - can't change on us, but good coding */
3007-
TransactionId pxmin = UINT32_ACCESS_ONCE(pgxact->xmin);
3003+
TransactionId pxmin = UINT32_ACCESS_ONCE(proc->xmin);
30083004

30093005
/*
30103006
* We ignore an invalid pxmin because this means that backend has

src/backend/storage/ipc/sinvaladt.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ BackendIdGetTransactionIds(int backendID, TransactionId *xid, TransactionId *xmi
420420
PGXACT *xact = &ProcGlobal->allPgXact[proc->pgprocno];
421421

422422
*xid = xact->xid;
423-
*xmin = xact->xmin;
423+
*xmin = proc->xmin;
424424
}
425425
}
426426

src/backend/storage/lmgr/proc.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ InitProcess(void)
388388
MyProc->fpVXIDLock = false;
389389
MyProc->fpLocalTransactionId = InvalidLocalTransactionId;
390390
MyPgXact->xid = InvalidTransactionId;
391-
MyPgXact->xmin = InvalidTransactionId;
391+
MyProc->xmin = InvalidTransactionId;
392392
MyProc->pid = MyProcPid;
393393
/* backendId, databaseId and roleId will be filled in later */
394394
MyProc->backendId = InvalidBackendId;
@@ -572,7 +572,7 @@ InitAuxiliaryProcess(void)
572572
MyProc->fpVXIDLock = false;
573573
MyProc->fpLocalTransactionId = InvalidLocalTransactionId;
574574
MyPgXact->xid = InvalidTransactionId;
575-
MyPgXact->xmin = InvalidTransactionId;
575+
MyProc->xmin = InvalidTransactionId;
576576
MyProc->backendId = InvalidBackendId;
577577
MyProc->databaseId = InvalidOid;
578578
MyProc->roleId = InvalidOid;

0 commit comments

Comments
 (0)