Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit3bd7f99

Browse files
committed
Track latest completed xid as a FullTransactionId.
The reason for doing so is that a subsequent commit will need that toavoid wraparound issues. As the subsequent change is large this wassplit out for easier review.The reason this is not a perfect straight-forward change is that we donot want track 64bit xids in the procarray or the WAL. Therefore weneed to advance lastestCompletedXid in relation to 32 bit xids. Thecode for that is now centralized in MaintainLatestCompletedXid*.Author: Andres FreundReviewed-By: Thomas Munro, Robert Haas, David RowleyDiscussion:https://postgr.es/m/20200301083601.ews6hz5dduc3w2se@alap3.anarazel.de
1 parentfea10a6 commit3bd7f99

File tree

4 files changed

+191
-29
lines changed

4 files changed

+191
-29
lines changed

‎src/backend/access/transam/varsup.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,3 +569,53 @@ GetNewObjectId(void)
569569

570570
returnresult;
571571
}
572+
573+
574+
#ifdefUSE_ASSERT_CHECKING
575+
576+
/*
577+
* Assert that xid is between [oldestXid, nextXid], which is the range we
578+
* expect XIDs coming from tables etc to be in.
579+
*
580+
* As ShmemVariableCache->oldestXid could change just after this call without
581+
* further precautions, and as a wrapped-around xid could again fall within
582+
* the valid range, this assertion can only detect if something is definitely
583+
* wrong, but not establish correctness.
584+
*
585+
* This intentionally does not expose a return value, to avoid code being
586+
* introduced that depends on the return value.
587+
*/
588+
void
589+
AssertTransactionIdInAllowableRange(TransactionIdxid)
590+
{
591+
TransactionIdoldest_xid;
592+
TransactionIdnext_xid;
593+
594+
Assert(TransactionIdIsValid(xid));
595+
596+
/* we may see bootstrap / frozen */
597+
if (!TransactionIdIsNormal(xid))
598+
return;
599+
600+
/*
601+
* We can't acquire XidGenLock, as this may be called with XidGenLock
602+
* already held (or with other locks that don't allow XidGenLock to be
603+
* nested). That's ok for our purposes though, since we already rely on
604+
* 32bit reads to be atomic. While nextXid is 64 bit, we only look at
605+
* the lower 32bit, so a skewed read doesn't hurt.
606+
*
607+
* There's no increased danger of falling outside [oldest, next] by
608+
* accessing them without a lock. xid needs to have been created with
609+
* GetNewTransactionId() in the originating session, and the locks there
610+
* pair with the memory barrier below. We do however accept xid to be <=
611+
* to next_xid, instead of just <, as xid could be from the procarray,
612+
* before we see the updated nextXid value.
613+
*/
614+
pg_memory_barrier();
615+
oldest_xid=ShmemVariableCache->oldestXid;
616+
next_xid=XidFromFullTransactionId(ShmemVariableCache->nextXid);
617+
618+
Assert(TransactionIdFollowsOrEquals(xid,oldest_xid)||
619+
TransactionIdPrecedesOrEquals(xid,next_xid));
620+
}
621+
#endif

‎src/backend/access/transam/xlog.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7865,8 +7865,8 @@ StartupXLOG(void)
78657865

78667866
/* also initialize latestCompletedXid, to nextXid - 1 */
78677867
LWLockAcquire(ProcArrayLock,LW_EXCLUSIVE);
7868-
ShmemVariableCache->latestCompletedXid=XidFromFullTransactionId(ShmemVariableCache->nextXid);
7869-
TransactionIdRetreat(ShmemVariableCache->latestCompletedXid);
7868+
ShmemVariableCache->latestCompletedXid=ShmemVariableCache->nextXid;
7869+
FullTransactionIdRetreat(&ShmemVariableCache->latestCompletedXid);
78707870
LWLockRelease(ProcArrayLock);
78717871

