From: Alvaro Herrera Date: Sat, 4 Sep 2021 16:14:30 +0000 (-0400) Subject: Revert "Avoid creating archive status ".ready" files too early" X-Git-Tag: REL9_6_24~54 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=121cdaff10686066a5e03eede8fa9ee562a0ad76;p=thirdparty%2Fpostgresql.git Revert "Avoid creating archive status ".ready" files too early" This reverts commit 515e3d84a0b5 and equivalent commits in back branches. This solution to the problem has a number of problems, so we'll try again with a different approach. Per note from Andres Freund Discussion: https://postgr.es/m/20210831042949.52eqp5xwbxgrfank@alap3.anarazel.de --- diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 10e5e9f9539..0e16018a047 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -682,18 +682,6 @@ typedef struct XLogCtlData XLogRecPtr lastFpwDisableRecPtr; slock_t info_lck; /* locks shared variables shown above */ - - /* - * Variables used to track segment-boundary-crossing WAL records. See - * RegisterSegmentBoundary. Protected by segtrack_lck. - */ - XLogSegNo lastNotifiedSeg; - XLogSegNo earliestSegBoundary; - XLogRecPtr earliestSegBoundaryEndPtr; - XLogSegNo latestSegBoundary; - XLogRecPtr latestSegBoundaryEndPtr; - - slock_t segtrack_lck; /* locks shared variables shown above */ } XLogCtlData; static XLogCtlData *XLogCtl = NULL; @@ -877,7 +865,6 @@ static void RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr PriorRedoPtr, XLogRec static void RemoveXlogFile(const char *segname, XLogRecPtr PriorRedoPtr, XLogRecPtr endptr); static void UpdateLastRemovedPtr(char *filename); static void ValidateXLOGDirectoryStructure(void); -static void RegisterSegmentBoundary(XLogSegNo seg, XLogRecPtr pos); static void CleanupBackupHistory(void); static void UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force); static XLogRecord *ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, @@ -1089,56 +1076,23 @@ XLogInsertRecord(XLogRecData *rdata, XLogRecPtr fpw_lsn) END_CRIT_SECTION(); /* - * If we crossed page boundary, update LogwrtRqst.Write; if we crossed - * segment boundary, register that and wake up walwriter. + * Update shared LogwrtRqst.Write, if we crossed page boundary. */ if (StartPos / XLOG_BLCKSZ != EndPos / XLOG_BLCKSZ) { - XLogSegNo StartSeg; - XLogSegNo EndSeg; - - XLByteToSeg(StartPos, StartSeg); - XLByteToSeg(EndPos, EndSeg); - - /* - * Register our crossing the segment boundary if that occurred. - * - * Note that we did not use XLByteToPrevSeg() for determining the - * ending segment. This is so that a record that fits perfectly into - * the end of the segment is marked ready for archival as soon as the - * flushed pointer jumps to the next segment. - */ - if (StartSeg != EndSeg && XLogArchivingActive()) - RegisterSegmentBoundary(EndSeg, EndPos); - - /* - * Advance LogwrtRqst.Write so that it includes new block(s). - * - * We do this after registering the segment boundary so that the - * comparison with the flushed pointer below can use the latest value - * known globally. - */ SpinLockAcquire(&XLogCtl->info_lck); + /* advance global request to include new block(s) */ if (XLogCtl->LogwrtRqst.Write < EndPos) XLogCtl->LogwrtRqst.Write = EndPos; /* update local result copy while I have the chance */ LogwrtResult = XLogCtl->LogwrtResult; SpinLockRelease(&XLogCtl->info_lck); - - /* - * There's a chance that the record was already flushed to disk and we - * missed marking segments as ready for archive. If this happens, we - * nudge the WALWriter, which will take care of notifying segments as - * needed. - */ - if (StartSeg != EndSeg && XLogArchivingActive() && - LogwrtResult.Flush >= EndPos && ProcGlobal->walwriterLatch) - SetLatch(ProcGlobal->walwriterLatch); } /* * If this was an XLOG_SWITCH record, flush the record and the empty - * padding space that fills the rest of the segment. + * padding space that fills the rest of the segment, and perform + * end-of-segment actions (eg, notifying archiver). */ if (isLogSwitch) { @@ -2257,7 +2211,6 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible) /* We should always be inside a critical section here */ Assert(CritSectionCount > 0); - Assert(LWLockHeldByMe(WALWriteLock)); /* * Update local LogwrtResult (caller probably did this already, but...) @@ -2403,12 +2356,11 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible) * later. Doing it here ensures that one and only one backend will * perform this fsync. * - * If WAL archiving is active, we attempt to notify the archiver - * of any segments that are now ready for archival. - * - * This is also the right place to update the timer for - * archive_timeout and to signal for a checkpoint if too many - * logfile segments have been used since the last checkpoint. + * This is also the right place to notify the Archiver that the + * segment is ready to copy to archival storage, and to update the + * timer for archive_timeout, and to signal for a checkpoint if + * too many logfile segments have been used since the last + * checkpoint. */ if (finishing_seg) { @@ -2420,7 +2372,7 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible) LogwrtResult.Flush = LogwrtResult.Write; /* end of page */ if (XLogArchivingActive()) - NotifySegmentsReadyForArchive(LogwrtResult.Flush); + XLogArchiveNotifySeg(openLogSegNo); XLogCtl->lastSegSwitchTime = (pg_time_t) time(NULL); @@ -2505,9 +2457,6 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible) XLogCtl->LogwrtRqst.Flush = LogwrtResult.Flush; SpinLockRelease(&XLogCtl->info_lck); } - - if (XLogArchivingActive()) - NotifySegmentsReadyForArchive(LogwrtResult.Flush); } /* @@ -4049,129 +3998,6 @@ ValidateXLOGDirectoryStructure(void) } } -/* - * RegisterSegmentBoundary - * - * WAL records that are split across a segment boundary require special - * treatment for archiving: the initial segment must not be archived until - * the end segment has been flushed, in case we crash before we have - * the chance to flush the end segment (because after recovery we would - * overwrite that WAL record with a different one, and so the file we - * archived no longer represents truth.) This also applies to streaming - * physical replication. - * - * To handle this, we keep track of the LSN of WAL records that cross - * segment boundaries. Two such are sufficient: the earliest and the - * latest we know about, since the flush position advances monotonically. - * WAL record writers register boundary-crossing records here, which is - * used by .ready file creation to delay until the end segment is known - * flushed. - */ -static void -RegisterSegmentBoundary(XLogSegNo seg, XLogRecPtr endpos) -{ - XLogSegNo segno PG_USED_FOR_ASSERTS_ONLY; - - /* verify caller computed segment number correctly */ - AssertArg((XLByteToSeg(endpos, segno), segno == seg)); - - SpinLockAcquire(&XLogCtl->segtrack_lck); - - /* - * If no segment boundaries are registered, store the new segment boundary - * in earliestSegBoundary. Otherwise, store the greater segment - * boundaries in latestSegBoundary. - */ - if (XLogCtl->earliestSegBoundary == MaxXLogSegNo) - { - XLogCtl->earliestSegBoundary = seg; - XLogCtl->earliestSegBoundaryEndPtr = endpos; - } - else if (seg > XLogCtl->earliestSegBoundary && - (XLogCtl->latestSegBoundary == MaxXLogSegNo || - seg > XLogCtl->latestSegBoundary)) - { - XLogCtl->latestSegBoundary = seg; - XLogCtl->latestSegBoundaryEndPtr = endpos; - } - - SpinLockRelease(&XLogCtl->segtrack_lck); -} - -/* - * NotifySegmentsReadyForArchive - * - * Mark segments as ready for archival, given that it is safe to do so. - * This function is idempotent. - */ -void -NotifySegmentsReadyForArchive(XLogRecPtr flushRecPtr) -{ - XLogSegNo latest_boundary_seg; - XLogSegNo last_notified; - XLogSegNo flushed_seg; - XLogSegNo seg; - bool keep_latest; - - XLByteToSeg(flushRecPtr, flushed_seg); - - SpinLockAcquire(&XLogCtl->segtrack_lck); - - if (XLogCtl->latestSegBoundary <= flushed_seg && - XLogCtl->latestSegBoundaryEndPtr <= flushRecPtr) - { - latest_boundary_seg = XLogCtl->latestSegBoundary; - keep_latest = false; - } - else if (XLogCtl->earliestSegBoundary <= flushed_seg && - XLogCtl->earliestSegBoundaryEndPtr <= flushRecPtr) - { - latest_boundary_seg = XLogCtl->earliestSegBoundary; - keep_latest = true; - } - else - { - SpinLockRelease(&XLogCtl->segtrack_lck); - return; - } - - last_notified = XLogCtl->lastNotifiedSeg; - - /* - * Update shared memory and discard segment boundaries that are no longer - * needed. - * - * It is safe to update shared memory before we attempt to create the - * .ready files. If our calls to XLogArchiveNotifySeg() fail, - * RemoveOldXlogFiles() will retry it as needed. - */ - if (last_notified < latest_boundary_seg - 1) - XLogCtl->lastNotifiedSeg = latest_boundary_seg - 1; - - if (keep_latest) - { - XLogCtl->earliestSegBoundary = XLogCtl->latestSegBoundary; - XLogCtl->earliestSegBoundaryEndPtr = XLogCtl->latestSegBoundaryEndPtr; - } - else - { - XLogCtl->earliestSegBoundary = MaxXLogSegNo; - XLogCtl->earliestSegBoundaryEndPtr = InvalidXLogRecPtr; - } - - XLogCtl->latestSegBoundary = MaxXLogSegNo; - XLogCtl->latestSegBoundaryEndPtr = InvalidXLogRecPtr; - - SpinLockRelease(&XLogCtl->segtrack_lck); - - /* - * Notify archiver about segments that are ready for archival (by creating - * the corresponding .ready files). - */ - for (seg = last_notified + 1; seg < latest_boundary_seg; seg++) - XLogArchiveNotifySeg(seg); -} - /* * Remove previous backup history files. This also retries creation of * .ready files for any backup history files for which XLogArchiveNotify @@ -5035,17 +4861,9 @@ XLOGShmemInit(void) SpinLockInit(&XLogCtl->Insert.insertpos_lck); SpinLockInit(&XLogCtl->info_lck); - SpinLockInit(&XLogCtl->segtrack_lck); SpinLockInit(&XLogCtl->ulsn_lck); InitSharedLatch(&XLogCtl->recoveryWakeupLatch); - /* Initialize stuff for marking segments as ready for archival. */ - XLogCtl->lastNotifiedSeg = MaxXLogSegNo; - XLogCtl->earliestSegBoundary = MaxXLogSegNo; - XLogCtl->earliestSegBoundaryEndPtr = InvalidXLogRecPtr; - XLogCtl->latestSegBoundary = MaxXLogSegNo; - XLogCtl->latestSegBoundaryEndPtr = InvalidXLogRecPtr; - /* * If we are not in bootstrap mode, pg_control should already exist. Read * and validate it immediately (see comments in ReadControlFile() for the @@ -7565,20 +7383,6 @@ StartupXLOG(void) XLogCtl->LogwrtRqst.Write = EndOfLog; XLogCtl->LogwrtRqst.Flush = EndOfLog; - /* - * Initialize XLogCtl->lastNotifiedSeg to the previous WAL file. - */ - if (XLogArchivingActive()) - { - XLogSegNo EndOfLogSeg; - - XLByteToSeg(EndOfLog, EndOfLogSeg); - - SpinLockAcquire(&XLogCtl->segtrack_lck); - XLogCtl->lastNotifiedSeg = EndOfLogSeg - 1; - SpinLockRelease(&XLogCtl->segtrack_lck); - } - /* * Update full_page_writes in shared memory and write an XLOG_FPW_CHANGE * record before resource manager writes cleanup WAL records or checkpoint diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c index a05dcee01f0..ccac6f914df 100644 --- a/src/backend/postmaster/walwriter.c +++ b/src/backend/postmaster/walwriter.c @@ -269,13 +269,6 @@ WalWriterMain(void) proc_exit(0); /* done */ } - /* - * Notify the archiver of any WAL segments that are ready. We do this - * here to handle a race condition where WAL is flushed to disk prior - * to registering the segment boundary. - */ - NotifySegmentsReadyForArchive(GetFlushRecPtr()); - /* * Do what we're here for; then, if XLogBackgroundFlush() found useful * work to do, reset hibernation counter. diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 94ef8d8c694..28f716d4cfa 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -274,7 +274,6 @@ extern XLogRecPtr GetInsertRecPtr(void); extern XLogRecPtr GetFlushRecPtr(void); extern void GetNextXidAndEpoch(TransactionId *xid, uint32 *epoch); extern void RemovePromoteSignalFiles(void); -extern void NotifySegmentsReadyForArchive(XLogRecPtr flushRecPtr); extern bool CheckPromoteSignal(void); extern void WakeupRecovery(void); diff --git a/src/include/access/xlogdefs.h b/src/include/access/xlogdefs.h index aba135cd343..c2c6632e633 100644 --- a/src/include/access/xlogdefs.h +++ b/src/include/access/xlogdefs.h @@ -32,7 +32,6 @@ typedef uint64 XLogRecPtr; * XLogSegNo - physical log file sequence number. */ typedef uint64 XLogSegNo; -#define MaxXLogSegNo ((XLogSegNo) 0xFFFFFFFFFFFFFFFF) /* * TimeLineID (TLI) - identifies different database histories to prevent