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

Commit 766dcfb

Browse files
committed
Fix off-by-one error in calculating subtrans/multixact truncation point.
If there were no subtransactions (or multixacts) active, we would calculate the oldestxid == next xid. That's correct, but if next XID happens to be on the next pg_subtrans (pg_multixact) page, the page does not exist yet, and SimpleLruTruncate will produce an "apparent wraparound" warning. The warning is harmless in this case, but looks very alarming to users. Backpatch to all supported versions. Patch and analysis by Thomas Munro.
1 parent 46d0a9b commit 766dcfb

File tree

2 files changed

+16
-4
lines changed

2 files changed

+16
-4
lines changed

src/backend/access/transam/multixact.c

+10-3
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@
173173
#define MULTIXACT_MEMBER_DANGER_THRESHOLD \
174174
(MaxMultiXactOffset - MaxMultiXactOffset / 4)
175175

176+
#define PreviousMultiXactId(xid) \
177+
((xid) == FirstMultiXactId ? MaxMultiXactId : (xid) - 1)
176178

177179
/*
178180
* Links to shared-memory data structures for MultiXact control
@@ -3057,10 +3059,15 @@ TruncateMultiXact(void)
30573059

30583060
SlruScanDirectory(MultiXactMemberCtl, SlruScanDirCbRemoveMembers, &range);
30593061

3060-
/* Now we can truncate MultiXactOffset */
3062+
/*
3063+
* Now we can truncate MultiXactOffset. We step back one multixact to
3064+
* avoid passing a cutoff page that hasn't been created yet in the rare
3065+
* case that oldestMXact would be the first item on a page and oldestMXact
3066+
* == nextMXact. In that case, if we didn't subtract one, we'd trigger
3067+
* SimpleLruTruncate's wraparound detection.
3068+
*/
30613069
SimpleLruTruncate(MultiXactOffsetCtl,
3062-
MultiXactIdToOffsetPage(oldestMXact));
3063-
3070+
MultiXactIdToOffsetPage(PreviousMultiXactId(oldestMXact)));
30643071

30653072
/*
30663073
* Now, and only now, we can advance the stop point for multixact members.

src/backend/access/transam/subtrans.c

+6-1
Original file line numberDiff line numberDiff line change
@@ -340,8 +340,13 @@ TruncateSUBTRANS(TransactionId oldestXact)
340340

341341
/*
342342
* The cutoff point is the start of the segment containing oldestXact. We
343-
* pass the *page* containing oldestXact to SimpleLruTruncate.
343+
* pass the *page* containing oldestXact to SimpleLruTruncate. We step
344+
* back one transaction to avoid passing a cutoff page that hasn't been
345+
* created yet in the rare case that oldestXact would be the first item on
346+
* a page and oldestXact == next XID. In that case, if we didn't subtract
347+
* one, we'd trigger SimpleLruTruncate's wraparound detection.
344348
*/
349+
TransactionIdRetreat(oldestXact);
345350
cutoffPage = TransactionIdToPage(oldestXact);
346351

347352
SimpleLruTruncate(SubTransCtl, cutoffPage);

0 commit comments

Comments
 (0)