78727872
/*

‎src/backend/storage/ipc/procarray.c

Lines changed: 104 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,11 @@ static void KnownAssignedXidsReset(void);
175175
staticinlinevoidProcArrayEndTransactionInternal(PGPROC*proc,
176176
PGXACT*pgxact,TransactionIdlatestXid);
177177
staticvoidProcArrayGroupClearXid(PGPROC*proc,TransactionIdlatestXid);
178+
staticvoidMaintainLatestCompletedXid(TransactionIdlatestXid);
179+
staticvoidMaintainLatestCompletedXidRecovery(TransactionIdlatestXid);
180+
181+
staticinlineFullTransactionIdFullXidRelativeTo(FullTransactionIdrel,
182+
TransactionIdxid);
178183

179184
/*
180185
* Report shared-memory space needed by CreateSharedProcArray.
@@ -349,9 +354,7 @@ ProcArrayRemove(PGPROC *proc, TransactionId latestXid)
349354
Assert(TransactionIdIsValid(allPgXact[proc->pgprocno].xid));
350355

351356
/* Advance global latestCompletedXid while holding the lock */
352-
if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid,
353-
latestXid))
354-
ShmemVariableCache->latestCompletedXid=latestXid;
357+
MaintainLatestCompletedXid(latestXid);
355358
}
356359
else
357360
{
@@ -464,9 +467,7 @@ ProcArrayEndTransactionInternal(PGPROC *proc, PGXACT *pgxact,
464467
pgxact->overflowed= false;
465468

466469
/* Also advance global latestCompletedXid while holding the lock */
467-
if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid,
468-
latestXid))
469-
ShmemVariableCache->latestCompletedXid=latestXid;
470+
MaintainLatestCompletedXid(latestXid);
470471
}
471472

472473
/*
@@ -621,6 +622,59 @@ ProcArrayClearTransaction(PGPROC *proc)
621622
pgxact->overflowed= false;
622623
}
623624

625+
/*
626+
* Update ShmemVariableCache->latestCompletedXid to point to latestXid if
627+
* currently older.
628+
*/
629+
staticvoid
630+
MaintainLatestCompletedXid(TransactionIdlatestXid)
631+
{
632+
FullTransactionIdcur_latest=ShmemVariableCache->latestCompletedXid;
633+
634+
Assert(FullTransactionIdIsValid(cur_latest));
635+
Assert(!RecoveryInProgress());
636+
Assert(LWLockHeldByMe(ProcArrayLock));
637+
638+
if (TransactionIdPrecedes(XidFromFullTransactionId(cur_latest),latestXid))
639+
{
640+
ShmemVariableCache->latestCompletedXid=
641+
FullXidRelativeTo(cur_latest,latestXid);
642+
}
643+
644+
Assert(IsBootstrapProcessingMode()||
645+
FullTransactionIdIsNormal(ShmemVariableCache->latestCompletedXid));
646+
}
647+
648+
/*
649+
* Same as MaintainLatestCompletedXid, except for use during WAL replay.
650+
*/
651+
staticvoid
652+
MaintainLatestCompletedXidRecovery(TransactionIdlatestXid)
653+
{
654+
FullTransactionIdcur_latest=ShmemVariableCache->latestCompletedXid;
655+
FullTransactionIdrel;
656+
657+
Assert(AmStartupProcess()|| !IsUnderPostmaster);
658+
Assert(LWLockHeldByMe(ProcArrayLock));
659+
660+
/*
661+
* Need a FullTransactionId to compare latestXid with. Can't rely on
662+
* latestCompletedXid to be initialized in recovery. But in recovery it's
663+
* safe to access nextXid without a lock for the startup process.
664+
*/
665+
rel=ShmemVariableCache->nextXid;
666+
Assert(FullTransactionIdIsValid(ShmemVariableCache->nextXid));
667+
668+
if (!FullTransactionIdIsValid(cur_latest)||
669+
TransactionIdPrecedes(XidFromFullTransactionId(cur_latest),latestXid))
670+
{
671+
ShmemVariableCache->latestCompletedXid=
672+
FullXidRelativeTo(rel,latestXid);
673+
}
674+
675+
Assert(FullTransactionIdIsNormal(ShmemVariableCache->latestCompletedXid));
676+
}
677+
624678
/*
625679
* ProcArrayInitRecovery -- initialize recovery xid mgmt environment
626680
*
@@ -869,12 +923,9 @@ ProcArrayApplyRecoveryInfo(RunningTransactions running)
869923
* If a transaction wrote a commit record in the gap between taking and
870924
* logging the snapshot then latestCompletedXid may already be higher than
871925
* the value from the snapshot, so check before we use the incoming value.
926+
* It also might not yet be set at all.
872927
*/
873-
if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid,
874-
running->latestCompletedXid))
875-
ShmemVariableCache->latestCompletedXid=running->latestCompletedXid;
876-
877-
Assert(TransactionIdIsNormal(ShmemVariableCache->latestCompletedXid));
928+
MaintainLatestCompletedXidRecovery(running->latestCompletedXid);
878929

879930
LWLockRelease(ProcArrayLock);
880931

