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

Commit1587f7b

Browse files
committed
Merge copies of converting an XID to a FullTransactionId.
Assume twophase.c is the performance-sensitive caller, and preserve itschoice of unlikely() branch hint. Add some retrospective rationale forthat choice. Back-patch to v17, for the next commit to use it.Reviewed (in earlier versions) by Michael Paquier.Discussion:https://postgr.es/m/17821-dd8c334263399284@postgresql.orgDiscussion:https://postgr.es/m/20250116010051.f3.nmisch@google.com
1 parenteca456e commit1587f7b

File tree

5 files changed

+77
-93
lines changed

5 files changed

+77
-93
lines changed

‎contrib/amcheck/verify_heapam.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1875,7 +1875,9 @@ check_tuple(HeapCheckContext *ctx, bool *xmin_commit_status_ok,
18751875
/*
18761876
* Convert a TransactionId into a FullTransactionId using our cached values of
18771877
* the valid transaction ID range. It is the caller's responsibility to have
1878-
* already updated the cached values, if necessary.
1878+
* already updated the cached values, if necessary. This is akin to
1879+
* FullTransactionIdFromAllowableAt(), but it tolerates corruption in the form
1880+
* of an xid before epoch 0.
18791881
*/
18801882
staticFullTransactionId
18811883
FullTransactionIdFromXidAndCtx(TransactionIdxid,constHeapCheckContext*ctx)

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

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -929,32 +929,16 @@ TwoPhaseGetDummyProc(TransactionId xid, bool lock_held)
929929
/*
930930
* Compute the FullTransactionId for the given TransactionId.
931931
*
932-
* The wrap logic is safe here because the span of active xids cannot exceed one
933-
* epoch at any given time.
932+
* This is safe if the xid has not yet reached COMMIT PREPARED or ROLLBACK
933+
* PREPARED. After those commands, concurrent vac_truncate_clog() may make
934+
* the xid cease to qualify as allowable. XXX Not all callers limit their
935+
* calls accordingly.
934936
*/
935937
staticinlineFullTransactionId
936938
AdjustToFullTransactionId(TransactionIdxid)
937939
{
938-
FullTransactionIdnextFullXid;
939-
TransactionIdnextXid;
940-
uint32epoch;
941-
942940
Assert(TransactionIdIsValid(xid));
943-
944-
LWLockAcquire(XidGenLock,LW_SHARED);
945-
nextFullXid=TransamVariables->nextXid;
946-
LWLockRelease(XidGenLock);
947-
948-
nextXid=XidFromFullTransactionId(nextFullXid);
949-
epoch=EpochFromFullTransactionId(nextFullXid);
950-
if (unlikely(xid>nextXid))
951-
{
952-
/* Wraparound occurred, must be from a prev epoch. */
953-
Assert(epoch>0);
954-
epoch--;
955-
}
956-
957-
returnFullTransactionIdFromEpochAndXid(epoch,xid);
941+
returnFullTransactionIdFromAllowableAt(ReadNextFullTransactionId(),xid);
958942
}
959943

960944
staticinlineint

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

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2166,28 +2166,14 @@ RestoreBlockImage(XLogReaderState *record, uint8 block_id, char *page)
21662166
FullTransactionId
21672167
XLogRecGetFullXid(XLogReaderState*record)
21682168
{
2169-
TransactionIdxid,
2170-
next_xid;
2171-
uint32epoch;
2172-
21732169
/*
21742170
* This function is only safe during replay, because it depends on the
21752171
* replay state. See AdvanceNextFullTransactionIdPastXid() for more.
21762172
*/
21772173
Assert(AmStartupProcess()|| !IsUnderPostmaster);
21782174

2179-
xid=XLogRecGetXid(record);
2180-
next_xid=XidFromFullTransactionId(TransamVariables->nextXid);
2181-
epoch=EpochFromFullTransactionId(TransamVariables->nextXid);
2182-
2183-
/*
2184-
* If xid is numerically greater than next_xid, it has to be from the last
2185-
* epoch.
2186-
*/
2187-
if (unlikely(xid>next_xid))
2188-
--epoch;
2189-
2190-
returnFullTransactionIdFromEpochAndXid(epoch,xid);
2175+
returnFullTransactionIdFromAllowableAt(TransamVariables->nextXid,
2176+
XLogRecGetXid(record));
21912177
}
21922178

21932179
#endif

‎src/backend/utils/adt/xid8funcs.c

Lines changed: 24 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -97,15 +97,11 @@ static bool
9797
TransactionIdInRecentPast(FullTransactionIdfxid,TransactionId*extracted_xid)
9898
{
9999
TransactionIdxid=XidFromFullTransactionId(fxid);
100-
uint32now_epoch;
101-
TransactionIdnow_epoch_next_xid;
102100
FullTransactionIdnow_fullxid;
103-
TransactionIdoldest_xid;
104-
FullTransactionIdoldest_fxid;
101+
TransactionIdoldest_clog_xid;
102+
FullTransactionIdoldest_clog_fxid;
105103

106104
now_fullxid=ReadNextFullTransactionId();
107-
now_epoch_next_xid=XidFromFullTransactionId(now_fullxid);
108-
now_epoch=EpochFromFullTransactionId(now_fullxid);
109105

110106
if (extracted_xid!=NULL)
111107
*extracted_xid=xid;
@@ -135,52 +131,19 @@ TransactionIdInRecentPast(FullTransactionId fxid, TransactionId *extracted_xid)
135131

136132
/*
137133
* If fxid is not older than TransamVariables->oldestClogXid, the relevant
138-
* CLOG entry is guaranteed to still exist. Convert
139-
* TransamVariables->oldestClogXid into a FullTransactionId to compare it
140-
* with fxid. Determine the right epoch knowing that oldest_fxid
141-
* shouldn't be more than 2^31 older than now_fullxid.
142-
*/
143-
oldest_xid=TransamVariables->oldestClogXid;
144-
Assert(TransactionIdPrecedesOrEquals(oldest_xid,now_epoch_next_xid));
145-
if (oldest_xid <=now_epoch_next_xid)
146-
{
147-
oldest_fxid=FullTransactionIdFromEpochAndXid(now_epoch,oldest_xid);
148-
}
149-
else
150-
{
151-
Assert(now_epoch>0);
152-
oldest_fxid=FullTransactionIdFromEpochAndXid(now_epoch-1,oldest_xid);
153-
}
154-
return !FullTransactionIdPrecedes(fxid,oldest_fxid);
155-
}
156-
157-
/*
158-
* Convert a TransactionId obtained from a snapshot held by the caller to a
159-
* FullTransactionId. Use next_fxid as a reference FullTransactionId, so that
160-
* we can compute the high order bits. It must have been obtained by the
161-
* caller with ReadNextFullTransactionId() after the snapshot was created.
162-
*/
163-
staticFullTransactionId
164-
widen_snapshot_xid(TransactionIdxid,FullTransactionIdnext_fxid)
165-
{
166-
TransactionIdnext_xid=XidFromFullTransactionId(next_fxid);
167-
uint32epoch=EpochFromFullTransactionId(next_fxid);
168-
169-
/* Special transaction ID. */
170-
if (!TransactionIdIsNormal(xid))
171-
returnFullTransactionIdFromEpochAndXid(0,xid);
172-
173-
/*
174-
* The 64 bit result must be <= next_fxid, since next_fxid hadn't been
175-
* issued yet when the snapshot was created. Every TransactionId in the
176-
* snapshot must therefore be from the same epoch as next_fxid, or the
177-
* epoch before. We know this because next_fxid is never allow to get
178-
* more than one epoch ahead of the TransactionIds in any snapshot.
134+
* CLOG entry is guaranteed to still exist.
135+
*
136+
* TransamVariables->oldestXid governs allowable XIDs. Usually,
137+
* oldestClogXid==oldestXid. It's also possible for oldestClogXid to
138+
* follow oldestXid, in which case oldestXid might advance after our
139+
* ReadNextFullTransactionId() call. If oldestXid has advanced, that
140+
* advancement reinstated the usual oldestClogXid==oldestXid. Whether or
141+
* not that happened, oldestClogXid is allowable relative to now_fullxid.
179142
*/
180-
if (xid>next_xid)
181-
epoch--;
182-
183-
returnFullTransactionIdFromEpochAndXid(epoch,xid);
143+
oldest_clog_xid=TransamVariables->oldestClogXid;
144+
oldest_clog_fxid=
145+
FullTransactionIdFromAllowableAt(now_fullxid,oldest_clog_xid);
146+
return!FullTransactionIdPrecedes(fxid,oldest_clog_fxid);
184147
}
185148

186149
/*
@@ -420,12 +383,18 @@ pg_current_snapshot(PG_FUNCTION_ARGS)
420383
nxip=cur->xcnt;
421384
snap=palloc(PG_SNAPSHOT_SIZE(nxip));
422385

423-
/* fill */
424-
snap->xmin=widen_snapshot_xid(cur->xmin,next_fxid);
425-
snap->xmax=widen_snapshot_xid(cur->xmax,next_fxid);
386+
/*
387+
* Fill. This is the current backend's active snapshot, so MyProc->xmin
388+
* is <= all these XIDs. As long as that remains so, oldestXid can't
389+
* advance past any of these XIDs. Hence, these XIDs remain allowable
390+
* relative to next_fxid.
391+
*/
392+
snap->xmin=FullTransactionIdFromAllowableAt(next_fxid,cur->xmin);
393+
snap->xmax=FullTransactionIdFromAllowableAt(next_fxid,cur->xmax);
426394
snap->nxip=nxip;
427395
for (i=0;i<nxip;i++)
428-
snap->xip[i]=widen_snapshot_xid(cur->xip[i],next_fxid);
396+
snap->xip[i]=
397+
FullTransactionIdFromAllowableAt(next_fxid,cur->xip[i]);
429398

430399
/*
431400
* We want them guaranteed to be in ascending order. This also removes

‎src/include/access/transam.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,49 @@ FullTransactionIdNewer(FullTransactionId a, FullTransactionId b)
370370
returnb;
371371
}
372372

373+
/*
374+
* Compute FullTransactionId for the given TransactionId, assuming xid was
375+
* between [oldestXid, nextXid] at the time when TransamVariables->nextXid was
376+
* nextFullXid. When adding calls, evaluate what prevents xid from preceding
377+
* oldestXid if SetTransactionIdLimit() runs between the collection of xid and
378+
* the collection of nextFullXid.
379+
*/
380+
staticinlineFullTransactionId
381+
FullTransactionIdFromAllowableAt(FullTransactionIdnextFullXid,
382+
TransactionIdxid)
383+
{
384+
uint32epoch;
385+
386+
/* Special transaction ID. */
387+
if (!TransactionIdIsNormal(xid))
388+
returnFullTransactionIdFromEpochAndXid(0,xid);
389+
390+
Assert(TransactionIdPrecedesOrEquals(xid,
391+
XidFromFullTransactionId(nextFullXid)));
392+
393+
/*
394+
* The 64 bit result must be <= nextFullXid, since nextFullXid hadn't been
395+
* issued yet when xid was in the past. The xid must therefore be from
396+
* the epoch of nextFullXid or the epoch before. We know this because we
397+
* must remove (by freezing) an XID before assigning the XID half an epoch
398+
* ahead of it.
399+
*
400+
* The unlikely() branch hint is dubious. It's perfect for the first 2^32
401+
* XIDs of a cluster's life. Right at 2^32 XIDs, misprediction shoots to
402+
* 100%, then improves until perfection returns 2^31 XIDs later. Since
403+
* current callers pass relatively-recent XIDs, expect >90% prediction
404+
* accuracy overall. This favors average latency over tail latency.
405+
*/
406+
epoch=EpochFromFullTransactionId(nextFullXid);
407+
if (unlikely(xid>XidFromFullTransactionId(nextFullXid)))
408+
{
409+
Assert(epoch!=0);
410+
epoch--;
411+
}
412+
413+
returnFullTransactionIdFromEpochAndXid(epoch,xid);
414+
}
415+
373416
#endif/* FRONTEND */
374417

375418
#endif/* TRANSAM_H */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp