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);
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);
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);
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 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);
* inserted. Copy the record in the space reserved.
*/
CopyXLogRecordToWAL(rechdr->xl_tot_len, isLogSwitch, rdata,
- StartPos, EndPos);
+ StartPos, EndPos, ThisTimeLineID);
/*
* Unless record is flagged as not important, update LSN of last
*/
static void
CopyXLogRecordToWAL(int write_len, bool isLogSwitch, XLogRecData *rdata,
- XLogRecPtr StartPos, XLogRecPtr EndPos)
+ XLogRecPtr StartPos, XLogRecPtr EndPos, TimeLineID tli)
{
char *currpos;
int freespace;
* inserting to.
*/
CurrPos = StartPos;
- currpos = GetXLogBuffer(CurrPos);
+ currpos = GetXLogBuffer(CurrPos, tli);
freespace = INSERT_FREESPACE(CurrPos);
/*
* 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;
* (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;
* later, because older buffers might be recycled already)
*/
static char *
-GetXLogBuffer(XLogRecPtr ptr)
+GetXLogBuffer(XLogRecPtr ptr, TimeLineID tli)
{
int idx;
XLogRecPtr endptr;
WALInsertLockUpdateInsertingAt(initializedUpto);
- AdvanceXLInsertBuffer(ptr, false);
+ AdvanceXLInsertBuffer(ptr, tli, false);
endptr = XLogCtl->xlblocks[idx];
if (expectedEndPtr != endptr)
* initialized properly.
*/
static void
-AdvanceXLInsertBuffer(XLogRecPtr upto, bool opportunistic)
+AdvanceXLInsertBuffer(XLogRecPtr upto, TimeLineID tli, bool opportunistic)
{
XLogCtlInsert *Insert = &XLogCtl->Insert;
int nextidx;
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();
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 */
* write.
*/
static void
-XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
+XLogWrite(XLogwrtRqst WriteRqst, TimeLineID tli, bool flexible)
{
bool ispartialpage;
bool last_iteration;
wal_segment_size);
/* create/use new log file */
- openLogFile = XLogFileInit(openLogSegNo, ThisTimeLineID);
+ openLogFile = XLogFileInit(openLogSegNo, tli);
ReserveExternalFD();
}
{
XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo,
wal_segment_size);
- openLogFile = XLogFileOpen(openLogSegNo);
+ openLogFile = XLogFileOpen(openLogSegNo, tli);
ReserveExternalFD();
}
continue;
save_errno = errno;
- XLogFileName(xlogfname, ThisTimeLineID, openLogSegNo,
+ XLogFileName(xlogfname, tli, openLogSegNo,
wal_segment_size);
errno = save_errno;
ereport(PANIC,
*/
if (finishing_seg)
{
- issue_xlog_fsync(openLogFile, openLogSegNo, ThisTimeLineID);
+ issue_xlog_fsync(openLogFile, openLogSegNo, tli);
/* signal that we need to wakeup walsenders later */
WalSndWakeupRequest();
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;
{
XLByteToPrevSeg(LogwrtResult.Write, openLogSegNo,
wal_segment_size);
- openLogFile = XLogFileOpen(openLogSegNo);
+ 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 */
WriteRqst.Write = insertpos;
WriteRqst.Flush = insertpos;
- XLogWrite(WriteRqst, false);
+ XLogWrite(WriteRqst, ThisTimeLineID, false);
LWLockRelease(WALWriteLock);
/* done */
if (WriteRqst.Write > LogwrtResult.Write ||
WriteRqst.Flush > LogwrtResult.Flush)
{
- XLogWrite(WriteRqst, flexible);
+ XLogWrite(WriteRqst, ThisTimeLineID, flexible);
}
LWLockRelease(WALWriteLock);
* 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, ThisTimeLineID, true);
/*
* If we determined that we need to write data, but somebody else
* 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];
/*
* 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");
}
* 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)
* reporting and resource reclamation.)
*/
static void
-PreallocXlogFiles(XLogRecPtr endptr)
+PreallocXlogFiles(XLogRecPtr endptr, TimeLineID tli)
{
XLogSegNo _logSegNo;
int lf;
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)
* 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;
/* 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);
}
}
}
* - 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);
}
}
*
* 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
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\"",
* 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.
* 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
*/
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(),
* 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);
/*
* 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.
* 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
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;
* (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
/*
* Preallocate additional log files, if wanted.
*/
- PreallocXlogFiles(EndOfLog);
+ PreallocXlogFiles(EndOfLog, ThisTimeLineID);
/*
* Okay, we're officially UP.
/* 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
KeepLogSeg(recptr, &_logSegNo);
}
_logSegNo--;
- RemoveOldXlogFiles(_logSegNo, RedoRecPtr, recptr);
+ RemoveOldXlogFiles(_logSegNo, RedoRecPtr, recptr, 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, ThisTimeLineID);
/*
* Truncate pg_subtrans if possible. We can throw away all data before
if (RecoveryInProgress())
ThisTimeLineID = replayTLI;
- RemoveOldXlogFiles(_logSegNo, RedoRecPtr, endptr);
+ RemoveOldXlogFiles(_logSegNo, RedoRecPtr, endptr, ThisTimeLineID);
/*
* Make more log segments if needed. (Do this after recycling old log
* segments, since that may supply some of the needed files.)
*/
- PreallocXlogFiles(endptr);
+ PreallocXlogFiles(endptr, ThisTimeLineID);
/*
* ThisTimeLineID is normally not set when we're still in recovery.
* 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