@@ -989,6 +1040,7 @@ TransactionIdIsInProgress(TransactionId xid)
9891040
intnxids=0;
9901041
ProcArrayStruct*arrayP=procArray;
9911042
TransactionIdtopxid;
1043+
TransactionIdlatestCompletedXid;
9921044
inti,
9931045
j;
9941046

@@ -1051,7 +1103,9 @@ TransactionIdIsInProgress(TransactionId xid)
10511103
* Now that we have the lock, we can check latestCompletedXid; if the
10521104
* target Xid is after that, it's surely still running.
10531105
*/
1054-
if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid,xid))
1106+
latestCompletedXid=
1107+
XidFromFullTransactionId(ShmemVariableCache->latestCompletedXid);
1108+
if (TransactionIdPrecedes(latestCompletedXid,xid))
10551109
{
10561110
LWLockRelease(ProcArrayLock);
10571111
xc_by_latest_xid_inc();
@@ -1330,9 +1384,9 @@ GetOldestXmin(Relation rel, int flags)
13301384
* and so protects us against overestimating the result due to future
13311385
* additions.
13321386
*/
1333-
result=ShmemVariableCache->latestCompletedXid;
1334-
Assert(TransactionIdIsNormal(result));
1387+
result=XidFromFullTransactionId(ShmemVariableCache->latestCompletedXid);
13351388
TransactionIdAdvance(result);
1389+
Assert(TransactionIdIsNormal(result));
13361390

13371391
for (index=0;index<arrayP->numProcs;index++)
13381392
{
@@ -1511,6 +1565,7 @@ GetSnapshotData(Snapshot snapshot)
15111565
intcount=0;
15121566
intsubcount=0;
15131567
boolsuboverflowed= false;
1568+
FullTransactionIdlatest_completed;
15141569
TransactionIdreplication_slot_xmin=InvalidTransactionId;
15151570
TransactionIdreplication_slot_catalog_xmin=InvalidTransactionId;
15161571

@@ -1554,10 +1609,11 @@ GetSnapshotData(Snapshot snapshot)
15541609
*/
15551610
LWLockAcquire(ProcArrayLock,LW_SHARED);
15561611

1612+
latest_completed=ShmemVariableCache->latestCompletedXid;
15571613
/* xmax is always latestCompletedXid + 1 */
1558-
xmax=ShmemVariableCache->latestCompletedXid;
1559-
Assert(TransactionIdIsNormal(xmax));
1614+
xmax=XidFromFullTransactionId(latest_completed);
15601615
TransactionIdAdvance(xmax);
1616+
Assert(TransactionIdIsNormal(xmax));
15611617

15621618
/* initialize xmin calculation with xmax */
15631619
globalxmin=xmin=xmax;
@@ -1984,9 +2040,10 @@ GetRunningTransactionData(void)
19842040
LWLockAcquire(ProcArrayLock,LW_SHARED);
19852041
LWLockAcquire(XidGenLock,LW_SHARED);
19862042

1987-
latestCompletedXid=ShmemVariableCache->latestCompletedXid;
1988-
1989-
oldestRunningXid=XidFromFullTransactionId(ShmemVariableCache->nextXid);
2043+
latestCompletedXid=
2044+
XidFromFullTransactionId(ShmemVariableCache->latestCompletedXid);
2045+
oldestRunningXid=
2046+
XidFromFullTransactionId(ShmemVariableCache->nextXid);
19902047

19912048
/*
19922049
* Spin over procArray collecting all xids
@@ -3207,9 +3264,7 @@ XidCacheRemoveRunningXids(TransactionId xid,
32073264
elog(WARNING,"did not find subXID %u in MyProc",xid);
32083265

32093266
/* Also advance global latestCompletedXid while holding the lock */
3210-
if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid,
3211-
latestXid))
3212-
ShmemVariableCache->latestCompletedXid=latestXid;
3267+
MaintainLatestCompletedXid(latestXid);
32133268

32143269
LWLockRelease(ProcArrayLock);
32153270
}
@@ -3236,6 +3291,32 @@ DisplayXidCache(void)
32363291
}
32373292
#endif/* XIDCACHE_DEBUG */
32383293

