mirror of
https://github.com/postgres/postgres.git
synced 2026-01-26 09:41:40 +03:00
Remove some unnecessary code from multixact truncation
With 64-bit multixact offsets, PerformMembersTruncation() doesn't need the starting offset anymore. The 'oldestOffset' value that TruncateMultiXact() calculates is no longer used for anything. Remove it, and the code to calculate it. 'oldestOffset' was included in the WAL record as 'startTruncMemb', which sounds nice if you e.g. look at the WAL with pg_waldump, but it was also confusing because we didn't actually use the value for determining what to truncate. Replaying the WAL would remove all segments older than 'endTruncMemb', regardless of 'startTruncMemb'. The 'startTruncOff' stored in the WAL record was similarly unnecessary even before 64-bit multixid offsets, it was stored just for the sake of symmetry with 'startTruncMemb'. Remove both from the WAL record, and rename the remaining 'endTruncOff' to 'oldestMulti' and 'endTruncMemb' to 'oldestOffset', for consistency with the variable names used for them in other places. Reviewed-by: Andrey Borodin <x4mmm@yandex-team.ru> Discussion: https://www.postgresql.org/message-id/000301b2-5b81-4938-bdac-90f6eb660843@iki.fi
This commit is contained in:
@@ -74,9 +74,8 @@ multixact_desc(StringInfo buf, XLogReaderState *record)
|
||||
{
|
||||
xl_multixact_truncate *xlrec = (xl_multixact_truncate *) rec;
|
||||
|
||||
appendStringInfo(buf, "offsets [%u, %u), members [%" PRIu64 ", %" PRIu64 ")",
|
||||
xlrec->startTruncOff, xlrec->endTruncOff,
|
||||
xlrec->startTruncMemb, xlrec->endTruncMemb);
|
||||
appendStringInfo(buf, "oldestMulti %u, oldestOffset %" PRIu64,
|
||||
xlrec->oldestMulti, xlrec->oldestOffset);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -282,9 +282,7 @@ static void ExtendMultiXactMember(MultiXactOffset offset, int nmembers);
|
||||
static void SetOldestOffset(void);
|
||||
static bool find_multixact_start(MultiXactId multi, MultiXactOffset *result);
|
||||
static void WriteMTruncateXlogRec(Oid oldestMultiDB,
|
||||
MultiXactId startTruncOff,
|
||||
MultiXactId endTruncOff,
|
||||
MultiXactOffset startTruncMemb,
|
||||
MultiXactOffset endTruncMemb);
|
||||
|
||||
|
||||
@@ -2558,45 +2556,22 @@ MultiXactMemberFreezeThreshold(void)
|
||||
return Min(result, autovacuum_multixact_freeze_max_age);
|
||||
}
|
||||
|
||||
typedef struct mxtruncinfo
|
||||
{
|
||||
int64 earliestExistingPage;
|
||||
} mxtruncinfo;
|
||||
|
||||
/*
|
||||
* SlruScanDirectory callback
|
||||
* This callback determines the earliest existing page number.
|
||||
*/
|
||||
static bool
|
||||
SlruScanDirCbFindEarliest(SlruCtl ctl, char *filename, int64 segpage, void *data)
|
||||
{
|
||||
mxtruncinfo *trunc = (mxtruncinfo *) data;
|
||||
|
||||
if (trunc->earliestExistingPage == -1 ||
|
||||
ctl->PagePrecedes(segpage, trunc->earliestExistingPage))
|
||||
{
|
||||
trunc->earliestExistingPage = segpage;
|
||||
}
|
||||
|
||||
return false; /* keep going */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Delete members segments [oldest, newOldest)
|
||||
* Delete members segments older than newOldestOffset
|
||||
*/
|
||||
static void
|
||||
PerformMembersTruncation(MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
|
||||
PerformMembersTruncation(MultiXactOffset newOldestOffset)
|
||||
{
|
||||
SimpleLruTruncate(MultiXactMemberCtl,
|
||||
MXOffsetToMemberPage(newOldestOffset));
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete offsets segments [oldest, newOldest)
|
||||
* Delete offsets segments older than newOldestMulti
|
||||
*/
|
||||
static void
|
||||
PerformOffsetsTruncation(MultiXactId oldestMulti, MultiXactId newOldestMulti)
|
||||
PerformOffsetsTruncation(MultiXactId newOldestMulti)
|
||||
{
|
||||
/*
|
||||
* We step back one multixact to avoid passing a cutoff page that hasn't
|
||||
@@ -2626,10 +2601,7 @@ TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB)
|
||||
MultiXactId oldestMulti;
|
||||
MultiXactId nextMulti;
|
||||
MultiXactOffset newOldestOffset;
|
||||
MultiXactOffset oldestOffset;
|
||||
MultiXactOffset nextOffset;
|
||||
mxtruncinfo trunc;
|
||||
MultiXactId earliest;
|
||||
|
||||
Assert(!RecoveryInProgress());
|
||||
Assert(MultiXactState->finishedStartup);
|
||||
@@ -2661,61 +2633,8 @@ TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB)
|
||||
}
|
||||
|
||||
/*
|
||||
* Note we can't just plow ahead with the truncation; it's possible that
|
||||
* there are no segments to truncate, which is a problem because we are
|
||||
* going to attempt to read the offsets page to determine where to
|
||||
* truncate the members SLRU. So we first scan the directory to determine
|
||||
* the earliest offsets page number that we can read without error.
|
||||
*
|
||||
* When nextMXact is less than one segment away from multiWrapLimit,
|
||||
* SlruScanDirCbFindEarliest can find some early segment other than the
|
||||
* actual earliest. (MultiXactOffsetPagePrecedes(EARLIEST, LATEST)
|
||||
* returns false, because not all pairs of entries have the same answer.)
|
||||
* That can also arise when an earlier truncation attempt failed unlink()
|
||||
* or returned early from this function. The only consequence is
|
||||
* returning early, which wastes space that we could have liberated.
|
||||
*
|
||||
* NB: It's also possible that the page that oldestMulti is on has already
|
||||
* been truncated away, and we crashed before updating oldestMulti.
|
||||
*/
|
||||
trunc.earliestExistingPage = -1;
|
||||
SlruScanDirectory(MultiXactOffsetCtl, SlruScanDirCbFindEarliest, &trunc);
|
||||
earliest = trunc.earliestExistingPage * MULTIXACT_OFFSETS_PER_PAGE;
|
||||
if (earliest < FirstMultiXactId)
|
||||
earliest = FirstMultiXactId;
|
||||
|
||||
/* If there's nothing to remove, we can bail out early. */
|
||||
if (MultiXactIdPrecedes(oldestMulti, earliest))
|
||||
{
|
||||
LWLockRelease(MultiXactTruncationLock);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* First, compute the safe truncation point for MultiXactMember. This is
|
||||
* the starting offset of the oldest multixact.
|
||||
*
|
||||
* Hopefully, find_multixact_start will always work here, because we've
|
||||
* already checked that it doesn't precede the earliest MultiXact on disk.
|
||||
* But if it fails, don't truncate anything, and log a message.
|
||||
*/
|
||||
if (oldestMulti == nextMulti)
|
||||
{
|
||||
/* there are NO MultiXacts */
|
||||
oldestOffset = nextOffset;
|
||||
}
|
||||
else if (!find_multixact_start(oldestMulti, &oldestOffset))
|
||||
{
|
||||
ereport(LOG,
|
||||
(errmsg("oldest MultiXact %u not found, earliest MultiXact %u, skipping truncation",
|
||||
oldestMulti, earliest)));
|
||||
LWLockRelease(MultiXactTruncationLock);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Secondly compute up to where to truncate. Lookup the corresponding
|
||||
* member offset for newOldestMulti for that.
|
||||
* Compute up to where to truncate MultiXactMember. Lookup the
|
||||
* corresponding member offset for newOldestMulti for that.
|
||||
*/
|
||||
if (newOldestMulti == nextMulti)
|
||||
{
|
||||
@@ -2732,13 +2651,11 @@ TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB)
|
||||
}
|
||||
|
||||
elog(DEBUG1, "performing multixact truncation: "
|
||||
"offsets [%u, %u), offsets segments [%" PRIx64 ", %" PRIx64 "), "
|
||||
"members [%" PRIu64 ", %" PRIu64 "), members segments [%" PRIx64 ", %" PRIx64 ")",
|
||||
oldestMulti, newOldestMulti,
|
||||
MultiXactIdToOffsetSegment(oldestMulti),
|
||||
"oldestMulti %u (offsets segment %" PRIx64 "), "
|
||||
"oldestOffset %" PRIu64 " (members segment %" PRIx64 ")",
|
||||
newOldestMulti,
|
||||
MultiXactIdToOffsetSegment(newOldestMulti),
|
||||
oldestOffset, newOldestOffset,
|
||||
MXOffsetToMemberSegment(oldestOffset),
|
||||
newOldestOffset,
|
||||
MXOffsetToMemberSegment(newOldestOffset));
|
||||
|
||||
/*
|
||||
@@ -2759,9 +2676,7 @@ TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB)
|
||||
MyProc->delayChkptFlags |= DELAY_CHKPT_START;
|
||||
|
||||
/* WAL log truncation */
|
||||
WriteMTruncateXlogRec(newOldestMultiDB,
|
||||
oldestMulti, newOldestMulti,
|
||||
oldestOffset, newOldestOffset);
|
||||
WriteMTruncateXlogRec(newOldestMultiDB, newOldestMulti, newOldestOffset);
|
||||
|
||||
/*
|
||||
* Update in-memory limits before performing the truncation, while inside
|
||||
@@ -2778,10 +2693,10 @@ TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB)
|
||||
LWLockRelease(MultiXactGenLock);
|
||||
|
||||
/* First truncate members */
|
||||
PerformMembersTruncation(oldestOffset, newOldestOffset);
|
||||
PerformMembersTruncation(newOldestOffset);
|
||||
|
||||
/* Then offsets */
|
||||
PerformOffsetsTruncation(oldestMulti, newOldestMulti);
|
||||
PerformOffsetsTruncation(newOldestMulti);
|
||||
|
||||
MyProc->delayChkptFlags &= ~DELAY_CHKPT_START;
|
||||
|
||||
@@ -2860,19 +2775,15 @@ MultiXactIdPrecedesOrEquals(MultiXactId multi1, MultiXactId multi2)
|
||||
*/
|
||||
static void
|
||||
WriteMTruncateXlogRec(Oid oldestMultiDB,
|
||||
MultiXactId startTruncOff, MultiXactId endTruncOff,
|
||||
MultiXactOffset startTruncMemb, MultiXactOffset endTruncMemb)
|
||||
MultiXactId oldestMulti,
|
||||
MultiXactOffset oldestOffset)
|
||||
{
|
||||
XLogRecPtr recptr;
|
||||
xl_multixact_truncate xlrec;
|
||||
|
||||
xlrec.oldestMultiDB = oldestMultiDB;
|
||||
|
||||
xlrec.startTruncOff = startTruncOff;
|
||||
xlrec.endTruncOff = endTruncOff;
|
||||
|
||||
xlrec.startTruncMemb = startTruncMemb;
|
||||
xlrec.endTruncMemb = endTruncMemb;
|
||||
xlrec.oldestMulti = oldestMulti;
|
||||
xlrec.oldestOffset = oldestOffset;
|
||||
|
||||
XLogBeginInsert();
|
||||
XLogRegisterData(&xlrec, SizeOfMultiXactTruncate);
|
||||
@@ -2943,14 +2854,12 @@ multixact_redo(XLogReaderState *record)
|
||||
SizeOfMultiXactTruncate);
|
||||
|
||||
elog(DEBUG1, "replaying multixact truncation: "
|
||||
"offsets [%u, %u), offsets segments [%" PRIx64 ", %" PRIx64 "), "
|
||||
"members [%" PRIu64 ", %" PRIu64 "), members segments [%" PRIx64 ", %" PRIx64 ")",
|
||||
xlrec.startTruncOff, xlrec.endTruncOff,
|
||||
MultiXactIdToOffsetSegment(xlrec.startTruncOff),
|
||||
MultiXactIdToOffsetSegment(xlrec.endTruncOff),
|
||||
xlrec.startTruncMemb, xlrec.endTruncMemb,
|
||||
MXOffsetToMemberSegment(xlrec.startTruncMemb),
|
||||
MXOffsetToMemberSegment(xlrec.endTruncMemb));
|
||||
"oldestMulti %u (offsets segment %" PRIx64 "), "
|
||||
"oldestOffset %" PRIu64 " (members segment %" PRIx64 ")",
|
||||
xlrec.oldestMulti,
|
||||
MultiXactIdToOffsetSegment(xlrec.oldestMulti),
|
||||
xlrec.oldestOffset,
|
||||
MXOffsetToMemberSegment(xlrec.oldestOffset));
|
||||
|
||||
/* should not be required, but more than cheap enough */
|
||||
LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
|
||||
@@ -2959,19 +2868,19 @@ multixact_redo(XLogReaderState *record)
|
||||
* Advance the horizon values, so they're current at the end of
|
||||
* recovery.
|
||||
*/
|
||||
SetMultiXactIdLimit(xlrec.endTruncOff, xlrec.oldestMultiDB);
|
||||
SetMultiXactIdLimit(xlrec.oldestMulti, xlrec.oldestMultiDB);
|
||||
|
||||
PerformMembersTruncation(xlrec.startTruncMemb, xlrec.endTruncMemb);
|
||||
PerformMembersTruncation(xlrec.oldestOffset);
|
||||
|
||||
/*
|
||||
* During XLOG replay, latest_page_number isn't necessarily set up
|
||||
* yet; insert a suitable value to bypass the sanity test in
|
||||
* SimpleLruTruncate.
|
||||
*/
|
||||
pageno = MultiXactIdToOffsetPage(xlrec.endTruncOff);
|
||||
pageno = MultiXactIdToOffsetPage(xlrec.oldestMulti);
|
||||
pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
|
||||
pageno);
|
||||
PerformOffsetsTruncation(xlrec.startTruncOff, xlrec.endTruncOff);
|
||||
PerformOffsetsTruncation(xlrec.oldestMulti);
|
||||
|
||||
LWLockRelease(MultiXactTruncationLock);
|
||||
}
|
||||
|
||||
@@ -83,13 +83,11 @@ typedef struct xl_multixact_truncate
|
||||
{
|
||||
Oid oldestMultiDB;
|
||||
|
||||
/* to-be-truncated range of multixact offsets */
|
||||
MultiXactId startTruncOff; /* just for completeness' sake */
|
||||
MultiXactId endTruncOff;
|
||||
/* truncate multixact offsets older than this */
|
||||
MultiXactId oldestMulti;
|
||||
|
||||
/* to-be-truncated range of multixact members */
|
||||
MultiXactOffset startTruncMemb;
|
||||
MultiXactOffset endTruncMemb;
|
||||
/* truncate multixact members older than this */
|
||||
MultiXactOffset oldestOffset;
|
||||
} xl_multixact_truncate;
|
||||
|
||||
#define SizeOfMultiXactTruncate (sizeof(xl_multixact_truncate))
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
/*
|
||||
* Each page of XLOG file has a header like this:
|
||||
*/
|
||||
#define XLOG_PAGE_MAGIC 0xD11A /* can be used as WAL version indicator */
|
||||
#define XLOG_PAGE_MAGIC 0xD11B /* can be used as WAL version indicator */
|
||||
|
||||
typedef struct XLogPageHeaderData
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user