]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Revert "Avoid creating archive status ".ready" files too early"
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Sat, 4 Sep 2021 16:14:30 +0000 (12:14 -0400)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Sat, 4 Sep 2021 16:14:30 +0000 (12:14 -0400)
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

src/backend/access/transam/xlog.c
src/backend/postmaster/walwriter.c
src/include/access/xlog.h
src/include/access/xlogdefs.h

index 10e5e9f9539e2241279d343736a8e8e0f7276808..0e16018a047d79d6a09e9d9354c9e9e1c2ad9b10 100644 (file)
@@ -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
index a05dcee01f0654b83bc9b85472d5c523729178a3..ccac6f914df786a0329246a557b8200b1ef609ac 100644 (file)
@@ -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.
index 94ef8d8c6948fbf0ed1250b111be43e8effde22f..28f716d4cfa86174e347fef0c8ffd5f827b5d474 100644 (file)
@@ -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);
index aba135cd3439719634dedd79394abd4703112577..c2c6632e633d076284ea9d75b778d37ce3f70e6c 100644 (file)
@@ -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