3294+
/*
3295+
* Convert a 32 bit transaction id into 64 bit transaction id, by assuming it
3296+
* is within MaxTransactionId / 2 of XidFromFullTransactionId(rel).
3297+
*
3298+
* Be very careful about when to use this function. It can only safely be used
3299+
* when there is a guarantee that xid is within MaxTransactionId / 2 xids of
3300+
* rel. That e.g. can be guaranteed if the the caller assures a snapshot is
3301+
* held by the backend and xid is from a table (where vacuum/freezing ensures
3302+
* the xid has to be within that range), or if xid is from the procarray and
3303+
* prevents xid wraparound that way.
3304+
*/
3305+
staticinlineFullTransactionId
3306+
FullXidRelativeTo(FullTransactionIdrel,TransactionIdxid)
3307+
{
3308+
TransactionIdrel_xid=XidFromFullTransactionId(rel);
3309+
3310+
Assert(TransactionIdIsValid(xid));
3311+
Assert(TransactionIdIsValid(rel_xid));
3312+
3313+
/* not guaranteed to find issues, but likely to catch mistakes */
3314+
AssertTransactionIdInAllowableRange(xid);
3315+
3316+
returnFullTransactionIdFromU64(U64FromFullTransactionId(rel)
3317+
+ (int32) (xid-rel_xid));
3318+
}
3319+
32393320

32403321
/* ----------------------------------------------
32413322
*KnownAssignedTransactionIds sub-module
@@ -3388,9 +3469,7 @@ ExpireTreeKnownAssignedTransactionIds(TransactionId xid, int nsubxids,
33883469
KnownAssignedXidsRemoveTree(xid,nsubxids,subxids);
33893470

33903471
/* As in ProcArrayEndTransaction, advance latestCompletedXid */
3391-
if (TransactionIdPrecedes(ShmemVariableCache->latestCompletedXid,
3392-
max_xid))
3393-
ShmemVariableCache->latestCompletedXid=max_xid;
3472+
MaintainLatestCompletedXidRecovery(max_xid);
33943473

33953474
LWLockRelease(ProcArrayLock);
33963475
}

‎src/include/access/transam.h

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@
5454
#defineFullTransactionIdFollowsOrEquals(a,b) ((a).value >= (b).value)
5555
#defineFullTransactionIdIsValid(x)TransactionIdIsValid(XidFromFullTransactionId(x))
5656
#defineInvalidFullTransactionIdFullTransactionIdFromEpochAndXid(0, InvalidTransactionId)
57+
#defineFirstNormalFullTransactionIdFullTransactionIdFromEpochAndXid(0, FirstNormalTransactionId)
58+
#defineFullTransactionIdIsNormal(x)FullTransactionIdFollowsOrEquals(x, FirstNormalFullTransactionId)
5759

5860
/*
5961
* A 64 bit value that contains an epoch and a TransactionId. This is
@@ -102,6 +104,31 @@ FullTransactionIdAdvance(FullTransactionId *dest)
102104
dest->value++;
103105
}
104106

107+
/*
108+
* Retreat a FullTransactionId variable, stepping over xids that would appear
109+
* to be special only when viewed as 32bit XIDs.
110+
*/
111+
staticinlinevoid
112+
FullTransactionIdRetreat(FullTransactionId*dest)
113+
{
114+
dest->value--;
115+
116+
/*
117+
* In contrast to 32bit XIDs don't step over the "actual" special xids.
118+
* For 64bit xids these can't be reached as part of a wraparound as they
119+
* can in the 32bit case.
120+
*/
121+
if (FullTransactionIdPrecedes(*dest,FirstNormalFullTransactionId))
122+
return;
123+
124+
/*
125+
* But we do need to step over XIDs that'd appear special only for 32bit
126+
* XIDs.
127+
*/
128+
while (XidFromFullTransactionId(*dest)<FirstNormalTransactionId)
129+
dest->value--;
130+
}
131+
105132
/* back up a transaction ID variable, handling wraparound correctly */
106133
#defineTransactionIdRetreat(dest)\
107134
do { \
@@ -193,8 +220,8 @@ typedef struct VariableCacheData
193220
/*
194221
* These fields are protected by ProcArrayLock.
195222
*/
196-
TransactionIdlatestCompletedXid;/* newest XID that has committed or
197-
* aborted */
223+
FullTransactionIdlatestCompletedXid;/* newestfullXID that has
224+
* committed or aborted */
198225

199226
/*
200227
* These fields are protected by XactTruncationLock
@@ -244,6 +271,12 @@ extern void AdvanceOldestClogXid(TransactionId oldest_datfrozenxid);
244271
externboolForceTransactionIdLimitUpdate(void);
245272
externOidGetNewObjectId(void);
246273

274+
#ifdefUSE_ASSERT_CHECKING
275+
externvoidAssertTransactionIdInAllowableRange(TransactionIdxid);
276+
#else
277+
#defineAssertTransactionIdInAllowableRange(xid) ((void)true)
278+
#endif
279+
247280
/*
248281
* Some frontend programs include this header. For compilers that emit static
249282
* inline functions even when they're unused, that leads to unsatisfied

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp