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

Commit 543fbec

Browse files
committed
Even when autovacuum=off, force it for members as we do in other cases.
Thomas Munro, with some adjustments by me.
1 parent 5bbac7e commit 543fbec

File tree

1 file changed

+52
-9
lines changed

1 file changed

+52
-9
lines changed

src/backend/access/transam/multixact.c

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ typedef struct MultiXactStateData
202202
*/
203203
MultiXactId oldestMultiXactId;
204204
Oid oldestMultiXactDB;
205+
MultiXactOffset oldestOffset;
205206

206207
/*
207208
* This is what the previous checkpoint stored as the truncate position.
@@ -959,14 +960,17 @@ GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
959960
* against catastrophic data loss due to multixact wraparound. The basic
960961
* rules are:
961962
*
962-
* If we're past multiVacLimit, start trying to force autovacuum cycles.
963+
* If we're past multiVacLimit or the safe threshold for member storage space,
964+
* start trying to force autovacuum cycles.
963965
* If we're past multiWarnLimit, start issuing warnings.
964966
* If we're past multiStopLimit, refuse to create new MultiXactIds.
965967
*
966968
* Note these are pretty much the same protections in GetNewTransactionId.
967969
*----------
968970
*/
969-
if (!MultiXactIdPrecedes(result, MultiXactState->multiVacLimit))
971+
if (!MultiXactIdPrecedes(result, MultiXactState->multiVacLimit) ||
972+
(MultiXactState->nextOffset - MultiXactState->oldestOffset
973+
> MULTIXACT_MEMBER_SAFE_THRESHOLD))
970974
{
971975
/*
972976
* For safety's sake, we release MultiXactGenLock while sending
@@ -2161,6 +2165,8 @@ SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
21612165
MultiXactId multiStopLimit;
21622166
MultiXactId multiWrapLimit;
21632167
MultiXactId curMulti;
2168+
MultiXactOffset oldestOffset;
2169+
MultiXactOffset nextOffset;
21642170

21652171
Assert(MultiXactIdIsValid(oldest_datminmxid));
21662172

@@ -2213,6 +2219,35 @@ SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
22132219
if (multiVacLimit < FirstMultiXactId)
22142220
multiVacLimit += FirstMultiXactId;
22152221

2222+
/*
2223+
* Determine the offset of the oldest multixact that might still be
2224+
* referenced. Normally, we can read the offset from the multixact itself,
2225+
* but there's an important special case: if there are no multixacts in
2226+
* existence at all, oldest_datminmxid obviously can't point to one. It
2227+
* will instead point to the multixact ID that will be assigned the next
2228+
* time one is needed.
2229+
*
2230+
* NB: oldest_dataminmxid is the oldest multixact that might still be
2231+
* referenced from a table, unlike in DetermineSafeOldestOffset, where we
2232+
* do this same computation based on the oldest value that might still
2233+
* exist in the SLRU. This is because here we're trying to compute a
2234+
* threshold for activating autovacuum, which can only remove references
2235+
* to multixacts, whereas there we are computing a threshold for creating
2236+
* new multixacts, which requires the old ones to have first been
2237+
* truncated away by a checkpoint.
2238+
*/
2239+
LWLockAcquire(MultiXactGenLock, LW_SHARED);
2240+
if (MultiXactState->nextMXact == oldest_datminmxid)
2241+
{
2242+
oldestOffset = MultiXactState->nextOffset;
2243+
LWLockRelease(MultiXactGenLock);
2244+
}
2245+
else
2246+
{
2247+
LWLockRelease(MultiXactGenLock);
2248+
oldestOffset = find_multixact_start(oldest_datminmxid);
2249+
}
2250+
22162251
/* Grab lock for just long enough to set the new limit values */
22172252
LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
22182253
MultiXactState->oldestMultiXactId = oldest_datminmxid;
@@ -2221,7 +2256,9 @@ SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
22212256
MultiXactState->multiWarnLimit = multiWarnLimit;
22222257
MultiXactState->multiStopLimit = multiStopLimit;
22232258
MultiXactState->multiWrapLimit = multiWrapLimit;
2259+
MultiXactState->oldestOffset = oldestOffset;
22242260
curMulti = MultiXactState->nextMXact;
2261+
nextOffset = MultiXactState->nextOffset;
22252262
LWLockRelease(MultiXactGenLock);
22262263

22272264
/* Log the info */
@@ -2236,7 +2273,8 @@ SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
22362273
* database, it'll call here, and we'll signal the postmaster to start
22372274
* another iteration immediately if there are still any old databases.
22382275
*/
2239-
if (MultiXactIdPrecedes(multiVacLimit, curMulti) &&
2276+
if ((MultiXactIdPrecedes(multiVacLimit, curMulti) ||
2277+
(nextOffset - oldestOffset > MULTIXACT_MEMBER_SAFE_THRESHOLD)) &&
22402278
IsUnderPostmaster && !InRecovery)
22412279
SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
22422280

@@ -2495,11 +2533,16 @@ DetermineSafeOldestOffset(MultiXactId oldestMXact)
24952533
MultiXactOffset oldestOffset;
24962534

24972535
/*
2498-
* We determine the safe upper bound for offsets of new xacts by reading
2499-
* the offset of the oldest multixact, and going back one segment. This
2500-
* way, the sequence of multixact member segments will always have a
2501-
* one-segment hole at a minimum. We start spewing warnings a few
2502-
* complete segments before that.
2536+
* Determine the offset of the oldest multixact. Normally, we can read
2537+
* the offset from the multixact itself, but there's an important special
2538+
* case: if there are no multixacts in existence at all, oldestMXact
2539+
* obviously can't point to one. It will instead point to the multixact
2540+
* ID that will be assigned the next time one is needed.
2541+
*
2542+
* NB: oldestMXact should be the oldest multixact that still exists in
2543+
* the SLRU, unlike in SetMultiXactIdLimit, where we do this same
2544+
* computation based on the oldest value that might be referenced in a
2545+
* table.
25032546
*/
25042547
LWLockAcquire(MultiXactGenLock, LW_SHARED);
25052548
if (MultiXactState->nextMXact == oldestMXact)
@@ -2613,9 +2656,9 @@ ReadMultiXactCounts(uint32 *multixacts, MultiXactOffset *members)
26132656
nextOffset = MultiXactState->nextOffset;
26142657
oldestMultiXactId = MultiXactState->oldestMultiXactId;
26152658
nextMultiXactId = MultiXactState->nextMXact;
2659+
oldestOffset = MultiXactState->oldestOffset;
26162660
LWLockRelease(MultiXactGenLock);
26172661

2618-
oldestOffset = find_multixact_start(oldestMultiXactId);
26192662
*members = nextOffset - oldestOffset;
26202663
*multixacts = nextMultiXactId - oldestMultiXactId;
26212664
}

0 commit comments

Comments
 (0)