@@ -408,7 +408,15 @@ typedef struct XLogCtlData
408408 char * pages ; /* buffers for unwritten XLOG pages */
409409 XLogRecPtr * xlblocks ; /* 1st byte ptr-s + XLOG_BLCKSZ */
410410 int XLogCacheBlck ; /* highest allocated xlog buffer index */
411+
412+ /*
413+ * Shared copy of ThisTimeLineID. Does not change after end-of-recovery.
414+ * If we created a new timeline when the system was started up,
415+ * PrevTimeLineID is the old timeline's ID that we forked off from.
416+ * Otherwise it's equal to ThisTimeLineID.
417+ */
411418 TimeLineID ThisTimeLineID ;
419+ TimeLineID PrevTimeLineID ;
412420
413421 /*
414422 * archiveCleanupCommand is read from recovery.conf but needs to be in
@@ -613,7 +621,8 @@ static void SetLatestXTime(TimestampTz xtime);
613621static void SetCurrentChunkStartTime (TimestampTz xtime );
614622static void CheckRequiredParameterValues (void );
615623static void XLogReportParameters (void );
616- static void checkTimeLineSwitch (XLogRecPtr lsn , TimeLineID newTLI );
624+ static void checkTimeLineSwitch (XLogRecPtr lsn , TimeLineID newTLI ,
625+ TimeLineID prevTLI );
617626static void LocalSetXLogInsertAllowed (void );
618627static void CreateEndOfRecoveryRecord (void );
619628static void CheckPointGuts (XLogRecPtr checkPointRedo , int flags );
@@ -3896,6 +3905,7 @@ BootStrapXLOG(void)
38963905 */
38973906 checkPoint .redo = XLogSegSize + SizeOfXLogLongPHD ;
38983907 checkPoint .ThisTimeLineID = ThisTimeLineID ;
3908+ checkPoint .PrevTimeLineID = ThisTimeLineID ;
38993909 checkPoint .fullPageWrites = fullPageWrites ;
39003910 checkPoint .nextXidEpoch = 0 ;
39013911 checkPoint .nextXid = FirstNormalTransactionId ;
@@ -4712,6 +4722,7 @@ StartupXLOG(void)
47124722 checkPointLoc ,
47134723 EndOfLog ;
47144724 XLogSegNo endLogSegNo ;
4725+ TimeLineID PrevTimeLineID ;
47154726 XLogRecord * record ;
47164727 uint32 freespace ;
47174728 TransactionId oldestActiveXID ;
@@ -5431,6 +5442,7 @@ StartupXLOG(void)
54315442 if (record -> xl_rmid == RM_XLOG_ID )
54325443 {
54335444 TimeLineID newTLI = ThisTimeLineID ;
5445+ TimeLineID prevTLI = ThisTimeLineID ;
54345446 uint8 info = record -> xl_info & ~XLR_INFO_MASK ;
54355447
54365448 if (info == XLOG_CHECKPOINT_SHUTDOWN )
@@ -5439,19 +5451,21 @@ StartupXLOG(void)
54395451
54405452 memcpy (& checkPoint , XLogRecGetData (record ), sizeof (CheckPoint ));
54415453 newTLI = checkPoint .ThisTimeLineID ;
5454+ prevTLI = checkPoint .PrevTimeLineID ;
54425455 }
54435456 else if (info == XLOG_END_OF_RECOVERY )
54445457 {
54455458 xl_end_of_recovery xlrec ;
54465459
54475460 memcpy (& xlrec , XLogRecGetData (record ), sizeof (xl_end_of_recovery ));
54485461 newTLI = xlrec .ThisTimeLineID ;
5462+ prevTLI = xlrec .PrevTimeLineID ;
54495463 }
54505464
54515465 if (newTLI != ThisTimeLineID )
54525466 {
54535467 /* Check that it's OK to switch to this TLI */
5454- checkTimeLineSwitch (EndRecPtr , newTLI );
5468+ checkTimeLineSwitch (EndRecPtr , newTLI , prevTLI );
54555469
54565470 /* Following WAL records should be run with new TLI */
54575471 ThisTimeLineID = newTLI ;
@@ -5620,6 +5634,7 @@ StartupXLOG(void)
56205634 *
56215635 * In a normal crash recovery, we can just extend the timeline we were in.
56225636 */
5637+ PrevTimeLineID = ThisTimeLineID ;
56235638 if (InArchiveRecovery )
56245639 {
56255640 char reason [200 ];
@@ -5655,6 +5670,7 @@ StartupXLOG(void)
56555670
56565671 /* Save the selected TimeLineID in shared memory, too */
56575672 XLogCtl -> ThisTimeLineID = ThisTimeLineID ;
5673+ XLogCtl -> PrevTimeLineID = PrevTimeLineID ;
56585674
56595675 /*
56605676 * We are now done reading the old WAL. Turn off archive fetching if it
@@ -6690,6 +6706,11 @@ CreateCheckPoint(int flags)
66906706 LocalSetXLogInsertAllowed ();
66916707
66926708 checkPoint .ThisTimeLineID = ThisTimeLineID ;
6709+ if (flags & CHECKPOINT_END_OF_RECOVERY )
6710+ checkPoint .PrevTimeLineID = XLogCtl -> PrevTimeLineID ;
6711+ else
6712+ checkPoint .PrevTimeLineID = ThisTimeLineID ;
6713+
66936714 checkPoint .fullPageWrites = Insert -> fullPageWrites ;
66946715
66956716 /*
@@ -6980,7 +7001,11 @@ CreateEndOfRecoveryRecord(void)
69807001 elog (ERROR , "can only be used to end recovery" );
69817002
69827003 xlrec .end_time = time (NULL );
7004+
7005+ LWLockAcquire (WALInsertLock , LW_SHARED );
69837006 xlrec .ThisTimeLineID = ThisTimeLineID ;
7007+ xlrec .PrevTimeLineID = XLogCtl -> PrevTimeLineID ;
7008+ LWLockRelease (WALInsertLock );
69847009
69857010 LocalSetXLogInsertAllowed ();
69867011
@@ -7535,8 +7560,13 @@ UpdateFullPageWrites(void)
75357560 * replay. (Currently, timeline can only change at a shutdown checkpoint).
75367561 */
75377562static void
7538- checkTimeLineSwitch (XLogRecPtr lsn , TimeLineID newTLI )
7563+ checkTimeLineSwitch (XLogRecPtr lsn , TimeLineID newTLI , TimeLineID prevTLI )
75397564{
7565+ /* Check that the record agrees on what the current (old) timeline is */
7566+ if (prevTLI != ThisTimeLineID )
7567+ ereport (PANIC ,
7568+ (errmsg ("unexpected prev timeline ID %u (current timeline ID %u) in checkpoint record" ,
7569+ prevTLI , ThisTimeLineID )));
75407570 /*
75417571 * The new timeline better be in the list of timelines we expect
75427572 * to see, according to the timeline history. It should also not
0 commit comments