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

Commitf6a6c46

Browse files
committed
Advance the stop point for multixact offset creation only at checkpoint.
Commitb69bf30 advanced the stop pointat vacuum time, but this has subsequently been shown to be unsafe as aresult of analysis by myself and Thomas Munro and testing by ThomasMunro. The crux of the problem is that the SLRU deletion logic mayget confused about what to remove if, at exactly the right time duringthe checkpoint process, the head of the SLRU crosses what used to bethe tail.This patch, by me, fixes the problem by advancing the stop point onlyfollowing a checkpoint. This has the additional advantage of makingthe removal logic work during recovery more like the way it works duringnormal running, which is probably good.At least one of the calls to DetermineSafeOldestOffset which this patchremoves was already dead, because MultiXactAdvanceOldest is called onlyduring recovery and DetermineSafeOldestOffset was set up to do nothingduring recovery. That, however, is inconsistent with the principle thatrecovery and normal running should work similarly, and was confusing toboot.Along the way, fix some comments that previous patches in this areaneglected to update. It's not clear to me whether there's anyconcrete basis for the decision to use only half of the multixact IDspace, but it's neither necessary nor sufficient to prevent multixactmember wraparound, so the comments should not say otherwise.
1 parent312747c commitf6a6c46

File tree

1 file changed

+17
-26
lines changed

1 file changed

+17
-26
lines changed

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

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2043,8 +2043,6 @@ TrimMultiXact(void)
20432043
}
20442044

20452045
LWLockRelease(MultiXactMemberControlLock);
2046-
2047-
DetermineSafeOldestOffset(MultiXactState->oldestMultiXactId);
20482046
}
20492047

20502048
/*
@@ -2148,13 +2146,11 @@ SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
21482146
Assert(MultiXactIdIsValid(oldest_datminmxid));
21492147

21502148
/*
2151-
* Since multixacts wrap differently from transaction IDs, this logic is
2152-
* not entirely correct: in some scenarios we could go for longer than 2
2153-
* billion multixacts without seeing any data loss, and in some others we
2154-
* could get in trouble before that if the new pg_multixact/members data
2155-
* stomps on the previous cycle's data. For lack of a better mechanism we
2156-
* use the same logic as for transaction IDs, that is, start taking action
2157-
* halfway around the oldest potentially-existing multixact.
2149+
* We pretend that a wrap will happen halfway through the multixact ID
2150+
* space, but that's not really true, because multixacts wrap differently
2151+
* from transaction IDs. Note that, separately from any concern about
2152+
* multixact IDs wrapping, we must ensure that multixact members do not
2153+
* wrap. Limits for that are set in DetermineSafeOldestOffset, not here.
21582154
*/
21592155
multiWrapLimit=oldest_datminmxid+ (MaxMultiXactId >>1);
21602156
if (multiWrapLimit<FirstMultiXactId)
@@ -2209,8 +2205,6 @@ SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
22092205
curMulti=MultiXactState->nextMXact;
22102206
LWLockRelease(MultiXactGenLock);
22112207

2212-
DetermineSafeOldestOffset(oldest_datminmxid);
2213-
22142208
/* Log the info */
22152209
ereport(DEBUG1,
22162210
(errmsg("MultiXactId wrap limit is %u, limited by database with OID %u",
@@ -2305,8 +2299,6 @@ MultiXactAdvanceOldest(MultiXactId oldestMulti, Oid oldestMultiDB)
23052299
{
23062300
if (MultiXactIdPrecedes(MultiXactState->oldestMultiXactId,oldestMulti))
23072301
SetMultiXactIdLimit(oldestMulti,oldestMultiDB);
2308-
else
2309-
DetermineSafeOldestOffset(oldestMulti);
23102302
}
23112303

23122304
/*
@@ -2484,19 +2476,11 @@ DetermineSafeOldestOffset(MultiXactId oldestMXact)
24842476
MultiXactOffsetoldestOffset;
24852477

24862478
/*
2487-
* Can't do this while initdb'ing or in the startup process while
2488-
* replaying WAL: the segment file to read might have not yet been
2489-
* created, or already been removed.
2490-
*/
2491-
if (IsBootstrapProcessingMode()||InRecovery)
2492-
return;
2493-
2494-
/*
2495-
* Determine the offset of the oldest multixact. Normally, we can read
2496-
* the offset from the multixact itself, but there's an important special
2497-
* case: if there are no multixacts in existence at all, oldestMXact
2498-
* obviously can't point to one. It will instead point to the multixact
2499-
* ID that will be assigned the next time one is needed.
2479+
* We determine the safe upper bound for offsets of new xacts by reading
2480+
* the offset of the oldest multixact, and going back one segment. This
2481+
* way, the sequence of multixact member segments will always have a
2482+
* one-segment hole at a minimum. We start spewing warnings a few
2483+
* complete segments before that.
25002484
*/
25012485
LWLockAcquire(MultiXactGenLock,LW_SHARED);
25022486
if (MultiXactState->nextMXact==oldestMXact)
@@ -2833,6 +2817,13 @@ TruncateMultiXact(void)
28332817
SimpleLruTruncate(MultiXactOffsetCtl,
28342818
MultiXactIdToOffsetPage(oldestMXact));
28352819

2820+
2821+
/*
2822+
* Now, and only now, we can advance the stop point for multixact members.
2823+
* If we did it any sooner, the segments we deleted above might already
2824+
* have been overwritten with new members. That would be bad.
2825+
*/
2826+
DetermineSafeOldestOffset(oldestMXact);
28362827
}
28372828

28382829
/*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp