|
|
|
@ -220,14 +220,6 @@ typedef struct MultiXactStateData
|
|
|
|
|
MultiXactOffset oldestOffset;
|
|
|
|
|
bool oldestOffsetKnown;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* True if a multixact truncation WAL record was replayed since the last
|
|
|
|
|
* checkpoint. This is used to trigger 'legacy truncations', i.e. truncate
|
|
|
|
|
* by looking at the data directory during WAL replay, when the primary is
|
|
|
|
|
* too old to generate truncation records.
|
|
|
|
|
*/
|
|
|
|
|
bool sawTruncationInCkptCycle;
|
|
|
|
|
|
|
|
|
|
/* support for anti-wraparound measures */
|
|
|
|
|
MultiXactId multiVacLimit;
|
|
|
|
|
MultiXactId multiWarnLimit;
|
|
|
|
@ -2381,28 +2373,7 @@ MultiXactAdvanceOldest(MultiXactId oldestMulti, Oid oldestMultiDB)
|
|
|
|
|
Assert(InRecovery);
|
|
|
|
|
|
|
|
|
|
if (MultiXactIdPrecedes(MultiXactState->oldestMultiXactId, oldestMulti))
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* If there has been a truncation on the master, detected by seeing a
|
|
|
|
|
* moving oldestMulti, without a corresponding truncation record, we
|
|
|
|
|
* know that the primary is still running an older version of postgres
|
|
|
|
|
* that doesn't yet log multixact truncations. So perform the
|
|
|
|
|
* truncation ourselves.
|
|
|
|
|
*/
|
|
|
|
|
if (!MultiXactState->sawTruncationInCkptCycle)
|
|
|
|
|
{
|
|
|
|
|
ereport(LOG,
|
|
|
|
|
(errmsg("performing legacy multixact truncation"),
|
|
|
|
|
errdetail("Legacy truncations are sometimes performed when replaying WAL from an older primary."),
|
|
|
|
|
errhint("Upgrade the primary, it is susceptible to data corruption.")));
|
|
|
|
|
TruncateMultiXact(oldestMulti, oldestMultiDB, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetMultiXactIdLimit(oldestMulti, oldestMultiDB);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* only looked at in the startup process, no lock necessary */
|
|
|
|
|
MultiXactState->sawTruncationInCkptCycle = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -2747,8 +2718,7 @@ find_multixact_start(MultiXactId multi, MultiXactOffset *result)
|
|
|
|
|
int slotno;
|
|
|
|
|
MultiXactOffset *offptr;
|
|
|
|
|
|
|
|
|
|
/* XXX: Remove || AmStartupProcess() after WAL page magic bump */
|
|
|
|
|
Assert(MultiXactState->finishedStartup || AmStartupProcess());
|
|
|
|
|
Assert(MultiXactState->finishedStartup);
|
|
|
|
|
|
|
|
|
|
pageno = MultiXactIdToOffsetPage(multi);
|
|
|
|
|
entryno = MultiXactIdToOffsetEntry(multi);
|
|
|
|
@ -2946,18 +2916,15 @@ PerformOffsetsTruncation(MultiXactId oldestMulti, MultiXactId newOldestMulti)
|
|
|
|
|
* Remove all MultiXactOffset and MultiXactMember segments before the oldest
|
|
|
|
|
* ones still of interest.
|
|
|
|
|
*
|
|
|
|
|
* On a primary this is called as part of vacuum (via
|
|
|
|
|
* vac_truncate_clog()). During recovery truncation is normally done by
|
|
|
|
|
* replaying truncation WAL records instead of this routine; the exception is
|
|
|
|
|
* when replaying records from an older primary that doesn't yet generate
|
|
|
|
|
* truncation WAL records. In that case truncation is triggered by
|
|
|
|
|
* MultiXactAdvanceOldest().
|
|
|
|
|
* This is only called on a primary as part of vacuum (via
|
|
|
|
|
* vac_truncate_clog()). During recovery truncation is done by replaying
|
|
|
|
|
* truncation WAL records logged here.
|
|
|
|
|
*
|
|
|
|
|
* newOldestMulti is the oldest currently required multixact, newOldestMultiDB
|
|
|
|
|
* is one of the databases preventing newOldestMulti from increasing.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB, bool in_recovery)
|
|
|
|
|
TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB)
|
|
|
|
|
{
|
|
|
|
|
MultiXactId oldestMulti;
|
|
|
|
|
MultiXactId nextMulti;
|
|
|
|
@ -2967,13 +2934,8 @@ TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB, bool in_reco
|
|
|
|
|
mxtruncinfo trunc;
|
|
|
|
|
MultiXactId earliest;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Need to allow being called in recovery for backwards compatibility,
|
|
|
|
|
* when an updated standby replays WAL generated by a non-updated primary.
|
|
|
|
|
*/
|
|
|
|
|
Assert(in_recovery || !RecoveryInProgress());
|
|
|
|
|
Assert(!in_recovery || AmStartupProcess());
|
|
|
|
|
Assert(in_recovery || MultiXactState->finishedStartup);
|
|
|
|
|
Assert(!RecoveryInProgress());
|
|
|
|
|
Assert(MultiXactState->finishedStartup);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We can only allow one truncation to happen at once. Otherwise parts of
|
|
|
|
@ -3086,19 +3048,12 @@ TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB, bool in_reco
|
|
|
|
|
* Prevent checkpoints from being scheduled concurrently. This is critical
|
|
|
|
|
* because otherwise a truncation record might not be replayed after a
|
|
|
|
|
* crash/basebackup, even though the state of the data directory would
|
|
|
|
|
* require it. It's not possible (startup process doesn't have a PGXACT
|
|
|
|
|
* entry), and not needed, to do this during recovery, when performing an
|
|
|
|
|
* old-style truncation, though. There the entire scheduling depends on
|
|
|
|
|
* the replayed WAL records which be the same after a possible crash.
|
|
|
|
|
* require it.
|
|
|
|
|
*/
|
|
|
|
|
if (!in_recovery)
|
|
|
|
|
{
|
|
|
|
|
Assert(!MyPgXact->delayChkpt);
|
|
|
|
|
MyPgXact->delayChkpt = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* WAL log truncation */
|
|
|
|
|
if (!in_recovery)
|
|
|
|
|
WriteMTruncateXlogRec(newOldestMultiDB,
|
|
|
|
|
oldestMulti, newOldestMulti,
|
|
|
|
|
oldestOffset, newOldestOffset);
|
|
|
|
@ -3122,7 +3077,6 @@ TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB, bool in_reco
|
|
|
|
|
/* Then offsets */
|
|
|
|
|
PerformOffsetsTruncation(oldestMulti, newOldestMulti);
|
|
|
|
|
|
|
|
|
|
if (!in_recovery)
|
|
|
|
|
MyPgXact->delayChkpt = false;
|
|
|
|
|
|
|
|
|
|
END_CRIT_SECTION();
|
|
|
|
@ -3371,9 +3325,6 @@ multixact_redo(XLogReaderState *record)
|
|
|
|
|
PerformOffsetsTruncation(xlrec.startTruncOff, xlrec.endTruncOff);
|
|
|
|
|
|
|
|
|
|
LWLockRelease(MultiXactTruncationLock);
|
|
|
|
|
|
|
|
|
|
/* only looked at in the startup process, no lock necessary */
|
|
|
|
|
MultiXactState->sawTruncationInCkptCycle = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
elog(PANIC, "multixact_redo: unknown op code %u", info);
|
|
|
|
|