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);