Change ThisTimeLineID from a global variable to a local variable.
authorRobert Haas <rhaas@postgresql.org>
Fri, 5 Nov 2021 16:53:15 +0000 (12:53 -0400)
committerRobert Haas <rhaas@postgresql.org>
Fri, 5 Nov 2021 16:53:15 +0000 (12:53 -0400)
StartupXLOG() still has ThisTimeLineID as a local variable, but the
remaining code in xlog.c now needs to the relevant TimeLineID by some
other means. Mostly, this means that we now pass it as a function
parameter to a bunch of functions where we didn't previously.
However, a few cases require special handling:

- In functions that might be called by outside callers who
  wouldn't necessarily know what timeline to specify, we get
  the timeline ID from shared memory. XLogCtl->ThisTimeLineID
  can be used in most cases since recovery is known to have
  completed by the time those functions are called.  In
  xlog_redo(), we can use XLogCtl->replayEndTLI.

- XLogFileClose() needs to know the TLI of the open logfile.
  Do that with a new global variable openLogTLI. While
  someone could argue that this is just trading one global
  variable for another, the new one has a far more narrow
  purposes and is referenced in just a few places.

- read_backup_label() now returns the TLI that it obtains
  by parsing the backup_label file. Previously, ReadRecord()
  could be called to parse the checkpoint record without
  ThisTimeLineID having been initialized. Now, the timeline
  is passed down, and I didn't want to pass an uninitialized
  variable; this change lets us avoid that. The old coding
  didn't seem to have any practical consequences that we need
  to worry about, but this is cleaner.

- In BootstrapXLOG(), it's just a constant.

Patch by me, reviewed and tested by Michael Paquier, Amul Sul, and
Álvaro Herrera.

Discussion: https://postgr.es/m/CA+TgmobfAAqhfWa1kaFBBFvX+5CjM=7TE=n4r4Q1o2bjbGYBpA@mail.gmail.com

src/backend/access/transam/xlog.c
src/include/access/xlog.h

index 9b15735921bcaa3355d606fe6cbcfb35411ca7ee..7b1b3e802bb7b8222e75ad3ff318ceab4fa5bc9b 100644 (file)
@@ -88,6 +88,9 @@ extern uint32 bootstrap_data_checksum_version;
 #define RECOVERY_COMMAND_FILE  "recovery.conf"
 #define RECOVERY_COMMAND_DONE  "recovery.done"
 
+/* timeline ID to be used when bootstrapping */
+#define BootstrapTimeLineID            1
+
 /* User-settable parameters */
 int                    max_wal_size_mb = 1024; /* 1 GB */
 int                    min_wal_size_mb = 80;   /* 80 MB */
