#define MULTIXACT_MEMBER_LOW_THRESHOLD UINT64CONST(2000000000)
#define MULTIXACT_MEMBER_HIGH_THRESHOLD UINT64CONST(4000000000)
+static inline MultiXactId
+NextMultiXactId(MultiXactId multi)
+{
+ return multi == MaxMultiXactId ? FirstMultiXactId : multi + 1;
+}
+
static inline MultiXactId
PreviousMultiXactId(MultiXactId multi)
{
*/
LWLockAcquire(MultiXactGenLock, LW_SHARED);
- /*
- * We have to beware of the possibility that nextMXact is in the
- * wrapped-around state. We don't fix the counter itself here, but we
- * must be sure to store a valid value in our array entry.
- */
nextMXact = MultiXactState->nextMXact;
- if (nextMXact < FirstMultiXactId)
- nextMXact = FirstMultiXactId;
OldestMemberMXactId[MyProcNumber] = nextMXact;
LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
- /*
- * We have to beware of the possibility that nextMXact is in the
- * wrapped-around state. We don't fix the counter itself here, but we
- * must be sure to store a valid value in our array entry.
- */
oldestMXact = MultiXactState->nextMXact;
- if (oldestMXact < FirstMultiXactId)
- oldestMXact = FirstMultiXactId;
-
for (i = 0; i < MaxOldestSlot; i++)
{
MultiXactId thisoldest = OldestMemberMXactId[i];
mxid = MultiXactState->nextMXact;
LWLockRelease(MultiXactGenLock);
- if (mxid < FirstMultiXactId)
- mxid = FirstMultiXactId;
-
return mxid;
}
*oldest = MultiXactState->oldestMultiXactId;
*next = MultiXactState->nextMXact;
LWLockRelease(MultiXactGenLock);
-
- if (*oldest < FirstMultiXactId)
- *oldest = FirstMultiXactId;
- if (*next < FirstMultiXactId)
- *next = FirstMultiXactId;
}
entryno = MultiXactIdToOffsetEntry(multi);
/* position of the next multixid */
- next = multi + 1;
- if (next < FirstMultiXactId)
- next = FirstMultiXactId;
+ next = NextMultiXactId(multi);
next_pageno = MultiXactIdToOffsetPage(next);
next_entryno = MultiXactIdToOffsetEntry(next);
LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
- /* Handle wraparound of the nextMXact counter */
- if (MultiXactState->nextMXact < FirstMultiXactId)
- MultiXactState->nextMXact = FirstMultiXactId;
-
/* Assign the MXID */
result = MultiXactState->nextMXact;
* request only once per 64K multis generated. This still gives
* plenty of chances before we get into real trouble.
*/
- if (IsUnderPostmaster && (result % 65536) == 0)
+ if (IsUnderPostmaster && ((result % 65536) == 0 || result == FirstMultiXactId))
SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER);
if (!MultiXactIdPrecedes(result, multiWarnLimit))
/* Re-acquire lock and start over */
LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
result = MultiXactState->nextMXact;
- if (result < FirstMultiXactId)
- result = FirstMultiXactId;
}
/*
* Make sure there is room for the next MXID in the file. Assigning this
* MXID sets the next MXID's offset already.
*/
- ExtendMultiXactOffset(result + 1);
+ ExtendMultiXactOffset(NextMultiXactId(result));
/*
* Reserve the members space, similarly to above.
/*
* Advance counters. As in GetNewTransactionId(), this must not happen
* until after file extension has succeeded!
- *
- * We don't care about MultiXactId wraparound here; it will be handled by
- * the next iteration. But note that nextMXact may be InvalidMultiXactId
- * or the first value on a segment-beginning page after this routine
- * exits, so anyone else looking at the variable must be prepared to deal
- * with either case.
*/
- (MultiXactState->nextMXact)++;
-
+ MultiXactState->nextMXact = NextMultiXactId(result);
MultiXactState->nextOffset += nmembers;
LWLockRelease(MultiXactGenLock);
MultiXactId tmpMXact;
/* handle wraparound if needed */
- tmpMXact = multi + 1;
- if (tmpMXact < FirstMultiXactId)
- tmpMXact = FirstMultiXactId;
+ tmpMXact = NextMultiXactId(multi);
prev_pageno = pageno;
LWLock *lock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
LWLockAcquire(lock, LW_EXCLUSIVE);
- if (entryno == 0)
+ if (entryno == 0 || nextMXact == FirstMultiXactId)
slotno = SimpleLruZeroPage(MultiXactOffsetCtl, pageno);
else
slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, nextMXact);
MultiXactSetNextMXact(MultiXactId nextMulti,
MultiXactOffset nextMultiOffset)
{
+ Assert(MultiXactIdIsValid(nextMulti));
debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %" PRIu64,
nextMulti, nextMultiOffset);
+
LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
MultiXactState->nextMXact = nextMulti;
MultiXactState->nextOffset = nextMultiOffset;
MultiXactAdvanceNextMXact(MultiXactId minMulti,
MultiXactOffset minMultiOffset)
{
+ Assert(MultiXactIdIsValid(minMulti));
+
LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
if (MultiXactIdPrecedes(MultiXactState->nextMXact, minMulti))
{
GetOldestMultiXactId(void)
{
MultiXactId oldestMXact;
- MultiXactId nextMXact;
int i;
/*
* OldestVisibleMXactId[] entries, or nextMXact if none are valid.
*/
LWLockAcquire(MultiXactGenLock, LW_SHARED);
-
- /*
- * We have to beware of the possibility that nextMXact is in the
- * wrapped-around state. We don't fix the counter itself here, but we
- * must be sure to use a valid value in our calculation.
- */
- nextMXact = MultiXactState->nextMXact;
- if (nextMXact < FirstMultiXactId)
- nextMXact = FirstMultiXactId;
-
- oldestMXact = nextMXact;
+ oldestMXact = MultiXactState->nextMXact;
for (i = 0; i < MaxOldestSlot; i++)
{
MultiXactId thisoldest;
Assert(!RecoveryInProgress());
Assert(MultiXactState->finishedStartup);
+ Assert(MultiXactIdIsValid(newOldestMulti));
/*
* We can only allow one truncation to happen at once. Otherwise parts of
nextOffset = MultiXactState->nextOffset;
oldestMulti = MultiXactState->oldestMultiXactId;
LWLockRelease(MultiXactGenLock);
- Assert(MultiXactIdIsValid(oldestMulti));
/*
* Make sure to only attempt truncation if there's values to truncate
xlrec->members);
/* Make sure nextMXact/nextOffset are beyond what this record has */
- MultiXactAdvanceNextMXact(xlrec->mid + 1,
+ MultiXactAdvanceNextMXact(NextMultiXactId(xlrec->mid),
xlrec->moff + xlrec->nmembers);
/*