aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/transam/xlog.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/transam/xlog.c')
-rw-r--r--src/backend/access/transam/xlog.c340
1 files changed, 191 insertions, 149 deletions
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 9b15735921b..7b1b3e802bb 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -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;
}