mirror of
https://github.com/postgres/postgres.git
synced 2025-04-24 10:47:04 +03:00
Even when autovacuum=off, force it for members as we do in other cases.
Thomas Munro, with some adjustments by me.
This commit is contained in:
parent
f6a6c46d7f
commit
04e6d3b877
@ -204,6 +204,7 @@ typedef struct MultiXactStateData
|
|||||||
*/
|
*/
|
||||||
MultiXactId oldestMultiXactId;
|
MultiXactId oldestMultiXactId;
|
||||||
Oid oldestMultiXactDB;
|
Oid oldestMultiXactDB;
|
||||||
|
MultiXactOffset oldestOffset;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is what the previous checkpoint stored as the truncate position.
|
* This is what the previous checkpoint stored as the truncate position.
|
||||||
@ -954,14 +955,17 @@ GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
|
|||||||
* against catastrophic data loss due to multixact wraparound. The basic
|
* against catastrophic data loss due to multixact wraparound. The basic
|
||||||
* rules are:
|
* rules are:
|
||||||
*
|
*
|
||||||
* If we're past multiVacLimit, start trying to force autovacuum cycles.
|
* If we're past multiVacLimit or the safe threshold for member storage space,
|
||||||
|
* start trying to force autovacuum cycles.
|
||||||
* If we're past multiWarnLimit, start issuing warnings.
|
* If we're past multiWarnLimit, start issuing warnings.
|
||||||
* If we're past multiStopLimit, refuse to create new MultiXactIds.
|
* If we're past multiStopLimit, refuse to create new MultiXactIds.
|
||||||
*
|
*
|
||||||
* Note these are pretty much the same protections in GetNewTransactionId.
|
* Note these are pretty much the same protections in GetNewTransactionId.
|
||||||
*----------
|
*----------
|
||||||
*/
|
*/
|
||||||
if (!MultiXactIdPrecedes(result, MultiXactState->multiVacLimit))
|
if (!MultiXactIdPrecedes(result, MultiXactState->multiVacLimit) ||
|
||||||
|
(MultiXactState->nextOffset - MultiXactState->oldestOffset
|
||||||
|
> MULTIXACT_MEMBER_SAFE_THRESHOLD))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* For safety's sake, we release MultiXactGenLock while sending
|
* For safety's sake, we release MultiXactGenLock while sending
|
||||||
@ -2142,6 +2146,8 @@ SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
|
|||||||
MultiXactId multiStopLimit;
|
MultiXactId multiStopLimit;
|
||||||
MultiXactId multiWrapLimit;
|
MultiXactId multiWrapLimit;
|
||||||
MultiXactId curMulti;
|
MultiXactId curMulti;
|
||||||
|
MultiXactOffset oldestOffset;
|
||||||
|
MultiXactOffset nextOffset;
|
||||||
|
|
||||||
Assert(MultiXactIdIsValid(oldest_datminmxid));
|
Assert(MultiXactIdIsValid(oldest_datminmxid));
|
||||||
|
|
||||||
@ -2194,6 +2200,35 @@ SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
|
|||||||
if (multiVacLimit < FirstMultiXactId)
|
if (multiVacLimit < FirstMultiXactId)
|
||||||
multiVacLimit += FirstMultiXactId;
|
multiVacLimit += FirstMultiXactId;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine the offset of the oldest multixact that might still be
|
||||||
|
* referenced. Normally, we can read the offset from the multixact itself,
|
||||||
|
* but there's an important special case: if there are no multixacts in
|
||||||
|
* existence at all, oldest_datminmxid obviously can't point to one. It
|
||||||
|
* will instead point to the multixact ID that will be assigned the next
|
||||||
|
* time one is needed.
|
||||||
|
*
|
||||||
|
* NB: oldest_dataminmxid is the oldest multixact that might still be
|
||||||
|
* referenced from a table, unlike in DetermineSafeOldestOffset, where we
|
||||||
|
* do this same computation based on the oldest value that might still
|
||||||
|
* exist in the SLRU. This is because here we're trying to compute a
|
||||||
|
* threshold for activating autovacuum, which can only remove references
|
||||||
|
* to multixacts, whereas there we are computing a threshold for creating
|
||||||
|
* new multixacts, which requires the old ones to have first been
|
||||||
|
* truncated away by a checkpoint.
|
||||||
|
*/
|
||||||
|
LWLockAcquire(MultiXactGenLock, LW_SHARED);
|
||||||
|
if (MultiXactState->nextMXact == oldest_datminmxid)
|
||||||
|
{
|
||||||
|
oldestOffset = MultiXactState->nextOffset;
|
||||||
|
LWLockRelease(MultiXactGenLock);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LWLockRelease(MultiXactGenLock);
|
||||||
|
oldestOffset = find_multixact_start(oldest_datminmxid);
|
||||||
|
}
|
||||||
|
|
||||||
/* Grab lock for just long enough to set the new limit values */
|
/* Grab lock for just long enough to set the new limit values */
|
||||||
LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
|
LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
|
||||||
MultiXactState->oldestMultiXactId = oldest_datminmxid;
|
MultiXactState->oldestMultiXactId = oldest_datminmxid;
|
||||||
@ -2202,7 +2237,9 @@ SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
|
|||||||
MultiXactState->multiWarnLimit = multiWarnLimit;
|
MultiXactState->multiWarnLimit = multiWarnLimit;
|
||||||
MultiXactState->multiStopLimit = multiStopLimit;
|
MultiXactState->multiStopLimit = multiStopLimit;
|
||||||
MultiXactState->multiWrapLimit = multiWrapLimit;
|
MultiXactState->multiWrapLimit = multiWrapLimit;
|
||||||
|
MultiXactState->oldestOffset = oldestOffset;
|
||||||
curMulti = MultiXactState->nextMXact;
|
curMulti = MultiXactState->nextMXact;
|
||||||
|
nextOffset = MultiXactState->nextOffset;
|
||||||
LWLockRelease(MultiXactGenLock);
|
LWLockRelease(MultiXactGenLock);
|
||||||
|
|
||||||
/* Log the info */
|
/* Log the info */
|
||||||
@ -2217,7 +2254,8 @@ SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
|
|||||||
* database, it'll call here, and we'll signal the postmaster to start
|
* database, it'll call here, and we'll signal the postmaster to start
|
||||||
* another iteration immediately if there are still any old databases.
|
* another iteration immediately if there are still any old databases.
|
||||||
*/
|
*/
|
||||||
if (MultiXactIdPrecedes(multiVacLimit, curMulti) &&
|
if ((MultiXactIdPrecedes(multiVacLimit, curMulti) ||
|
||||||
|
(nextOffset - oldestOffset > MULTIXACT_MEMBER_SAFE_THRESHOLD)) &&
|
||||||
IsUnderPostmaster && !InRecovery)
|
IsUnderPostmaster && !InRecovery)
|
||||||
SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
|
SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
|
||||||
|
|
||||||
@ -2476,11 +2514,16 @@ DetermineSafeOldestOffset(MultiXactId oldestMXact)
|
|||||||
MultiXactOffset oldestOffset;
|
MultiXactOffset oldestOffset;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We determine the safe upper bound for offsets of new xacts by reading
|
* Determine the offset of the oldest multixact. Normally, we can read
|
||||||
* the offset of the oldest multixact, and going back one segment. This
|
* the offset from the multixact itself, but there's an important special
|
||||||
* way, the sequence of multixact member segments will always have a
|
* case: if there are no multixacts in existence at all, oldestMXact
|
||||||
* one-segment hole at a minimum. We start spewing warnings a few
|
* obviously can't point to one. It will instead point to the multixact
|
||||||
* complete segments before that.
|
* ID that will be assigned the next time one is needed.
|
||||||
|
*
|
||||||
|
* NB: oldestMXact should be the oldest multixact that still exists in
|
||||||
|
* the SLRU, unlike in SetMultiXactIdLimit, where we do this same
|
||||||
|
* computation based on the oldest value that might be referenced in a
|
||||||
|
* table.
|
||||||
*/
|
*/
|
||||||
LWLockAcquire(MultiXactGenLock, LW_SHARED);
|
LWLockAcquire(MultiXactGenLock, LW_SHARED);
|
||||||
if (MultiXactState->nextMXact == oldestMXact)
|
if (MultiXactState->nextMXact == oldestMXact)
|
||||||
@ -2594,9 +2637,9 @@ ReadMultiXactCounts(uint32 *multixacts, MultiXactOffset *members)
|
|||||||
nextOffset = MultiXactState->nextOffset;
|
nextOffset = MultiXactState->nextOffset;
|
||||||
oldestMultiXactId = MultiXactState->oldestMultiXactId;
|
oldestMultiXactId = MultiXactState->oldestMultiXactId;
|
||||||
nextMultiXactId = MultiXactState->nextMXact;
|
nextMultiXactId = MultiXactState->nextMXact;
|
||||||
|
oldestOffset = MultiXactState->oldestOffset;
|
||||||
LWLockRelease(MultiXactGenLock);
|
LWLockRelease(MultiXactGenLock);
|
||||||
|
|
||||||
oldestOffset = find_multixact_start(oldestMultiXactId);
|
|
||||||
*members = nextOffset - oldestOffset;
|
*members = nextOffset - oldestOffset;
|
||||||
*multixacts = nextMultiXactId - oldestMultiXactId;
|
*multixacts = nextMultiXactId - oldestMultiXactId;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user