@@ -188,12 +191,6 @@ const struct config_enum_entry recovery_target_action_options[] = {
  */
 CheckpointStatsData CheckpointStats;
 
-/*
- * ThisTimeLineID will be same in all backends --- it identifies current
- * WAL timeline for the database system.
- */
-static TimeLineID      ThisTimeLineID = 0;
-
 static XLogRecPtr LastRec;
 
 /* Local copy of WalRcv->flushedUpto */
@@ -801,12 +798,15 @@ static const char *const xlogSourceNames[] = {"any", "archive", "pg_wal", "strea
 
 /*
  * openLogFile is -1 or a kernel FD for an open log file segment.
- * openLogSegNo identifies the segment.  These variables are only used to
- * write the XLOG, and so will normally refer to the active segment.
+ * openLogSegNo identifies the segment, and openLogTLI the corresponding TLI.
+ * These variables are only used to write the XLOG, and so will normally refer
+ * to the active segment.
+ *
  * Note: call Reserve/ReleaseExternalFD to track consumption of this FD.
  */
 static int     openLogFile = -1;
 static XLogSegNo openLogSegNo = 0;
+static TimeLineID openLogTLI = 0;
 
 /*
  * These variables are used similarly to the ones above, but for reading
@@ -842,6 +842,7 @@ typedef struct XLogPageReadPrivate
        int                     emode;
        bool            fetching_ckpt;  /* are we fetching a checkpoint record? */
        bool            randAccess;
+       TimeLineID      replayTLI;
 } XLogPageReadPrivate;
 
 /*
@@ -889,9 +890,11 @@ static MemoryContext walDebugCxt = NULL;
 
 static void readRecoverySignalFile(void);
 static void validateRecoveryParameters(void);
-static void exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog);
+static void exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog,
+                                                               TimeLineID newTLI);
 static void CleanupAfterArchiveRecovery(TimeLineID EndOfLogTLI,
-                                                                               XLogRecPtr EndOfLog);
+                                                                               XLogRecPtr EndOfLog,
+                                                                               TimeLineID newTLI);
 static bool recoveryStopsBefore(XLogReaderState *record);
 static bool recoveryStopsAfter(XLogReaderState *record);
 static char *getRecoveryStopReason(void);
@@ -903,7 +906,7 @@ static void SetCurrentChunkStartTime(TimestampTz xtime);
 static void CheckRequiredParameterValues(void);
 static void XLogReportParameters(void);
 static void checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI,
-                                                               TimeLineID prevTLI);
+                                                               TimeLineID prevTLI, TimeLineID replayTLI);
 static void VerifyOverwriteContrecord(xl_overwrite_contrecord *xlrec,
                                                                          XLogReaderState *state);
 static int LocalSetXLogInsertAllowed(void);
@@ -913,9 +916,10 @@ static void CheckPointGuts(XLogRecPtr checkPointRedo, int flags);
 static void KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo);
 static XLogRecPtr XLogGetReplicationSlotMinimumLSN(void);
 
-static void AdvanceXLInsertBuffer(XLogRecPtr upto, bool opportunistic);
+static void AdvanceXLInsertBuffer(XLogRecPtr upto, TimeLineID tli,
+                                                                 bool opportunistic);
 static bool XLogCheckpointNeeded(XLogSegNo new_segno);
-static void XLogWrite(XLogwrtRqst WriteRqst, bool flexible);
+static void XLogWrite(XLogwrtRqst WriteRqst, TimeLineID tli, bool flexible);
 static bool InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
                                                                   bool find_free, XLogSegNo max_segno,
                                                                   TimeLineID tli);
@@ -925,26 +929,30 @@ static int        XLogFileReadAnyTLI(XLogSegNo segno, int emode, XLogSource source);
 static int     XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr,
                                                 int reqLen, XLogRecPtr targetRecPtr, char *readBuf);
 static bool WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
-                                                                               bool fetching_ckpt, XLogRecPtr tliRecPtr);
+                                                                               bool fetching_ckpt, XLogRecPtr tliRecPtr,
+                                                                               TimeLineID replayTLI);
 static void XLogShutdownWalRcv(void);
 static int     emode_for_corrupt_record(int emode, XLogRecPtr RecPtr);
 static void XLogFileClose(void);
-static void PreallocXlogFiles(XLogRecPtr endptr);
+static void PreallocXlogFiles(XLogRecPtr endptr, TimeLineID tli);
 static void RemoveTempXlogFiles(void);
-static void RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr lastredoptr, XLogRecPtr endptr);
+static void RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr lastredoptr,
+                                                          XLogRecPtr endptr, TimeLineID insertTLI);
 static void RemoveXlogFile(const char *segname, XLogSegNo recycleSegNo,
-                                                  XLogSegNo *endlogSegNo);
+                                                  XLogSegNo *endlogSegNo, TimeLineID insertTLI);
 static void UpdateLastRemovedPtr(char *filename);
 static void ValidateXLOGDirectoryStructure(void);
 static void CleanupBackupHistory(void);
 static void UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force);
 static XLogRecord *ReadRecord(XLogReaderState *xlogreader,
-                                                         int emode, bool fetching_ckpt);
+                                                         int emode, bool fetching_ckpt,
+                                                         TimeLineID replayTLI);
 static void CheckRecoveryConsistency(void);
 static bool PerformRecoveryXLogAction(void);
 static XLogRecord *ReadCheckpointRecord(XLogReaderState *xlogreader,
-                                                                               XLogRecPtr RecPtr, int whichChkpt, bool report);
-static bool rescanLatestTimeLine(void);
+                                                                               XLogRecPtr RecPtr, int whichChkpt, bool report,
+                                                                               TimeLineID replayTLI);
+static bool rescanLatestTimeLine(TimeLineID replayTLI);
 static void InitControlFile(uint64 sysidentifier);
 static void WriteControlFile(void);
 static void ReadControlFile(void);
@@ -960,6 +968,7 @@ static void xlog_outdesc(StringInfo buf, XLogReaderState *record);
 static void pg_start_backup_callback(int code, Datum arg);
 static void pg_stop_backup_callback(int code, Datum arg);
 static bool read_backup_label(XLogRecPtr *checkPointLoc,
+                                                         TimeLineID *backupLabelTLI,
                                                          bool *backupEndRequired, bool *backupFromStandby);
 static bool read_tablespace_map(List **tablespaces);
 
@@ -968,13 +977,14 @@ static int        get_sync_bit(int method);
 
 static void CopyXLogRecordToWAL(int write_len, bool isLogSwitch,
                                                                XLogRecData *rdata,
-                                                               XLogRecPtr StartPos, XLogRecPtr EndPos);
+                                                               XLogRecPtr StartPos, XLogRecPtr EndPos,
+                                                               TimeLineID tli);
 static void ReserveXLogInsertLocation(int size, XLogRecPtr *StartPos,
                                                                          XLogRecPtr *EndPos, XLogRecPtr *PrevPtr);
 static bool ReserveXLogSwitch(XLogRecPtr *StartPos, XLogRecPtr *EndPos,
                                                          XLogRecPtr *PrevPtr);
 static XLogRecPtr WaitXLogInsertionsToFinish(XLogRecPtr upto);
-static char *GetXLogBuffer(XLogRecPtr ptr);
+static char *GetXLogBuffer(XLogRecPtr ptr, TimeLineID tli);
 static XLogRecPtr XLogBytePosToRecPtr(uint64 bytepos);
 static XLogRecPtr XLogBytePosToEndRecPtr(uint64 bytepos);
 static uint64 XLogRecPtrToBytePos(XLogRecPtr ptr);
@@ -1031,6 +1041,7 @@ XLogInsertRecord(XLogRecData *rdata,
        XLogRecPtr      StartPos;
        XLogRecPtr      EndPos;
        bool            prevDoPageWrites = doPageWrites;
+       TimeLineID      insertTLI;
 
        /* we assume that all of the record header is in the first chunk */
        Assert(rdata->len >= SizeOfXLogRecord);
@@ -1039,6 +1050,12 @@ XLogInsertRecord(XLogRecData *rdata,
        if (!XLogInsertAllowed())
                elog(ERROR, "cannot make new WAL entries during recovery");
 
+       /*
+        * Given that we're not in recovery, ThisTimeLineID is set and can't
+        * change, so we can read it without a lock.
+        */
+       insertTLI = XLogCtl->ThisTimeLineID;
+
        /*----------
         *
         * We have now done all the preparatory work we can without holding a
@@ -1142,7 +1159,7 @@ XLogInsertRecord(XLogRecData *rdata,
                 * inserted. Copy the record in the space reserved.
                 */
                CopyXLogRecordToWAL(rechdr->xl_tot_len, isLogSwitch, rdata,
-                                                       StartPos, EndPos);
+                                                       StartPos, EndPos, insertTLI);
 
                /*
                 * Unless record is flagged as not important, update LSN of last
@@ -1533,7 +1550,7 @@ checkXLogConsistency(XLogReaderState *record)
  */
 static void
 CopyXLogRecordToWAL(int write_len, bool isLogSwitch, XLogRecData *rdata,
-                                       XLogRecPtr StartPos, XLogRecPtr EndPos)
+                                       XLogRecPtr StartPos, XLogRecPtr EndPos, TimeLineID tli)
 {
        char       *currpos;
        int                     freespace;
@@ -1546,7 +1563,7 @@ CopyXLogRecordToWAL(int write_len, bool isLogSwitch, XLogRecData *rdata,
         * inserting to.
         */
        CurrPos = StartPos;
-       currpos = GetXLogBuffer(CurrPos);
+       currpos = GetXLogBuffer(CurrPos, tli);
        freespace = INSERT_FREESPACE(CurrPos);
 
        /*
@@ -1583,7 +1600,7 @@ CopyXLogRecordToWAL(int write_len, bool isLogSwitch, XLogRecData *rdata,
                         * page was initialized, in AdvanceXLInsertBuffer, and we're the
                         * only backend that needs to set the contrecord flag.
                         */
-                       currpos = GetXLogBuffer(CurrPos);
+                       currpos = GetXLogBuffer(CurrPos, tli);
                        pagehdr = (XLogPageHeader) currpos;
                        pagehdr->xlp_rem_len = write_len - written;
                        pagehdr->xlp_info |= XLP_FIRST_IS_CONTRECORD;
@@ -1656,7 +1673,7 @@ CopyXLogRecordToWAL(int write_len, bool isLogSwitch, XLogRecData *rdata,
                         * (which itself calls the two methods we need) to get the pointer
                         * and zero most of the page.  Then we just zero the page header.
                         */
-                       currpos = GetXLogBuffer(CurrPos);
+                       currpos = GetXLogBuffer(CurrPos, tli);
                        MemSet(currpos, 0, SizeOfXLogShortPHD);
 
                        CurrPos += XLOG_BLCKSZ;
@@ -1908,7 +1925,7 @@ WaitXLogInsertionsToFinish(XLogRecPtr upto)
  * later, because older buffers might be recycled already)
  */
 static char *
-GetXLogBuffer(XLogRecPtr ptr)
+GetXLogBuffer(XLogRecPtr ptr, TimeLineID tli)
 {
        int                     idx;
        XLogRecPtr      endptr;
@@ -1984,7 +2001,7 @@ GetXLogBuffer(XLogRecPtr ptr)
 
                WALInsertLockUpdateInsertingAt(initializedUpto);
 
-               AdvanceXLInsertBuffer(ptr, false);
+               AdvanceXLInsertBuffer(ptr, tli, false);
                endptr = XLogCtl->xlblocks[idx];
 
                if (expectedEndPtr != endptr)
@@ -2146,7 +2163,7 @@ XLogRecPtrToBytePos(XLogRecPtr ptr)
  * initialized properly.
  */
 static void
-AdvanceXLInsertBuffer(XLogRecPtr upto, bool opportunistic)
+AdvanceXLInsertBuffer(XLogRecPtr upto, TimeLineID tli, bool opportunistic)
 {
        XLogCtlInsert *Insert = &XLogCtl->Insert;
        int                     nextidx;
@@ -2219,7 +2236,7 @@ AdvanceXLInsertBuffer(XLogRecPtr upto, bool opportunistic)
                                        TRACE_POSTGRESQL_WAL_BUFFER_WRITE_DIRTY_START();
                                        WriteRqst.Write = OldPageRqstPtr;
                                        WriteRqst.Flush = 0;
-                                       XLogWrite(WriteRqst, false);
+                                       XLogWrite(WriteRqst, tli, false);
                                        LWLockRelease(WALWriteLock);
                                        WalStats.m_wal_buffers_full++;
                                        TRACE_POSTGRESQL_WAL_BUFFER_WRITE_DIRTY_DONE();
@@ -2253,7 +2270,7 @@ AdvanceXLInsertBuffer(XLogRecPtr upto, bool opportunistic)
                NewPage->xlp_magic = XLOG_PAGE_MAGIC;
 
                /* NewPage->xlp_info = 0; */    /* done by memset */
-               NewPage->xlp_tli = ThisTimeLineID;
+               NewPage->xlp_tli = tli;
                NewPage->xlp_pageaddr = NewPageBeginPtr;
 
                /* NewPage->xlp_rem_len = 0; */ /* done by memset */
@@ -2449,7 +2466,7 @@ XLogCheckpointNeeded(XLogSegNo new_segno)
  * write.
  */
 static void
-XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
+XLogWrite(XLogwrtRqst WriteRqst, TimeLineID tli, bool flexible)
 {
        bool            ispartialpage;
        bool            last_iteration;
@@ -2517,9 +2534,10 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
                                XLogFileClose();
                        XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo,
                                                        wal_segment_size);
+                       openLogTLI = tli;
 
                        /* create/use new log file */
-                       openLogFile = XLogFileInit(openLogSegNo, ThisTimeLineID);
+                       openLogFile = XLogFileInit(openLogSegNo, tli);
                        ReserveExternalFD();
                }
 
@@ -2528,7 +2546,8 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
                {
                        XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo,
                                                        wal_segment_size);
-                       openLogFile = XLogFileOpen(openLogSegNo);
+                       openLogTLI = tli;
+                       openLogFile = XLogFileOpen(openLogSegNo, tli);
                        ReserveExternalFD();
                }
 
@@ -2603,7 +2622,7 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
                                                continue;
 
                                        save_errno = errno;
-                                       XLogFileName(xlogfname, ThisTimeLineID, openLogSegNo,
+                                       XLogFileName(xlogfname, tli, openLogSegNo,
                                                                 wal_segment_size);
                                        errno = save_errno;
                                        ereport(PANIC,
@@ -2634,7 +2653,7 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
                         */
                        if (finishing_seg)
                        {
-                               issue_xlog_fsync(openLogFile, openLogSegNo, ThisTimeLineID);
+                               issue_xlog_fsync(openLogFile, openLogSegNo, tli);
 
                                /* signal that we need to wakeup walsenders later */
                                WalSndWakeupRequest();
@@ -2642,7 +2661,7 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
                                LogwrtResult.Flush = LogwrtResult.Write;        /* end of page */
 
                                if (XLogArchivingActive())
-                                       XLogArchiveNotifySeg(openLogSegNo, ThisTimeLineID);
+                                       XLogArchiveNotifySeg(openLogSegNo, tli);
 
                                XLogCtl->lastSegSwitchTime = (pg_time_t) time(NULL);
                                XLogCtl->lastSegSwitchLSN = LogwrtResult.Flush;
@@ -2701,11 +2720,12 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
                        {
                                XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo,
                                                                wal_segment_size);
-                               openLogFile = XLogFileOpen(openLogSegNo);
+                               openLogTLI = tli;
+                               openLogFile = XLogFileOpen(openLogSegNo, tli);
                                ReserveExternalFD();
                        }
 
-                       issue_xlog_fsync(openLogFile, openLogSegNo, ThisTimeLineID);
+                       issue_xlog_fsync(openLogFile, openLogSegNo, tli);
                }
 
                /* signal that we need to wakeup walsenders later */
@@ -2901,6 +2921,7 @@ XLogFlush(XLogRecPtr record)
 {
        XLogRecPtr      WriteRqstPtr;
        XLogwrtRqst WriteRqst;
+       TimeLineID      insertTLI = XLogCtl->ThisTimeLineID;
 
        /*
         * During REDO, we are reading not writing WAL.  Therefore, instead of
@@ -3021,7 +3042,7 @@ XLogFlush(XLogRecPtr record)
                WriteRqst.Write = insertpos;
                WriteRqst.Flush = insertpos;
 
-               XLogWrite(WriteRqst, false);
+               XLogWrite(WriteRqst, insertTLI, false);
 
                LWLockRelease(WALWriteLock);
                /* done */
@@ -3093,11 +3114,18 @@ XLogBackgroundFlush(void)
        static TimestampTz lastflush;
        TimestampTz now;
        int                     flushbytes;
+       TimeLineID      insertTLI;
 
        /* XLOG doesn't need flushing during recovery */
        if (RecoveryInProgress())
                return false;
 
+       /*
+        * Since we're not in recovery, ThisTimeLineID is set and can't change,
+        * so we can read it without a lock.
+        */
+       insertTLI = XLogCtl->ThisTimeLineID;
+
        /* read LogwrtResult and update local state */
        SpinLockAcquire(&XLogCtl->info_lck);
        LogwrtResult = XLogCtl->LogwrtResult;
@@ -3188,7 +3216,7 @@ XLogBackgroundFlush(void)
        if (WriteRqst.Write > LogwrtResult.Write ||
                WriteRqst.Flush > LogwrtResult.Flush)
        {
-               XLogWrite(WriteRqst, flexible);
+               XLogWrite(WriteRqst, insertTLI, flexible);
        }
        LWLockRelease(WALWriteLock);
 
@@ -3201,7 +3229,7 @@ XLogBackgroundFlush(void)
         * Great, done. To take some work off the critical path, try to initialize
         * as many of the no-longer-needed WAL buffers for future use as we can.
         */
-       AdvanceXLInsertBuffer(InvalidXLogRecPtr, true);
+       AdvanceXLInsertBuffer(InvalidXLogRecPtr, insertTLI, true);
 
        /*
         * If we determined that we need to write data, but somebody else
@@ -3523,7 +3551,8 @@ XLogFileInit(XLogSegNo logsegno, TimeLineID logtli)
  * emplacing a bogus file.
  */
 static void
-XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno,
+XLogFileCopy(TimeLineID destTLI, XLogSegNo destsegno,
+                        TimeLineID srcTLI, XLogSegNo srcsegno,
                         int upto)
 {
        char            path[MAXPGPATH];
@@ -3636,7 +3665,7 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno,
        /*
         * Now move the segment into place with its final name.
         */
-       if (!InstallXLogFileSegment(&destsegno, tmppath, false, 0, ThisTimeLineID))
+       if (!InstallXLogFileSegment(&destsegno, tmppath, false, 0, destTLI))
                elog(ERROR, "InstallXLogFileSegment should not have failed");
 }
 
@@ -3725,12 +3754,12 @@ InstallXLogFileSegment(XLogSegNo *segno, char *tmppath,
  * Open a pre-existing logfile segment for writing.
  */
 int
-XLogFileOpen(XLogSegNo segno)
+XLogFileOpen(XLogSegNo segno, TimeLineID tli)
 {
        char            path[MAXPGPATH];
        int                     fd;
 
-       XLogFilePath(path, ThisTimeLineID, segno, wal_segment_size);
+       XLogFilePath(path, tli, segno, wal_segment_size);
 
        fd = BasicOpenFile(path, O_RDWR | PG_BINARY | get_sync_bit(sync_method));
        if (fd < 0)
@@ -3951,7 +3980,7 @@ XLogFileClose(void)
                char            xlogfname[MAXFNAMELEN];
                int                     save_errno = errno;
 
-               XLogFileName(xlogfname, ThisTimeLineID, openLogSegNo, wal_segment_size);
+               XLogFileName(xlogfname, openLogTLI, openLogSegNo, wal_segment_size);
                errno = save_errno;
                ereport(PANIC,
                                (errcode_for_file_access(),
@@ -3982,7 +4011,7 @@ XLogFileClose(void)
  * reporting and resource reclamation.)
  */
 static void
-PreallocXlogFiles(XLogRecPtr endptr)
+PreallocXlogFiles(XLogRecPtr endptr, TimeLineID tli)
 {
        XLogSegNo       _logSegNo;
        int                     lf;
@@ -3998,7 +4027,7 @@ PreallocXlogFiles(XLogRecPtr endptr)
        if (offset >= (uint32) (0.75 * wal_segment_size))
        {
                _logSegNo++;
-               lf = XLogFileInitInternal(_logSegNo, ThisTimeLineID, &added, path);
+               lf = XLogFileInitInternal(_logSegNo, tli, &added, path);
                if (lf >= 0)
                        close(lf);
                if (added)
@@ -4115,9 +4144,13 @@ RemoveTempXlogFiles(void)
  * endptr is current (or recent) end of xlog, and lastredoptr is the
  * redo pointer of the last checkpoint. These are used to determine
  * whether we want to recycle rather than delete no-longer-wanted log files.
+ *
+ * insertTLI is the current timeline for XLOG insertion. Any recycled
+ * segments should be reused for this timeline.
  */
 static void
-RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr lastredoptr, XLogRecPtr endptr)
+RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr lastredoptr, XLogRecPtr endptr,
+                                  TimeLineID insertTLI)
 {
        DIR                *xldir;
        struct dirent *xlde;
@@ -4166,7 +4199,8 @@ RemoveOldXlogFiles(XLogSegNo segno, XLogRecPtr lastredoptr, XLogRecPtr endptr)
                                /* Update the last removed location in shared memory first */
                                UpdateLastRemovedPtr(xlde->d_name);
 
-                               RemoveXlogFile(xlde->d_name, recycleSegNo, &endlogSegNo);
+                               RemoveXlogFile(xlde->d_name, recycleSegNo, &endlogSegNo,
+                                                          insertTLI);
                        }
                }
        }
@@ -4238,7 +4272,8 @@ RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI)
                         * - but seems safer to let them be archived and removed later.
                         */
                        if (!XLogArchiveIsReady(xlde->d_name))
-                               RemoveXlogFile(xlde->d_name, recycleSegNo, &endLogSegNo);
+                               RemoveXlogFile(xlde->d_name, recycleSegNo, &endLogSegNo,
+                                                          newTLI);
                }
        }
 
@@ -4254,10 +4289,13 @@ RemoveNonParentXlogFiles(XLogRecPtr switchpoint, TimeLineID newTLI)
  *
  * endlogSegNo gets incremented if the segment is recycled so as it is not
  * checked again with future callers of this function.
+ *
+ * insertTLI is the current timeline for XLOG insertion. Any recycled segments
+ * should be used for this timeline.
  */
 static void
 RemoveXlogFile(const char *segname, XLogSegNo recycleSegNo,
-                          XLogSegNo *endlogSegNo)
+                          XLogSegNo *endlogSegNo, TimeLineID insertTLI)
 {
        char            path[MAXPGPATH];
 #ifdef WIN32
@@ -4277,7 +4315,7 @@ RemoveXlogFile(const char *segname, XLogSegNo recycleSegNo,
                XLogCtl->InstallXLogFileSegmentActive &&        /* callee rechecks this */
                lstat(path, &statbuf) == 0 && S_ISREG(statbuf.st_mode) &&
                InstallXLogFileSegment(endlogSegNo, path,
-                                                          true, recycleSegNo, ThisTimeLineID))
+                                                          true, recycleSegNo, insertTLI))
        {
                ereport(DEBUG2,
                                (errmsg_internal("recycled write-ahead log file \"%s\"",
@@ -4422,7 +4460,7 @@ CleanupBackupHistory(void)
  */
 static XLogRecord *
 ReadRecord(XLogReaderState *xlogreader, int emode,
-                  bool fetching_ckpt)
+                  bool fetching_ckpt, TimeLineID replayTLI)
 {
        XLogRecord *record;
        XLogPageReadPrivate *private = (XLogPageReadPrivate *) xlogreader->private_data;
@@ -4431,6 +4469,7 @@ ReadRecord(XLogReaderState *xlogreader, int emode,
        private->fetching_ckpt = fetching_ckpt;
        private->emode = emode;
        private->randAccess = (xlogreader->ReadRecPtr == InvalidXLogRecPtr);
+       private->replayTLI = replayTLI;
 
        /* This is the first attempt to read this page. */
        lastSourceFailed = false;
@@ -4533,7 +4572,7 @@ ReadRecord(XLogReaderState *xlogreader, int emode,
                                if (ControlFile->minRecoveryPoint < EndRecPtr)
                                {
                                        ControlFile->minRecoveryPoint = EndRecPtr;
-                                       ControlFile->minRecoveryPointTLI = ThisTimeLineID;
+                                       ControlFile->minRecoveryPointTLI = replayTLI;
                                }
                                /* update local copy */
                                minRecoveryPoint = ControlFile->minRecoveryPoint;
@@ -4587,7 +4626,7 @@ ReadRecord(XLogReaderState *xlogreader, int emode,
  * one and returns 'true'.
  */
 static bool
-rescanLatestTimeLine(void)
+rescanLatestTimeLine(TimeLineID replayTLI)
 {
        List       *newExpectedTLEs;
        bool            found;
@@ -4629,7 +4668,7 @@ rescanLatestTimeLine(void)
                ereport(LOG,
                                (errmsg("new timeline %u is not a child of database system timeline %u",
                                                newtarget,
-                                               ThisTimeLineID)));
+                                               replayTLI)));
                return false;
        }
 
@@ -4643,7 +4682,7 @@ rescanLatestTimeLine(void)
                ereport(LOG,
                                (errmsg("new timeline %u forked off current database system timeline %u before current recovery point %X/%X",
                                                newtarget,
-                                               ThisTimeLineID,
+                                               replayTLI,
                                                LSN_FORMAT_ARGS(EndRecPtr))));
                return false;
        }
@@ -5337,9 +5376,6 @@ BootStrapXLOG(void)
        sysidentifier |= ((uint64) tv.tv_usec) << 12;
        sysidentifier |= getpid() & 0xFFF;
 
-       /* First timeline ID is always 1 */
-       ThisTimeLineID = 1;
-
        /* page buffer must be aligned suitably for O_DIRECT */
        buffer = (char *) palloc(XLOG_BLCKSZ + XLOG_BLCKSZ);
        page = (XLogPageHeader) TYPEALIGN(XLOG_BLCKSZ, buffer);
@@ -5353,8 +5389,8 @@ BootStrapXLOG(void)
         * used, so that we can use 0/0 to mean "before any valid WAL segment".
         */
        checkPoint.redo = wal_segment_size + SizeOfXLogLongPHD;
-       checkPoint.ThisTimeLineID = ThisTimeLineID;
-       checkPoint.PrevTimeLineID = ThisTimeLineID;
+       checkPoint.ThisTimeLineID = BootstrapTimeLineID;
+       checkPoint.PrevTimeLineID = BootstrapTimeLineID;
        checkPoint.fullPageWrites = fullPageWrites;
        checkPoint.nextXid =
                FullTransactionIdFromEpochAndXid(0, FirstNormalTransactionId);
@@ -5382,7 +5418,7 @@ BootStrapXLOG(void)
        /* Set up the XLOG page header */
        page->xlp_magic = XLOG_PAGE_MAGIC;
        page->xlp_info = XLP_LONG_HEADER;
-       page->xlp_tli = ThisTimeLineID;
+       page->xlp_tli = BootstrapTimeLineID;
        page->xlp_pageaddr = wal_segment_size;
        longpage = (XLogLongPageHeader) page;
        longpage->xlp_sysid = sysidentifier;
@@ -5412,7 +5448,8 @@ BootStrapXLOG(void)
        record->xl_crc = crc;
 
        /* Create first XLOG segment file */
-       openLogFile = XLogFileInit(1, ThisTimeLineID);
+       openLogTLI = BootstrapTimeLineID;
+       openLogFile = XLogFileInit(1, BootstrapTimeLineID);
 
        /*
         * We needn't bother with Reserve/ReleaseExternalFD here, since we'll
@@ -5656,14 +5693,14 @@ validateRecoveryParameters(void)
  * Exit archive-recovery state
  */
 static void
-exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog)
+exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog, TimeLineID newTLI)
 {
        char            xlogfname[MAXFNAMELEN];
        XLogSegNo       endLogSegNo;
        XLogSegNo       startLogSegNo;
 
        /* we always switch to a new timeline after archive recovery */
-       Assert(endTLI != ThisTimeLineID);
+       Assert(endTLI != newTLI);
 
        /*
         * We are no longer in archive recovery state.
@@ -5709,7 +5746,7 @@ exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog)
                 * considerations. But we should be just as tense as XLogFileInit to
                 * avoid emplacing a bogus file.
                 */
-               XLogFileCopy(endLogSegNo, endTLI, endLogSegNo,
+               XLogFileCopy(newTLI, endLogSegNo, endTLI, endLogSegNo,
                                         XLogSegmentOffset(endOfLog, wal_segment_size));
        }
        else
@@ -5720,15 +5757,14 @@ exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog)
                 */
                int                     fd;
 
-               fd = XLogFileInit(startLogSegNo, ThisTimeLineID);
+               fd = XLogFileInit(startLogSegNo, newTLI);
 
                if (close(fd) != 0)
                {
                        char            xlogfname[MAXFNAMELEN];
                        int                     save_errno = errno;
 
-                       XLogFileName(xlogfname, ThisTimeLineID, startLogSegNo,
-                                                wal_segment_size);
+                       XLogFileName(xlogfname, newTLI, startLogSegNo, wal_segment_size);
                        errno = save_errno;
                        ereport(ERROR,
                                        (errcode_for_file_access(),
@@ -5740,7 +5776,7 @@ exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog)
         * Let's just make real sure there are not .ready or .done flags posted
         * for the new segment.
         */
-       XLogFileName(xlogfname, ThisTimeLineID, startLogSegNo, wal_segment_size);
+       XLogFileName(xlogfname, newTLI, startLogSegNo, wal_segment_size);
        XLogArchiveCleanup(xlogfname);
 
        /*
@@ -5761,7 +5797,8 @@ exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog)
  * Perform cleanup actions at the conclusion of archive recovery.
  */
 static void
-CleanupAfterArchiveRecovery(TimeLineID EndOfLogTLI, XLogRecPtr EndOfLog)
+CleanupAfterArchiveRecovery(TimeLineID EndOfLogTLI, XLogRecPtr EndOfLog,
+                                                       TimeLineID newTLI)
 {
        /*
         * Execute the recovery_end_command, if any.
@@ -5779,7 +5816,7 @@ CleanupAfterArchiveRecovery(TimeLineID EndOfLogTLI, XLogRecPtr EndOfLog)
         * files containing garbage. In any case, they are not part of the new
         * timeline's history so we don't need them.
         */
-       RemoveNonParentXlogFiles(EndOfLog, ThisTimeLineID);
+       RemoveNonParentXlogFiles(EndOfLog, newTLI);
 
        /*
         * If the switch happened in the middle of a segment, what to do with the
@@ -6649,7 +6686,8 @@ StartupXLOG(void)
                                checkPointLoc,
                                EndOfLog;
        TimeLineID      EndOfLogTLI;
-       TimeLineID      PrevTimeLineID;
+       TimeLineID      ThisTimeLineID,
+                               PrevTimeLineID;
        XLogRecord *record;
        TransactionId oldestActiveXID;
        bool            backupEndRequired = false;
@@ -6844,7 +6882,7 @@ StartupXLOG(void)
        replay_image_masked = (char *) palloc(BLCKSZ);
        primary_image_masked = (char *) palloc(BLCKSZ);
 
-       if (read_backup_label(&checkPointLoc, &backupEndRequired,
+       if (read_backup_label(&checkPointLoc, &ThisTimeLineID, &backupEndRequired,
                                                  &backupFromStandby))
        {
                List       *tablespaces = NIL;
@@ -6862,7 +6900,8 @@ StartupXLOG(void)
                 * When a backup_label file is present, we want to roll forward from
                 * the checkpoint it identifies, rather than using pg_control.
                 */
-               record = ReadCheckpointRecord(xlogreader, checkPointLoc, 0, true);
+               record = ReadCheckpointRecord(xlogreader, checkPointLoc, 0, true,
+                                                                         ThisTimeLineID);
                if (record != NULL)
                {
                        memcpy(&checkPoint, XLogRecGetData(xlogreader), sizeof(CheckPoint));
@@ -6881,7 +6920,8 @@ StartupXLOG(void)
                        if (checkPoint.redo < checkPointLoc)
                        {
                                XLogBeginRead(xlogreader, checkPoint.redo);
-                               if (!ReadRecord(xlogreader, LOG, false))
+                               if (!ReadRecord(xlogreader, LOG, false,
+                                                               checkPoint.ThisTimeLineID))
                                        ereport(FATAL,
                                                        (errmsg("could not find redo location referenced by checkpoint record"),
                                                         errhint("If you are restoring from a backup, touch \"%s/recovery.signal\" and add required recovery options.\n"
@@ -6997,7 +7037,9 @@ StartupXLOG(void)
                /* Get the last valid checkpoint record. */
                checkPointLoc = ControlFile->checkPoint;
                RedoStartLSN = ControlFile->checkPointCopy.redo;
-               record = ReadCheckpointRecord(xlogreader, checkPointLoc, 1, true);
+               ThisTimeLineID = ControlFile->checkPointCopy.ThisTimeLineID;
+               record = ReadCheckpointRecord(xlogreader, checkPointLoc, 1, true,
+                                                                         ThisTimeLineID);
                if (record != NULL)
                {
                        ereport(DEBUG1,
@@ -7497,12 +7539,12 @@ StartupXLOG(void)
                {
                        /* back up to find the record */
                        XLogBeginRead(xlogreader, checkPoint.redo);
-                       record = ReadRecord(xlogreader, PANIC, false);
+                       record = ReadRecord(xlogreader, PANIC, false, ThisTimeLineID);
                }
                else
                {
                        /* just have to read next record after CheckPoint */
-                       record = ReadRecord(xlogreader, LOG, false);
+                       record = ReadRecord(xlogreader, LOG, false, ThisTimeLineID);
                }
 
                if (record != NULL)
@@ -7646,7 +7688,8 @@ StartupXLOG(void)
                                        if (newTLI != ThisTimeLineID)
                                        {
                                                /* Check that it's OK to switch to this TLI */
-                                               checkTimeLineSwitch(EndRecPtr, newTLI, prevTLI);
+                                               checkTimeLineSwitch(EndRecPtr, newTLI, prevTLI,
+                                                                                       ThisTimeLineID);
 
                                                /* Following WAL records should be run with new TLI */
                                                ThisTimeLineID = newTLI;
@@ -7738,7 +7781,7 @@ StartupXLOG(void)
                                }
 
                                /* Else, try to fetch the next WAL record */
-                               record = ReadRecord(xlogreader, LOG, false);
+                               record = ReadRecord(xlogreader, LOG, false, ThisTimeLineID);
                        } while (record != NULL);
 
                        /*
@@ -7862,7 +7905,7 @@ StartupXLOG(void)
         * what we consider the valid portion of WAL.
         */
        XLogBeginRead(xlogreader, LastRec);
-       record = ReadRecord(xlogreader, PANIC, false);
+       record = ReadRecord(xlogreader, PANIC, false, ThisTimeLineID);
        EndOfLog = EndRecPtr;
 
        /*
@@ -7959,7 +8002,7 @@ StartupXLOG(void)
                 * (Note that we also have a copy of the last block of the old WAL in
                 * readBuf; we will use that below.)
                 */
-               exitArchiveRecovery(EndOfLogTLI, EndOfLog);
+               exitArchiveRecovery(EndOfLogTLI, EndOfLog, ThisTimeLineID);
 
                /*
                 * Write the timeline history file, and have it archived. After this
@@ -8057,7 +8100,7 @@ StartupXLOG(void)
        /*
         * Preallocate additional log files, if wanted.
         */
-       PreallocXlogFiles(EndOfLog);
+       PreallocXlogFiles(EndOfLog, ThisTimeLineID);
 
        /*
         * Okay, we're officially UP.
@@ -8138,7 +8181,7 @@ StartupXLOG(void)
 
        /* If this is archive recovery, perform post-recovery cleanup actions. */
        if (ArchiveRecoveryRequested)
-               CleanupAfterArchiveRecovery(EndOfLogTLI, EndOfLog);
+               CleanupAfterArchiveRecovery(EndOfLogTLI, EndOfLog, ThisTimeLineID);
 
        /*
         * Local WAL inserts enabled, so it's time to finish initialization of
@@ -8526,7 +8569,7 @@ LocalSetXLogInsertAllowed(void)
  */
 static XLogRecord *
 ReadCheckpointRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr,
-                                        int whichChkpt, bool report)
+                                        int whichChkpt, bool report, TimeLineID replayTLI)
 {
        XLogRecord *record;
        uint8           info;
@@ -8551,7 +8594,7 @@ ReadCheckpointRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr,
        }
 
        XLogBeginRead(xlogreader, RecPtr);
-       record = ReadRecord(xlogreader, LOG, true);
+       record = ReadRecord(xlogreader, LOG, true, replayTLI);
 
        if (record == NULL)
        {
@@ -8624,21 +8667,13 @@ ReadCheckpointRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr,
 /*
  * This must be called in a backend process before creating WAL records
  * (except in a standalone backend, which does StartupXLOG instead).  We need
- * to initialize the local copies of ThisTimeLineID and RedoRecPtr.
- *
- * Note: before Postgres 8.0, we went to some effort to keep the postmaster
- * process's copies of ThisTimeLineID and RedoRecPtr valid too.  This was
- * unnecessary however, since the postmaster itself never touches XLOG anyway.
+ * to initialize the local copy of RedoRecPtr.
  */
 void
 InitXLOGAccess(void)
 {
        XLogCtlInsert *Insert = &XLogCtl->Insert;
 
-       /* ThisTimeLineID doesn't change so we need no lock to copy it */
-       ThisTimeLineID = XLogCtl->ThisTimeLineID;
-       Assert(ThisTimeLineID != 0 || IsBootstrapProcessingMode());
-
        /* set wal_segment_size */
        wal_segment_size = ControlFile->xlog_seg_size;
 
@@ -9184,17 +9219,16 @@ CreateCheckPoint(int flags)
        /*
         * An end-of-recovery checkpoint is created before anyone is allowed to
         * write WAL. To allow us to write the checkpoint record, temporarily
-        * enable XLogInsertAllowed.  (This also ensures ThisTimeLineID is
-        * initialized, which we need here and in AdvanceXLInsertBuffer.)
+        * enable XLogInsertAllowed.
         */
        if (flags & CHECKPOINT_END_OF_RECOVERY)
                oldXLogAllowed = LocalSetXLogInsertAllowed();
 
-       checkPoint.ThisTimeLineID = ThisTimeLineID;
+       checkPoint.ThisTimeLineID = XLogCtl->ThisTimeLineID;
        if (flags & CHECKPOINT_END_OF_RECOVERY)
                checkPoint.PrevTimeLineID = XLogCtl->PrevTimeLineID;
        else
-               checkPoint.PrevTimeLineID = ThisTimeLineID;
+               checkPoint.PrevTimeLineID = checkPoint.ThisTimeLineID;
 
        checkPoint.fullPageWrites = Insert->fullPageWrites;
 
@@ -9451,14 +9485,15 @@ CreateCheckPoint(int flags)
                KeepLogSeg(recptr, &_logSegNo);
        }
        _logSegNo--;
-       RemoveOldXlogFiles(_logSegNo, RedoRecPtr, recptr);
+       RemoveOldXlogFiles(_logSegNo, RedoRecPtr, recptr,
+                                          checkPoint.ThisTimeLineID);
 
        /*
         * Make more log segments if needed.  (Do this after recycling old log
         * segments, since that may supply some of the needed files.)
         */
        if (!shutdown)
-               PreallocXlogFiles(recptr);
+               PreallocXlogFiles(recptr, checkPoint.ThisTimeLineID);
 
        /*
         * Truncate pg_subtrans if possible.  We can throw away all data before
@@ -9504,7 +9539,7 @@ CreateEndOfRecoveryRecord(void)
        xlrec.end_time = GetCurrentTimestamp();
 
        WALInsertLockAcquireExclusive();
-       xlrec.ThisTimeLineID = ThisTimeLineID;
+       xlrec.ThisTimeLineID = XLogCtl->ThisTimeLineID;
        xlrec.PrevTimeLineID = XLogCtl->PrevTimeLineID;
        WALInsertLockRelease();
 
@@ -9523,7 +9558,7 @@ CreateEndOfRecoveryRecord(void)
        LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
        ControlFile->time = (pg_time_t) time(NULL);
        ControlFile->minRecoveryPoint = recptr;
-       ControlFile->minRecoveryPointTLI = ThisTimeLineID;
+       ControlFile->minRecoveryPointTLI = xlrec.ThisTimeLineID;
        UpdateControlFile();
        LWLockRelease(ControlFileLock);
 
@@ -9846,9 +9881,8 @@ CreateRestartPoint(int flags)
        /*
         * Try to recycle segments on a useful timeline. If we've been promoted
         * since the beginning of this restartpoint, use the new timeline chosen
-        * at end of recovery (RecoveryInProgress() sets ThisTimeLineID in that
-        * case). If we're still in recovery, use the timeline we're currently
-        * replaying.
+        * at end of recovery.  If we're still in recovery, use the timeline we're
+        * currently replaying.
         *
         * There is no guarantee that the WAL segments will be useful on the
         * current timeline; if recovery proceeds to a new timeline right after
@@ -9856,25 +9890,16 @@ CreateRestartPoint(int flags)
         * and will go wasted until recycled on the next restartpoint. We'll live
         * with that.
         */
-       if (RecoveryInProgress())
-               ThisTimeLineID = replayTLI;
+       if (!RecoveryInProgress())
+               replayTLI = XLogCtl->ThisTimeLineID;
 
-       RemoveOldXlogFiles(_logSegNo, RedoRecPtr, endptr);
+       RemoveOldXlogFiles(_logSegNo, RedoRecPtr, endptr, replayTLI);
 
        /*
         * Make more log segments if needed.  (Do this after recycling old log
         * segments, since that may supply some of the needed files.)
         */
-       PreallocXlogFiles(endptr);
-
-       /*
-        * ThisTimeLineID is normally not set when we're still in recovery.
-        * However, recycling/preallocating segments above needed ThisTimeLineID
-        * to determine which timeline to install the segments on. Reset it now,
-        * to restore the normal state of affairs for debugging purposes.
-        */
-       if (RecoveryInProgress())
-               ThisTimeLineID = 0;
+       PreallocXlogFiles(endptr, replayTLI);
 
        /*
         * Truncate pg_subtrans if possible.  We can throw away all data before
@@ -10282,22 +10307,23 @@ UpdateFullPageWrites(void)
  * replay. (Currently, timeline can only change at a shutdown checkpoint).
  */
 static void
-checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI, TimeLineID prevTLI)
+checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI, TimeLineID prevTLI,
+                                       TimeLineID replayTLI)
 {
        /* Check that the record agrees on what the current (old) timeline is */
-       if (prevTLI != ThisTimeLineID)
+       if (prevTLI != replayTLI)
                ereport(PANIC,
                                (errmsg("unexpected previous timeline ID %u (current timeline ID %u) in checkpoint record",
-                                               prevTLI, ThisTimeLineID)));
+                                               prevTLI, replayTLI)));
 
        /*
         * The new timeline better be in the list of timelines we expect to see,
         * according to the timeline history. It should also not decrease.
         */
-       if (newTLI < ThisTimeLineID || !tliInHistory(newTLI, expectedTLEs))
+       if (newTLI < replayTLI || !tliInHistory(newTLI, expectedTLEs))
                ereport(PANIC,
                                (errmsg("unexpected timeline ID %u (after %u) in checkpoint record",
-                                               newTLI, ThisTimeLineID)));
+                                               newTLI, replayTLI)));
 
        /*
         * If we have not yet reached min recovery point, and we're about to
@@ -10331,6 +10357,10 @@ xlog_redo(XLogReaderState *record)
 {
        uint8           info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
        XLogRecPtr      lsn = record->EndRecPtr;
+       TimeLineID      replayTLI;
+
+       /* No other process can change this, so we can read it without a lock. */
+       replayTLI = XLogCtl->replayEndTLI;
 
        /*
         * In XLOG rmgr, backup blocks are only used by XLOG_FPI and
@@ -10444,10 +10474,10 @@ xlog_redo(XLogReaderState *record)
                 * We should've already switched to the new TLI before replaying this
                 * record.
                 */
-               if (checkPoint.ThisTimeLineID != ThisTimeLineID)
+               if (checkPoint.ThisTimeLineID != replayTLI)
                        ereport(PANIC,
                                        (errmsg("unexpected timeline ID %u (should be %u) in checkpoint record",
-                                                       checkPoint.ThisTimeLineID, ThisTimeLineID)));
+                                                       checkPoint.ThisTimeLineID, replayTLI)));
 
                RecoveryRestartPoint(&checkPoint);
        }
