diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 24165ab03e..1e5b49595b 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -933,6 +933,7 @@ static void RemoveXlogFile(const char *segname, XLogSegNo recycleSegNo, static void UpdateLastRemovedPtr(char *filename); static void ValidateXLOGDirectoryStructure(void); static void RegisterSegmentBoundary(XLogSegNo seg, XLogRecPtr pos); +static void NotifySegmentsReadyForArchive(XLogRecPtr flushRecPtr); static void CleanupBackupHistory(void); static void UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force); static XLogRecord *ReadRecord(XLogReaderState *xlogreader, @@ -1157,6 +1158,29 @@ XLogInsertRecord(XLogRecData *rdata, */ } + /* + * Register our crossing the segment boundary if that occurred. We + * do this before WALInsertLockRelease() so that the record cannot be + * flushed to disk prior to registering the boundary (which could cause + * us to miss marking segments as ready for archive). + * + * Note that we do not use XLByteToPrevSeg() for determining the ending + * segment. This is so that a record that fits perfectly into the end + * of the segment causes the segment to get marked ready for archival + * immediately. + */ + if (XLogArchivingActive()) + { + XLogSegNo StartSeg; + XLogSegNo EndSeg; + + XLByteToSeg(StartPos, StartSeg, wal_segment_size); + XLByteToSeg(EndPos, EndSeg, wal_segment_size); + + if (StartSeg != EndSeg) + RegisterSegmentBoundary(EndSeg, EndPos); + } + /* * Done! Let others know that we're finished. */ @@ -1167,51 +1191,16 @@ XLogInsertRecord(XLogRecData *rdata, END_CRIT_SECTION(); /* - * If we crossed page boundary, update LogwrtRqst.Write; if we crossed - * segment boundary, register that and wake up walwriter. + * If we crossed page boundary, update LogwrtRqst.Write. */ if (StartPos / XLOG_BLCKSZ != EndPos / XLOG_BLCKSZ) { - XLogSegNo StartSeg; - XLogSegNo EndSeg; - - XLByteToSeg(StartPos, StartSeg, wal_segment_size); - XLByteToSeg(EndPos, EndSeg, wal_segment_size); - - /* - * 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 causes the latter to get marked ready for - * archival immediately. - */ - 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); 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); } /* @@ -2720,6 +2709,9 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible) WalSndWakeupRequest(); LogwrtResult.Flush = LogwrtResult.Write; + + if (XLogArchivingActive()) + NotifySegmentsReadyForArchive(LogwrtResult.Flush); } /* @@ -2738,9 +2730,6 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible) XLogCtl->LogwrtRqst.Flush = LogwrtResult.Flush; SpinLockRelease(&XLogCtl->info_lck); } - - if (XLogArchivingActive()) - NotifySegmentsReadyForArchive(LogwrtResult.Flush); } /* @@ -4434,7 +4423,7 @@ RegisterSegmentBoundary(XLogSegNo seg, XLogRecPtr endpos) * Mark segments as ready for archival, given that it is safe to do so. * This function is idempotent. */ -void +static void NotifySegmentsReadyForArchive(XLogRecPtr flushRecPtr) { XLogSegNo latest_boundary_seg; diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c index 6a1e16edc2..626fae8454 100644 --- a/src/backend/postmaster/walwriter.c +++ b/src/backend/postmaster/walwriter.c @@ -248,13 +248,6 @@ WalWriterMain(void) /* Process any signals received recently */ HandleWalWriterInterrupts(); - /* - * 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 6b6ae81c2d..0a8ede700d 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -315,7 +315,6 @@ extern XLogRecPtr GetInsertRecPtr(void); extern XLogRecPtr GetFlushRecPtr(void); extern XLogRecPtr GetLastImportantRecPtr(void); extern void RemovePromoteSignalFiles(void); -extern void NotifySegmentsReadyForArchive(XLogRecPtr flushRecPtr); extern bool PromoteIsTriggered(void); extern bool CheckPromoteSignal(void);