@@ -408,7 +408,15 @@ typedef struct XLogCtlData
408
408
char * pages ; /* buffers for unwritten XLOG pages */
409
409
XLogRecPtr * xlblocks ; /* 1st byte ptr-s + XLOG_BLCKSZ */
410
410
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
+ */
411
418
TimeLineID ThisTimeLineID ;
419
+ TimeLineID PrevTimeLineID ;
412
420
413
421
/*
414
422
* archiveCleanupCommand is read from recovery.conf but needs to be in
@@ -613,7 +621,8 @@ static void SetLatestXTime(TimestampTz xtime);
613
621
static void SetCurrentChunkStartTime (TimestampTz xtime );
614
622
static void CheckRequiredParameterValues (void );
615
623
static void XLogReportParameters (void );
616
- static void checkTimeLineSwitch (XLogRecPtr lsn , TimeLineID newTLI );
624
+ static void checkTimeLineSwitch (XLogRecPtr lsn , TimeLineID newTLI ,
625
+ TimeLineID prevTLI );
617
626
static void LocalSetXLogInsertAllowed (void );
618
627
static void CreateEndOfRecoveryRecord (void );
619
628
static void CheckPointGuts (XLogRecPtr checkPointRedo , int flags );
@@ -3896,6 +3905,7 @@ BootStrapXLOG(void)
3896
3905
*/
3897
3906
checkPoint .redo = XLogSegSize + SizeOfXLogLongPHD ;
3898
3907
checkPoint .ThisTimeLineID = ThisTimeLineID ;
3908
+ checkPoint .PrevTimeLineID = ThisTimeLineID ;
3899
3909
checkPoint .fullPageWrites = fullPageWrites ;
3900
3910
checkPoint .nextXidEpoch = 0 ;
3901
3911
checkPoint .nextXid = FirstNormalTransactionId ;
@@ -4712,6 +4722,7 @@ StartupXLOG(void)
4712
4722
checkPointLoc ,
4713
4723
EndOfLog ;
4714
4724
XLogSegNo endLogSegNo ;
4725
+ TimeLineID PrevTimeLineID ;
4715
4726
XLogRecord * record ;
4716
4727
uint32 freespace ;
4717
4728
TransactionId oldestActiveXID ;
@@ -5431,6 +5442,7 @@ StartupXLOG(void)
5431
5442
if (record -> xl_rmid == RM_XLOG_ID )
5432
5443
{
5433
5444
TimeLineID newTLI = ThisTimeLineID ;
5445
+ TimeLineID prevTLI = ThisTimeLineID ;
5434
5446
uint8 info = record -> xl_info & ~XLR_INFO_MASK ;
5435
5447
5436
5448
if (info == XLOG_CHECKPOINT_SHUTDOWN )
@@ -5439,19 +5451,21 @@ StartupXLOG(void)
5439
5451
5440
5452
memcpy (& checkPoint , XLogRecGetData (record ), sizeof (CheckPoint ));
5441
5453
newTLI = checkPoint .ThisTimeLineID ;
5454
+ prevTLI = checkPoint .PrevTimeLineID ;
5442
5455
}
5443
5456
else if (info == XLOG_END_OF_RECOVERY )
5444
5457
{
5445
5458
xl_end_of_recovery xlrec ;
5446
5459
5447
5460
memcpy (& xlrec , XLogRecGetData (record ), sizeof (xl_end_of_recovery ));
5448
5461
newTLI = xlrec .ThisTimeLineID ;
5462
+ prevTLI = xlrec .PrevTimeLineID ;
5449
5463
}
5450
5464
5451
5465
if (newTLI != ThisTimeLineID )
5452
5466
{
5453
5467
/* Check that it's OK to switch to this TLI */
5454
- checkTimeLineSwitch (EndRecPtr , newTLI );
5468
+ checkTimeLineSwitch (EndRecPtr , newTLI , prevTLI );
5455
5469
5456
5470
/* Following WAL records should be run with new TLI */
5457
5471
ThisTimeLineID = newTLI ;
@@ -5620,6 +5634,7 @@ StartupXLOG(void)
5620
5634
*
5621
5635
* In a normal crash recovery, we can just extend the timeline we were in.
5622
5636
*/
5637
+ PrevTimeLineID = ThisTimeLineID ;
5623
5638
if (InArchiveRecovery )
5624
5639
{
5625
5640
char reason [200 ];
@@ -5655,6 +5670,7 @@ StartupXLOG(void)
5655
5670
5656
5671
/* Save the selected TimeLineID in shared memory, too */
5657
5672
XLogCtl -> ThisTimeLineID = ThisTimeLineID ;
5673
+ XLogCtl -> PrevTimeLineID = PrevTimeLineID ;
5658
5674
5659
5675
/*
5660
5676
* We are now done reading the old WAL. Turn off archive fetching if it
@@ -6690,6 +6706,11 @@ CreateCheckPoint(int flags)
6690
6706
LocalSetXLogInsertAllowed ();
6691
6707
6692
6708
checkPoint .ThisTimeLineID = ThisTimeLineID ;
6709
+ if (flags & CHECKPOINT_END_OF_RECOVERY )
6710
+ checkPoint .PrevTimeLineID = XLogCtl -> PrevTimeLineID ;
6711
+ else
6712
+ checkPoint .PrevTimeLineID = ThisTimeLineID ;
6713
+
6693
6714
checkPoint .fullPageWrites = Insert -> fullPageWrites ;
6694
6715
6695
6716
/*
@@ -6980,7 +7001,11 @@ CreateEndOfRecoveryRecord(void)
6980
7001
elog (ERROR , "can only be used to end recovery" );
6981
7002
6982
7003
xlrec .end_time = time (NULL );
7004
+
7005
+ LWLockAcquire (WALInsertLock , LW_SHARED );
6983
7006
xlrec .ThisTimeLineID = ThisTimeLineID ;
7007
+ xlrec .PrevTimeLineID = XLogCtl -> PrevTimeLineID ;
7008
+ LWLockRelease (WALInsertLock );
6984
7009
6985
7010
LocalSetXLogInsertAllowed ();
6986
7011
@@ -7535,8 +7560,13 @@ UpdateFullPageWrites(void)
7535
7560
* replay. (Currently, timeline can only change at a shutdown checkpoint).
7536
7561
*/
7537
7562
static void
7538
- checkTimeLineSwitch (XLogRecPtr lsn , TimeLineID newTLI )
7563
+ checkTimeLineSwitch (XLogRecPtr lsn , TimeLineID newTLI , TimeLineID prevTLI )
7539
7564
{
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 )));
7540
7570
/*
7541
7571
* The new timeline better be in the list of timelines we expect
7542
7572
* to see, according to the timeline history. It should also not
0 commit comments