@@ -10500,10 +10530,10 @@ xlog_redo(XLogReaderState *record)
                SpinLockRelease(&XLogCtl->info_lck);
 
                /* TLI should not change in an on-line checkpoint */
-               if (checkPoint.ThisTimeLineID != ThisTimeLineID)
+               if (checkPoint.ThisTimeLineID != replayTLI)
                        ereport(PANIC,
                                        (errmsg("unexpected timeline ID %u (should be %u) in checkpoint record",
-                                                       checkPoint.ThisTimeLineID, ThisTimeLineID)));
+                                                       checkPoint.ThisTimeLineID, replayTLI)));
 
                RecoveryRestartPoint(&checkPoint);
        }
@@ -10530,10 +10560,10 @@ xlog_redo(XLogReaderState *record)
                 * We should've already switched to the new TLI before replaying this
                 * record.
                 */
-               if (xlrec.ThisTimeLineID != ThisTimeLineID)
+               if (xlrec.ThisTimeLineID != replayTLI)
                        ereport(PANIC,
                                        (errmsg("unexpected timeline ID %u (should be %u) in checkpoint record",
-                                                       xlrec.ThisTimeLineID, ThisTimeLineID)));
+                                                       xlrec.ThisTimeLineID, replayTLI)));
        }
        else if (info == XLOG_NOOP)
        {
@@ -10603,7 +10633,7 @@ xlog_redo(XLogReaderState *record)
                        if (ControlFile->minRecoveryPoint < lsn)
                        {
                                ControlFile->minRecoveryPoint = lsn;
-                               ControlFile->minRecoveryPointTLI = ThisTimeLineID;
+                               ControlFile->minRecoveryPointTLI = replayTLI;
                        }
                        ControlFile->backupStartPoint = InvalidXLogRecPtr;
                        ControlFile->backupEndRequired = false;
@@ -10644,7 +10674,7 @@ xlog_redo(XLogReaderState *record)
                if (minRecoveryPoint != InvalidXLogRecPtr && minRecoveryPoint < lsn)
                {
                        ControlFile->minRecoveryPoint = lsn;
-                       ControlFile->minRecoveryPointTLI = ThisTimeLineID;
+                       ControlFile->minRecoveryPointTLI = replayTLI;
                }
 
                CommitTsParameterChange(xlrec.track_commit_timestamp,
@@ -10857,7 +10887,7 @@ assign_xlog_sync_method(int new_sync_method, void *extra)
                                int                     save_errno;
 
                                save_errno = errno;
-                               XLogFileName(xlogfname, ThisTimeLineID, openLogSegNo,
+                               XLogFileName(xlogfname, openLogTLI, openLogSegNo,
                                                         wal_segment_size);
                                errno = save_errno;
                                ereport(PANIC,
@@ -11779,7 +11809,12 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
                XLogBeginInsert();
                XLogRegisterData((char *) (&startpoint), sizeof(startpoint));
                stoppoint = XLogInsert(RM_XLOG_ID, XLOG_BACKUP_END);
-               stoptli = ThisTimeLineID;
+
+               /*
+                * Given that we're not in recovery, ThisTimeLineID is set and can't
+                * change, so we can read it without a lock.
+                */
+               stoptli = XLogCtl->ThisTimeLineID;
 
                /*
                 * Force a switch to a new xlog segment file, so that the backup is
@@ -12050,14 +12085,17 @@ GetOldestRestartPoint(XLogRecPtr *oldrecptr, TimeLineID *oldtli)
  * point, we will fail to restore a consistent database state.
  *
  * Returns true if a backup_label was found (and fills the checkpoint
- * location and its REDO location into *checkPointLoc and RedoStartLSN,
- * respectively); returns false if not. If this backup_label came from a
- * streamed backup, *backupEndRequired is set to true. If this backup_label
- * was created during recovery, *backupFromStandby is set to true.
+ * location and TLI into *checkPointLoc and *backupLabelTLI, respectively);
+ * returns false if not. If this backup_label came from a streamed backup,
+ * *backupEndRequired is set to true. If this backup_label was created during
+ * recovery, *backupFromStandby is set to true.
+ *
+ * Also sets the global variable RedoStartLSN with the LSN read from the
+ * backup file.
  */
 static bool
-read_backup_label(XLogRecPtr *checkPointLoc, bool *backupEndRequired,
-                                 bool *backupFromStandby)
+read_backup_label(XLogRecPtr *checkPointLoc, TimeLineID *backupLabelTLI,
+                                 bool *backupEndRequired, bool *backupFromStandby)
 {
        char            startxlogfilename[MAXFNAMELEN];
        TimeLineID      tli_from_walseg,
@@ -12166,6 +12204,8 @@ read_backup_label(XLogRecPtr *checkPointLoc, bool *backupEndRequired,
                                 errmsg("could not read file \"%s\": %m",
                                                BACKUP_LABEL_FILE)));
 
+       *backupLabelTLI = tli_from_walseg;
+
        return true;
 }
 
@@ -12442,7 +12482,8 @@ retry:
                if (!WaitForWALToBecomeAvailable(targetPagePtr + reqLen,
                                                                                 private->randAccess,
                                                                                 private->fetching_ckpt,
-                                                                                targetRecPtr))
+                                                                                targetRecPtr,
+                                                                                private->replayTLI))
                {
                        if (readFile >= 0)
                                close(readFile);
@@ -12606,7 +12647,8 @@ next_record_is_invalid:
  */
 static bool
 WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
-                                                       bool fetching_ckpt, XLogRecPtr tliRecPtr)
+                                                       bool fetching_ckpt, XLogRecPtr tliRecPtr,
+                                                       TimeLineID replayTLI)
 {
        static TimestampTz last_fail_time = 0;
        TimestampTz now;
@@ -12729,7 +12771,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
                                         */
                                        if (recoveryTargetTimeLineGoal == RECOVERY_TARGET_TIMELINE_LATEST)
                                        {
-                                               if (rescanLatestTimeLine())
+                                               if (rescanLatestTimeLine(replayTLI))
                                                {
                                                        currentSource = XLOG_FROM_ARCHIVE;
                                                        break;
@@ -12856,7 +12898,7 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
                                                 */
                                                if (recoveryTargetTimeLineGoal ==
                                                        RECOVERY_TARGET_TIMELINE_LATEST)
-                                                       rescanLatestTimeLine();
+                                                       rescanLatestTimeLine(replayTLI);
 
                                                startWalReceiver = true;
                                        }
index f188c41bedf318b579965bc181ab812705a56a59..898df2ee034307c86c77d7a7a59145e972ce2319 100644 (file)
@@ -261,7 +261,7 @@ extern void XLogFlush(XLogRecPtr RecPtr);
 extern bool XLogBackgroundFlush(void);
 extern bool XLogNeedsFlush(XLogRecPtr RecPtr);
 extern int     XLogFileInit(XLogSegNo segno, TimeLineID tli);
-extern int     XLogFileOpen(XLogSegNo segno);
+extern int     XLogFileOpen(XLogSegNo segno, TimeLineID tli);
 
 extern void CheckXLogRemoved(XLogSegNo segno, TimeLineID tli);
 extern XLogSegNo XLogGetLastRemovedSegno(void);