From c95e8c57a6e3a187a5b5c538e2fdc1e9d4d7cede Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Mon, 18 Oct 2021 16:28:18 -0400 Subject: [PATCH 1/2] Test code to see whether we have always properly initialized ThisTimeLineID. --- src/backend/access/transam/twophase.c | 4 +- src/backend/access/transam/xlog.c | 108 ++++++++++-------- src/backend/access/transam/xlogarchive.c | 2 +- src/backend/access/transam/xlogfuncs.c | 4 +- src/backend/access/transam/xlogutils.c | 13 ++- src/backend/replication/basebackup.c | 12 +- .../replication/logical/logicalfuncs.c | 4 + src/backend/replication/slotfuncs.c | 4 + src/backend/replication/walreceiver.c | 5 +- src/backend/replication/walsender.c | 19 +-- src/include/access/xlog.h | 4 + 11 files changed, 105 insertions(+), 74 deletions(-) diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c index 2156de187c..43cab819da 100644 --- a/src/backend/access/transam/twophase.c +++ b/src/backend/access/transam/twophase.c @@ -1328,7 +1328,8 @@ XlogReadTwoPhaseData(XLogRecPtr lsn, char **buf, int *len) XLogRecord *record; XLogReaderState *xlogreader; char *errormsg; - TimeLineID save_currtli = ThisTimeLineID; + TimeLineID save_currtli = ThisTimeLineID; // XXX ThisTimeLineIDChecked fails assertion, ThisTimeLineID = 0!!! + bool save_currtli_valid = ThisTimeLineIDValid; xlogreader = XLogReaderAllocate(wal_segment_size, NULL, XL_ROUTINE(.page_read = &read_local_xlog_page, @@ -1350,6 +1351,7 @@ XlogReadTwoPhaseData(XLogRecPtr lsn, char **buf, int *len) * while recovery was finishing or if the timeline has jumped in-between. */ ThisTimeLineID = save_currtli; + ThisTimeLineIDValid = save_currtli_valid; if (record == NULL) ereport(ERROR, diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 62862255fc..5f1e6d360f 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -192,6 +192,7 @@ CheckpointStatsData CheckpointStats; * WAL timeline for the database system. */ TimeLineID ThisTimeLineID = 0; +bool ThisTimeLineIDValid = false; static XLogRecPtr LastRec; @@ -2240,7 +2241,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 = ThisTimeLineIDChecked; NewPage->xlp_pageaddr = NewPageBeginPtr; /* NewPage->xlp_rem_len = 0; */ /* done by memset */ @@ -2590,7 +2591,7 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible) continue; save_errno = errno; - XLogFileName(xlogfname, ThisTimeLineID, openLogSegNo, + XLogFileName(xlogfname, ThisTimeLineIDChecked, openLogSegNo, wal_segment_size); errno = save_errno; ereport(PANIC, @@ -3293,7 +3294,7 @@ XLogFileInitInternal(XLogSegNo logsegno, bool *added, char *path) int fd; int save_errno; - XLogFilePath(path, ThisTimeLineID, logsegno, wal_segment_size); + XLogFilePath(path, ThisTimeLineIDChecked, logsegno, wal_segment_size); /* * Try to use existent file (checkpoint maker may have created it already) @@ -3652,7 +3653,7 @@ InstallXLogFileSegment(XLogSegNo *segno, char *tmppath, char path[MAXPGPATH]; struct stat stat_buf; - XLogFilePath(path, ThisTimeLineID, *segno, wal_segment_size); + XLogFilePath(path, ThisTimeLineIDChecked, *segno, wal_segment_size); LWLockAcquire(ControlFileLock, LW_EXCLUSIVE); if (!XLogCtl->InstallXLogFileSegmentActive) @@ -3678,7 +3679,7 @@ InstallXLogFileSegment(XLogSegNo *segno, char *tmppath, return false; } (*segno)++; - XLogFilePath(path, ThisTimeLineID, *segno, wal_segment_size); + XLogFilePath(path, ThisTimeLineIDChecked, *segno, wal_segment_size); } } @@ -3707,7 +3708,7 @@ XLogFileOpen(XLogSegNo segno) char path[MAXPGPATH]; int fd; - XLogFilePath(path, ThisTimeLineID, segno, wal_segment_size); + XLogFilePath(path, ThisTimeLineIDChecked, segno, wal_segment_size); fd = BasicOpenFile(path, O_RDWR | PG_BINARY | get_sync_bit(sync_method)); if (fd < 0) @@ -3928,7 +3929,7 @@ XLogFileClose(void) char xlogfname[MAXFNAMELEN]; int save_errno = errno; - XLogFileName(xlogfname, ThisTimeLineID, openLogSegNo, wal_segment_size); + XLogFileName(xlogfname, ThisTimeLineIDChecked, openLogSegNo, wal_segment_size); errno = save_errno; ereport(PANIC, (errcode_for_file_access(), @@ -4510,7 +4511,7 @@ ReadRecord(XLogReaderState *xlogreader, int emode, if (ControlFile->minRecoveryPoint < EndRecPtr) { ControlFile->minRecoveryPoint = EndRecPtr; - ControlFile->minRecoveryPointTLI = ThisTimeLineID; + ControlFile->minRecoveryPointTLI = ThisTimeLineIDChecked; } /* update local copy */ minRecoveryPoint = ControlFile->minRecoveryPoint; @@ -4606,7 +4607,7 @@ rescanLatestTimeLine(void) ereport(LOG, (errmsg("new timeline %u is not a child of database system timeline %u", newtarget, - ThisTimeLineID))); + ThisTimeLineIDChecked))); return false; } @@ -4620,7 +4621,7 @@ rescanLatestTimeLine(void) ereport(LOG, (errmsg("new timeline %u forked off current database system timeline %u before current recovery point %X/%X", newtarget, - ThisTimeLineID, + ThisTimeLineIDChecked, LSN_FORMAT_ARGS(EndRecPtr)))); return false; } @@ -5316,6 +5317,7 @@ BootStrapXLOG(void) /* First timeline ID is always 1 */ ThisTimeLineID = 1; + ThisTimeLineIDValid = true; /* page buffer must be aligned suitably for O_DIRECT */ buffer = (char *) palloc(XLOG_BLCKSZ + XLOG_BLCKSZ); @@ -5330,8 +5332,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 = ThisTimeLineIDChecked; + checkPoint.PrevTimeLineID = ThisTimeLineIDChecked; checkPoint.fullPageWrites = fullPageWrites; checkPoint.nextXid = FullTransactionIdFromEpochAndXid(0, FirstNormalTransactionId); @@ -5359,7 +5361,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 = ThisTimeLineIDChecked; page->xlp_pageaddr = wal_segment_size; longpage = (XLogLongPageHeader) page; longpage->xlp_sysid = sysidentifier; @@ -5640,7 +5642,7 @@ exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog) XLogSegNo startLogSegNo; /* we always switch to a new timeline after archive recovery */ - Assert(endTLI != ThisTimeLineID); + Assert(endTLI != ThisTimeLineIDChecked); /* * We are no longer in archive recovery state. @@ -5704,7 +5706,7 @@ exitArchiveRecovery(TimeLineID endTLI, XLogRecPtr endOfLog) char xlogfname[MAXFNAMELEN]; int save_errno = errno; - XLogFileName(xlogfname, ThisTimeLineID, startLogSegNo, + XLogFileName(xlogfname, ThisTimeLineIDChecked, startLogSegNo, wal_segment_size); errno = save_errno; ereport(ERROR, @@ -5717,7 +5719,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, ThisTimeLineIDChecked, startLogSegNo, wal_segment_size); XLogArchiveCleanup(xlogfname); /* @@ -5756,7 +5758,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, ThisTimeLineIDChecked); /* * If the switch happened in the middle of a segment, what to do with the @@ -7137,6 +7139,7 @@ StartupXLOG(void) * also xlog_redo()). */ ThisTimeLineID = checkPoint.ThisTimeLineID; + ThisTimeLineIDValid = true; /* * Copy any missing timeline history files between 'now' and the recovery @@ -7150,7 +7153,7 @@ StartupXLOG(void) * are small, so it's better to copy them unnecessarily than not copy them * and regret later. */ - restoreTimeLineHistoryFiles(ThisTimeLineID, recoveryTargetTLI); + restoreTimeLineHistoryFiles(ThisTimeLineIDChecked, recoveryTargetTLI); /* * Before running in recovery, scan pg_twophase and fill in its status to @@ -7434,7 +7437,7 @@ StartupXLOG(void) XLogCtl->replayEndRecPtr = checkPoint.redo; else XLogCtl->replayEndRecPtr = EndRecPtr; - XLogCtl->replayEndTLI = ThisTimeLineID; + XLogCtl->replayEndTLI = ThisTimeLineIDChecked; XLogCtl->lastReplayedEndRecPtr = XLogCtl->replayEndRecPtr; XLogCtl->lastReplayedTLI = XLogCtl->replayEndTLI; XLogCtl->recoveryLastXTime = 0; @@ -7586,8 +7589,8 @@ StartupXLOG(void) */ if (record->xl_rmid == RM_XLOG_ID) { - TimeLineID newTLI = ThisTimeLineID; - TimeLineID prevTLI = ThisTimeLineID; + TimeLineID newTLI = ThisTimeLineIDChecked; + TimeLineID prevTLI = ThisTimeLineIDChecked; uint8 info = record->xl_info & ~XLR_INFO_MASK; if (info == XLOG_CHECKPOINT_SHUTDOWN) @@ -7607,13 +7610,14 @@ StartupXLOG(void) prevTLI = xlrec.PrevTimeLineID; } - if (newTLI != ThisTimeLineID) + if (newTLI != ThisTimeLineIDChecked) { /* Check that it's OK to switch to this TLI */ checkTimeLineSwitch(EndRecPtr, newTLI, prevTLI); /* Following WAL records should be run with new TLI */ ThisTimeLineID = newTLI; + ThisTimeLineIDValid = true; switchedTLI = true; } } @@ -7624,7 +7628,7 @@ StartupXLOG(void) */ SpinLockAcquire(&XLogCtl->info_lck); XLogCtl->replayEndRecPtr = EndRecPtr; - XLogCtl->replayEndTLI = ThisTimeLineID; + XLogCtl->replayEndTLI = ThisTimeLineIDChecked; SpinLockRelease(&XLogCtl->info_lck); /* @@ -7656,7 +7660,7 @@ StartupXLOG(void) */ SpinLockAcquire(&XLogCtl->info_lck); XLogCtl->lastReplayedEndRecPtr = EndRecPtr; - XLogCtl->lastReplayedTLI = ThisTimeLineID; + XLogCtl->lastReplayedTLI = ThisTimeLineIDChecked; SpinLockRelease(&XLogCtl->info_lck); /* @@ -7684,7 +7688,7 @@ StartupXLOG(void) * (possibly bogus) future WAL segments on the old * timeline. */ - RemoveNonParentXlogFiles(EndRecPtr, ThisTimeLineID); + RemoveNonParentXlogFiles(EndRecPtr, ThisTimeLineIDChecked); /* * Wake up any walsenders to notice that we are on a new @@ -7903,7 +7907,7 @@ StartupXLOG(void) * * In a normal crash recovery, we can just extend the timeline we were in. */ - PrevTimeLineID = ThisTimeLineID; + PrevTimeLineID = ThisTimeLineIDChecked; if (ArchiveRecoveryRequested) { char *reason; @@ -7912,8 +7916,9 @@ StartupXLOG(void) Assert(InArchiveRecovery); ThisTimeLineID = findNewestTimeLine(recoveryTargetTLI) + 1; + ThisTimeLineIDValid = true; ereport(LOG, - (errmsg("selected new timeline ID: %u", ThisTimeLineID))); + (errmsg("selected new timeline ID: %u", ThisTimeLineIDChecked))); reason = getRecoveryStopReason(); @@ -7935,7 +7940,7 @@ StartupXLOG(void) * To minimize the window for that, try to do as little as possible * between here and writing the end-of-recovery record. */ - writeTimeLineHistory(ThisTimeLineID, recoveryTargetTLI, + writeTimeLineHistory(ThisTimeLineIDChecked, recoveryTargetTLI, EndRecPtr, reason); /* @@ -7951,7 +7956,7 @@ StartupXLOG(void) } /* Save the selected TimeLineID in shared memory, too */ - XLogCtl->ThisTimeLineID = ThisTimeLineID; + XLogCtl->ThisTimeLineID = ThisTimeLineIDChecked; XLogCtl->PrevTimeLineID = PrevTimeLineID; /* @@ -8597,6 +8602,7 @@ InitXLOGAccess(void) /* ThisTimeLineID doesn't change so we need no lock to copy it */ ThisTimeLineID = XLogCtl->ThisTimeLineID; + ThisTimeLineIDValid = true; Assert(ThisTimeLineID != 0 || IsBootstrapProcessingMode()); /* set wal_segment_size */ @@ -9129,11 +9135,11 @@ CreateCheckPoint(int flags) if (flags & CHECKPOINT_END_OF_RECOVERY) LocalSetXLogInsertAllowed(); - checkPoint.ThisTimeLineID = ThisTimeLineID; + checkPoint.ThisTimeLineID = ThisTimeLineIDChecked; if (flags & CHECKPOINT_END_OF_RECOVERY) checkPoint.PrevTimeLineID = XLogCtl->PrevTimeLineID; else - checkPoint.PrevTimeLineID = ThisTimeLineID; + checkPoint.PrevTimeLineID = ThisTimeLineIDChecked; checkPoint.fullPageWrites = Insert->fullPageWrites; @@ -9443,7 +9449,7 @@ CreateEndOfRecoveryRecord(void) xlrec.end_time = GetCurrentTimestamp(); WALInsertLockAcquireExclusive(); - xlrec.ThisTimeLineID = ThisTimeLineID; + xlrec.ThisTimeLineID = ThisTimeLineIDChecked; xlrec.PrevTimeLineID = XLogCtl->PrevTimeLineID; WALInsertLockRelease(); @@ -9464,7 +9470,7 @@ CreateEndOfRecoveryRecord(void) LWLockAcquire(ControlFileLock, LW_EXCLUSIVE); ControlFile->time = (pg_time_t) time(NULL); ControlFile->minRecoveryPoint = recptr; - ControlFile->minRecoveryPointTLI = ThisTimeLineID; + ControlFile->minRecoveryPointTLI = ThisTimeLineIDChecked; UpdateControlFile(); LWLockRelease(ControlFileLock); @@ -9800,7 +9806,10 @@ CreateRestartPoint(int flags) * with that. */ if (RecoveryInProgress()) + { ThisTimeLineID = replayTLI; + ThisTimeLineIDValid = true; + } RemoveOldXlogFiles(_logSegNo, RedoRecPtr, endptr); @@ -9817,7 +9826,10 @@ CreateRestartPoint(int flags) * to restore the normal state of affairs for debugging purposes. */ if (RecoveryInProgress()) + { ThisTimeLineID = 0; + ThisTimeLineIDValid = false; + } /* * Truncate pg_subtrans if possible. We can throw away all data before @@ -10228,19 +10240,19 @@ static void checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI, TimeLineID prevTLI) { /* Check that the record agrees on what the current (old) timeline is */ - if (prevTLI != ThisTimeLineID) + if (prevTLI != ThisTimeLineIDChecked) ereport(PANIC, (errmsg("unexpected previous timeline ID %u (current timeline ID %u) in checkpoint record", - prevTLI, ThisTimeLineID))); + prevTLI, ThisTimeLineIDChecked))); /* * 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 < ThisTimeLineIDChecked || !tliInHistory(newTLI, expectedTLEs)) ereport(PANIC, (errmsg("unexpected timeline ID %u (after %u) in checkpoint record", - newTLI, ThisTimeLineID))); + newTLI, ThisTimeLineIDChecked))); /* * If we have not yet reached min recovery point, and we're about to @@ -10387,10 +10399,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 != ThisTimeLineIDChecked) ereport(PANIC, (errmsg("unexpected timeline ID %u (should be %u) in checkpoint record", - checkPoint.ThisTimeLineID, ThisTimeLineID))); + checkPoint.ThisTimeLineID, ThisTimeLineIDChecked))); RecoveryRestartPoint(&checkPoint); } @@ -10443,10 +10455,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 != ThisTimeLineIDChecked) ereport(PANIC, (errmsg("unexpected timeline ID %u (should be %u) in checkpoint record", - checkPoint.ThisTimeLineID, ThisTimeLineID))); + checkPoint.ThisTimeLineID, ThisTimeLineIDChecked))); RecoveryRestartPoint(&checkPoint); } @@ -10473,10 +10485,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 != ThisTimeLineIDChecked) ereport(PANIC, (errmsg("unexpected timeline ID %u (should be %u) in checkpoint record", - xlrec.ThisTimeLineID, ThisTimeLineID))); + xlrec.ThisTimeLineID, ThisTimeLineIDChecked))); } else if (info == XLOG_NOOP) { @@ -10546,7 +10558,7 @@ xlog_redo(XLogReaderState *record) if (ControlFile->minRecoveryPoint < lsn) { ControlFile->minRecoveryPoint = lsn; - ControlFile->minRecoveryPointTLI = ThisTimeLineID; + ControlFile->minRecoveryPointTLI = ThisTimeLineIDChecked; } ControlFile->backupStartPoint = InvalidXLogRecPtr; ControlFile->backupEndRequired = false; @@ -10587,7 +10599,7 @@ xlog_redo(XLogReaderState *record) if (minRecoveryPoint != InvalidXLogRecPtr && minRecoveryPoint < lsn) { ControlFile->minRecoveryPoint = lsn; - ControlFile->minRecoveryPointTLI = ThisTimeLineID; + ControlFile->minRecoveryPointTLI = ThisTimeLineIDChecked; } CommitTsParameterChange(xlrec.track_commit_timestamp, @@ -10800,7 +10812,7 @@ assign_xlog_sync_method(int new_sync_method, void *extra) int save_errno; save_errno = errno; - XLogFileName(xlogfname, ThisTimeLineID, openLogSegNo, + XLogFileName(xlogfname, ThisTimeLineIDChecked, openLogSegNo, wal_segment_size); errno = save_errno; ereport(PANIC, @@ -10876,7 +10888,7 @@ issue_xlog_fsync(int fd, XLogSegNo segno) char xlogfname[MAXFNAMELEN]; int save_errno = errno; - XLogFileName(xlogfname, ThisTimeLineID, segno, + XLogFileName(xlogfname, ThisTimeLineIDChecked, segno, wal_segment_size); errno = save_errno; ereport(PANIC, @@ -11721,7 +11733,7 @@ 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; + stoptli = ThisTimeLineIDChecked; /* * Force a switch to a new xlog segment file, so that the backup is diff --git a/src/backend/access/transam/xlogarchive.c b/src/backend/access/transam/xlogarchive.c index 26b023e754..24fe509fdd 100644 --- a/src/backend/access/transam/xlogarchive.c +++ b/src/backend/access/transam/xlogarchive.c @@ -502,7 +502,7 @@ XLogArchiveNotifySeg(XLogSegNo segno) { char xlog[MAXFNAMELEN]; - XLogFileName(xlog, ThisTimeLineID, segno, wal_segment_size); + XLogFileName(xlog, ThisTimeLineIDChecked, segno, wal_segment_size); XLogArchiveNotify(xlog); } diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c index b98deb72ec..dada5675e5 100644 --- a/src/backend/access/transam/xlogfuncs.c +++ b/src/backend/access/transam/xlogfuncs.c @@ -469,7 +469,7 @@ pg_walfile_name_offset(PG_FUNCTION_ARGS) * xlogfilename */ XLByteToPrevSeg(locationpoint, xlogsegno, wal_segment_size); - XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno, wal_segment_size); + XLogFileName(xlogfilename, ThisTimeLineIDChecked, xlogsegno, wal_segment_size); values[0] = CStringGetTextDatum(xlogfilename); isnull[0] = false; @@ -511,7 +511,7 @@ pg_walfile_name(PG_FUNCTION_ARGS) "pg_walfile_name()"))); XLByteToPrevSeg(locationpoint, xlogsegno, wal_segment_size); - XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno, wal_segment_size); + XLogFileName(xlogfilename, ThisTimeLineIDChecked, xlogsegno, wal_segment_size); PG_RETURN_TEXT_P(cstring_to_text(xlogfilename)); } diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c index 88a1bfd939..802517c881 100644 --- a/src/backend/access/transam/xlogutils.c +++ b/src/backend/access/transam/xlogutils.c @@ -737,7 +737,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage, uint32 wa * it looked up the timeline. There's nothing we can do about it if * StartupXLOG() renames it to .partial concurrently. */ - if (state->currTLI == ThisTimeLineID && wantPage >= lastReadPage) + if (state->currTLI == ThisTimeLineIDChecked && wantPage >= lastReadPage) { Assert(state->currTLIValidUntil == InvalidXLogRecPtr); return; @@ -749,7 +749,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage, uint32 wa * the current segment we can just keep reading. */ if (state->currTLIValidUntil != InvalidXLogRecPtr && - state->currTLI != ThisTimeLineID && + state->currTLI != ThisTimeLineIDChecked && state->currTLI != 0 && ((wantPage + wantLength) / state->segcxt.ws_segsize) < (state->currTLIValidUntil / state->segcxt.ws_segsize)) @@ -772,7 +772,7 @@ XLogReadDetermineTimeline(XLogReaderState *state, XLogRecPtr wantPage, uint32 wa * We need to re-read the timeline history in case it's been changed * by a promotion or replay from a cascaded replica. */ - List *timelineHistory = readTimeLineHistory(ThisTimeLineID); + List *timelineHistory = readTimeLineHistory(ThisTimeLineIDChecked); XLogRecPtr endOfSegment; endOfSegment = ((wantPage / state->segcxt.ws_segsize) + 1) * @@ -870,8 +870,11 @@ read_local_xlog_page(XLogReaderState *state, XLogRecPtr targetPagePtr, if (!RecoveryInProgress()) read_upto = GetFlushRecPtr(); else + { read_upto = GetXLogReplayRecPtr(&ThisTimeLineID); - tli = ThisTimeLineID; + ThisTimeLineIDValid = true; + } + tli = ThisTimeLineIDChecked; /* * Check which timeline to get the record from. @@ -899,7 +902,7 @@ read_local_xlog_page(XLogReaderState *state, XLogRecPtr targetPagePtr, */ XLogReadDetermineTimeline(state, targetPagePtr, reqLen); - if (state->currTLI == ThisTimeLineID) + if (state->currTLI == ThisTimeLineIDChecked) { if (loc <= read_upto) diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c index b31c36d918..7d6370d399 100644 --- a/src/backend/replication/basebackup.c +++ b/src/backend/replication/basebackup.c @@ -502,9 +502,9 @@ perform_base_backup(basebackup_options *opt) * including them. */ XLByteToSeg(startptr, startsegno, wal_segment_size); - XLogFileName(firstoff, ThisTimeLineID, startsegno, wal_segment_size); + XLogFileName(firstoff, ThisTimeLineIDChecked, startsegno, wal_segment_size); XLByteToPrevSeg(endptr, endsegno, wal_segment_size); - XLogFileName(lastoff, ThisTimeLineID, endsegno, wal_segment_size); + XLogFileName(lastoff, ThisTimeLineIDChecked, endsegno, wal_segment_size); dir = AllocateDir("pg_wal"); while ((de = ReadDir(dir, "pg_wal")) != NULL) @@ -528,7 +528,7 @@ perform_base_backup(basebackup_options *opt) * Before we go any further, check that none of the WAL segments we * need were removed. */ - CheckXLogRemoved(startsegno, ThisTimeLineID); + CheckXLogRemoved(startsegno, ThisTimeLineIDChecked); /* * Sort the WAL filenames. We want to send the files in order from @@ -555,7 +555,7 @@ perform_base_backup(basebackup_options *opt) { char startfname[MAXFNAMELEN]; - XLogFileName(startfname, ThisTimeLineID, startsegno, + XLogFileName(startfname, ThisTimeLineIDChecked, startsegno, wal_segment_size); ereport(ERROR, (errmsg("could not find WAL file \"%s\"", startfname))); @@ -571,7 +571,7 @@ perform_base_backup(basebackup_options *opt) { char nextfname[MAXFNAMELEN]; - XLogFileName(nextfname, ThisTimeLineID, nextsegno, + XLogFileName(nextfname, ThisTimeLineIDChecked, nextsegno, wal_segment_size); ereport(ERROR, (errmsg("could not find WAL file \"%s\"", nextfname))); @@ -581,7 +581,7 @@ perform_base_backup(basebackup_options *opt) { char endfname[MAXFNAMELEN]; - XLogFileName(endfname, ThisTimeLineID, endsegno, wal_segment_size); + XLogFileName(endfname, ThisTimeLineIDChecked, endsegno, wal_segment_size); ereport(ERROR, (errmsg("could not find WAL file \"%s\"", endfname))); } diff --git a/src/backend/replication/logical/logicalfuncs.c b/src/backend/replication/logical/logicalfuncs.c index e59939aad1..379dc0c1d9 100644 --- a/src/backend/replication/logical/logicalfuncs.c +++ b/src/backend/replication/logical/logicalfuncs.c @@ -214,7 +214,11 @@ pg_logical_slot_get_changes_guts(FunctionCallInfo fcinfo, bool confirm, bool bin if (!RecoveryInProgress()) end_of_wal = GetFlushRecPtr(); else + { + Assert(ThisTimeLineIDValid); end_of_wal = GetXLogReplayRecPtr(&ThisTimeLineID); + ThisTimeLineIDValid = true; + } ReplicationSlotAcquire(NameStr(*name), true); diff --git a/src/backend/replication/slotfuncs.c b/src/backend/replication/slotfuncs.c index 17df99c2ac..a3f8c35aec 100644 --- a/src/backend/replication/slotfuncs.c +++ b/src/backend/replication/slotfuncs.c @@ -627,7 +627,11 @@ pg_replication_slot_advance(PG_FUNCTION_ARGS) if (!RecoveryInProgress()) moveto = Min(moveto, GetFlushRecPtr()); else + { + Assert(ThisTimeLineIDValid); moveto = Min(moveto, GetXLogReplayRecPtr(&ThisTimeLineID)); + ThisTimeLineIDValid = true; + } /* Acquire the slot so we "own" it */ ReplicationSlotAcquire(NameStr(*slotname), true); diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index b90e5ca98e..0ac4e29fd6 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -395,6 +395,7 @@ WalReceiverMain(void) options.slotname = slotname[0] != '\0' ? slotname : NULL; options.proto.physical.startpointTLI = startpointTLI; ThisTimeLineID = startpointTLI; + ThisTimeLineIDValid = true; if (walrcv_startstreaming(wrconn, &options)) { if (first_stream) @@ -893,7 +894,7 @@ XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr) /* Create/use new log file */ XLByteToSeg(recptr, recvSegNo, wal_segment_size); recvFile = XLogFileInit(recvSegNo); - recvFileTLI = ThisTimeLineID; + recvFileTLI = ThisTimeLineIDChecked; } /* Calculate the start offset of the received logs */ @@ -972,7 +973,7 @@ XLogWalRcvFlush(bool dying) { walrcv->latestChunkStart = walrcv->flushedUpto; walrcv->flushedUpto = LogstreamResult.Flush; - walrcv->receivedTLI = ThisTimeLineID; + walrcv->receivedTLI = ThisTimeLineIDChecked; } SpinLockRelease(&walrcv->mutex); diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c index b811a5c0ef..73a6e06e6b 100644 --- a/src/backend/replication/walsender.c +++ b/src/backend/replication/walsender.c @@ -440,7 +440,7 @@ IdentifySystem(void) values[0] = CStringGetTextDatum(sysid); /* column 2: timeline */ - values[1] = Int32GetDatum(ThisTimeLineID); + values[1] = Int32GetDatum(ThisTimeLineIDChecked); /* column 3: wal location */ values[2] = CStringGetTextDatum(xloc); @@ -628,7 +628,7 @@ StartReplication(StartReplicationCmd *cmd) XLogRecPtr switchpoint; sendTimeLine = cmd->timeline; - if (sendTimeLine == ThisTimeLineID) + if (sendTimeLine == ThisTimeLineIDChecked) { sendTimeLineIsHistoric = false; sendTimeLineValidUpto = InvalidXLogRecPtr; @@ -643,7 +643,7 @@ StartReplication(StartReplicationCmd *cmd) * Check that the timeline the client requested exists, and the * requested start location is on that timeline. */ - timeLineHistory = readTimeLineHistory(ThisTimeLineID); + timeLineHistory = readTimeLineHistory(ThisTimeLineIDChecked); switchpoint = tliSwitchPoint(cmd->timeline, timeLineHistory, &sendTimeLineNextTLI); list_free_deep(timeLineHistory); @@ -682,7 +682,7 @@ StartReplication(StartReplicationCmd *cmd) } else { - sendTimeLine = ThisTimeLineID; + sendTimeLine = ThisTimeLineIDChecked; sendTimeLineValidUpto = InvalidXLogRecPtr; sendTimeLineIsHistoric = false; } @@ -812,7 +812,7 @@ logical_read_xlog_page(XLogReaderState *state, XLogRecPtr targetPagePtr, int req XLogSegNo segno; XLogReadDetermineTimeline(state, targetPagePtr, reqLen); - sendTimeLineIsHistoric = (state->currTLI != ThisTimeLineID); + sendTimeLineIsHistoric = (state->currTLI != ThisTimeLineIDChecked); sendTimeLine = state->currTLI; sendTimeLineValidUpto = state->currTLIValidUntil; sendTimeLineNextTLI = state->nextTLI; @@ -945,7 +945,7 @@ CreateReplicationSlot(CreateReplicationSlotCmd *cmd) /* setup state for WalSndSegmentOpen */ sendTimeLineIsHistoric = false; - sendTimeLine = ThisTimeLineID; + sendTimeLine = ThisTimeLineID; // XXX ThisTimeLineIDChecked fails assertion, ThisTimeLineID = 0!!! if (cmd->kind == REPLICATION_KIND_PHYSICAL) { @@ -2618,7 +2618,7 @@ XLogSendPhysical(void) * still the one recovery is recovering from? ThisTimeLineID was * updated by the GetStandbyFlushRecPtr() call above. */ - if (sendTimeLine != ThisTimeLineID) + if (sendTimeLine != ThisTimeLineIDChecked) becameHistoric = true; } @@ -2631,7 +2631,7 @@ XLogSendPhysical(void) */ List *history; - history = readTimeLineHistory(ThisTimeLineID); + history = readTimeLineHistory(ThisTimeLineIDChecked); sendTimeLineValidUpto = tliSwitchPoint(sendTimeLine, history, &sendTimeLineNextTLI); Assert(sendTimeLine < sendTimeLineNextTLI); @@ -2989,9 +2989,10 @@ GetStandbyFlushRecPtr(void) replayPtr = GetXLogReplayRecPtr(&replayTLI); ThisTimeLineID = replayTLI; + ThisTimeLineIDValid = true; result = replayPtr; - if (receiveTLI == ThisTimeLineID && receivePtr > replayPtr) + if (receiveTLI == ThisTimeLineIDChecked && receivePtr > replayPtr) result = receivePtr; return result; diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 5e2c94a05f..317e110488 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -29,8 +29,12 @@ #define SYNC_METHOD_OPEN_DSYNC 4 /* for O_DSYNC */ extern int sync_method; +extern PGDLLIMPORT bool ThisTimeLineIDValid; extern PGDLLIMPORT TimeLineID ThisTimeLineID; /* current TLI */ +#define ThisTimeLineIDChecked \ + (AssertMacro(ThisTimeLineIDValid), ThisTimeLineID) + /* * Recovery target type. * Only set during a Point in Time recovery, not when in standby mode. -- 2.24.3 (Apple Git-128)