diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c index 1424cab..ddedade 100644 --- a/src/backend/access/transam/multixact.c +++ b/src/backend/access/transam/multixact.c @@ -204,6 +204,7 @@ typedef struct MultiXactStateData */ MultiXactId oldestMultiXactId; Oid oldestMultiXactDB; + MultiXactOffset oldestOffset; /* * This is what the previous checkpoint stored as the truncate position. @@ -954,14 +955,16 @@ GetNewMultiXactId(int nmembers, MultiXactOffset *offset) * against catastrophic data loss due to multixact wraparound. The basic * 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 multiStopLimit, refuse to create new MultiXactIds. * * 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 @@ -2482,6 +2485,7 @@ static void DetermineSafeOldestOffset(MultiXactId oldestMXact) { MultiXactOffset oldestOffset; + MultiXactOffset startOfOldestSegment; /* * Can't do this while initdb'ing or in the startup process while @@ -2505,8 +2509,9 @@ DetermineSafeOldestOffset(MultiXactId oldestMXact) LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE); /* always leave one segment before the wraparound point */ - MultiXactState->offsetStopLimit = oldestOffset - + MultiXactState->offsetStopLimit = startOfOldestSegment - (MULTIXACT_MEMBERS_PER_PAGE * SLRU_PAGES_PER_SEGMENT); + MultiXactState->oldestOffset = oldestOffset; LWLockRelease(MultiXactGenLock); } @@ -2599,9 +2604,9 @@ ReadMultiXactCounts(uint32 *multixacts, MultiXactOffset *members) nextOffset = MultiXactState->nextOffset; oldestMultiXactId = MultiXactState->oldestMultiXactId; nextMultiXactId = MultiXactState->nextMXact; + oldestOffset = MultiXactState->oldestOffset; LWLockRelease(MultiXactGenLock); - oldestOffset = find_multixact_start(oldestMultiXactId); *members = nextOffset - oldestOffset; *multixacts = nextMultiXactId - oldestMultiXactId; }