Skip to content

Commit 7803e93

Browse files
committed
Include previous TLI in end-of-recovery and shutdown checkpoint records.
This isn't used for anything but a sanity check at the moment, but it could be highly valuable for debugging purposes. It could also be used to recreate timeline history by traversing WAL, which seems useful.
1 parent c352ea2 commit 7803e93

File tree

6 files changed

+48
-8
lines changed

6 files changed

+48
-8
lines changed

src/backend/access/rmgrdesc/xlogdesc.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,12 @@ xlog_desc(StringInfo buf, uint8 xl_info, char *rec)
4141
CheckPoint *checkpoint = (CheckPoint *) rec;
4242

4343
appendStringInfo(buf, "checkpoint: redo %X/%X; "
44-
"tli %u; fpw %s; xid %u/%u; oid %u; multi %u; offset %u; "
44+
"tli %u; prev tli %u; fpw %s; xid %u/%u; oid %u; multi %u; offset %u; "
4545
"oldest xid %u in DB %u; oldest multi %u in DB %u; "
4646
"oldest running xid %u; %s",
4747
(uint32) (checkpoint->redo >> 32), (uint32) checkpoint->redo,
4848
checkpoint->ThisTimeLineID,
49+
checkpoint->PrevTimeLineID,
4950
checkpoint->fullPageWrites ? "true" : "false",
5051
checkpoint->nextXidEpoch, checkpoint->nextXid,
5152
checkpoint->nextOid,
@@ -125,8 +126,8 @@ xlog_desc(StringInfo buf, uint8 xl_info, char *rec)
125126
xl_end_of_recovery xlrec;
126127

127128
memcpy(&xlrec, rec, sizeof(xl_end_of_recovery));
128-
appendStringInfo(buf, "end_of_recovery: tli %u; time %s",
129-
xlrec.ThisTimeLineID,
129+
appendStringInfo(buf, "end_of_recovery: tli %u; prev tli %u; time %s",
130+
xlrec.ThisTimeLineID, xlrec.PrevTimeLineID,
130131
timestamptz_to_str(xlrec.end_time));
131132
}
132133
else

src/backend/access/transam/xlog.c

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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);
613621
static void SetCurrentChunkStartTime(TimestampTz xtime);
614622
static void CheckRequiredParameterValues(void);
615623
static void XLogReportParameters(void);
616-
static void checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI);
624+
static void checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI,
625+
TimeLineID prevTLI);
617626
static void LocalSetXLogInsertAllowed(void);
618627
static void CreateEndOfRecoveryRecord(void);
619628
static 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
*/
75377562
static 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

src/bin/pg_controldata/pg_controldata.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,8 @@ main(int argc, char *argv[])
215215
xlogfilename);
216216
printf(_("Latest checkpoint's TimeLineID: %u\n"),
217217
ControlFile.checkPointCopy.ThisTimeLineID);
218+
printf(_("Latest checkpoint's PrevTimeLineID: %u\n"),
219+
ControlFile.checkPointCopy.PrevTimeLineID);
218220
printf(_("Latest checkpoint's full_page_writes: %s\n"),
219221
ControlFile.checkPointCopy.fullPageWrites ? _("on") : _("off"));
220222
printf(_("Latest checkpoint's NextXID: %u/%u\n"),

src/bin/pg_resetxlog/pg_resetxlog.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,10 @@ main(int argc, char *argv[])
340340
ControlFile.checkPointCopy.nextMultiOffset = set_mxoff;
341341

342342
if (minXlogTli > ControlFile.checkPointCopy.ThisTimeLineID)
343+
{
343344
ControlFile.checkPointCopy.ThisTimeLineID = minXlogTli;
345+
ControlFile.checkPointCopy.PrevTimeLineID = minXlogTli;
346+
}
344347

345348
if (minXlogSegNo > newXlogSegNo)
346349
newXlogSegNo = minXlogSegNo;
@@ -490,6 +493,7 @@ GuessControlValues(void)
490493

491494
ControlFile.checkPointCopy.redo = SizeOfXLogLongPHD;
492495
ControlFile.checkPointCopy.ThisTimeLineID = 1;
496+
ControlFile.checkPointCopy.PrevTimeLineID = 1;
493497
ControlFile.checkPointCopy.fullPageWrites = false;
494498
ControlFile.checkPointCopy.nextXidEpoch = 0;
495499
ControlFile.checkPointCopy.nextXid = FirstNormalTransactionId;

src/include/access/xlog_internal.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,8 @@ typedef struct xl_restore_point
221221
typedef struct xl_end_of_recovery
222222
{
223223
TimestampTz end_time;
224-
TimeLineID ThisTimeLineID;
224+
TimeLineID ThisTimeLineID; /* new TLI */
225+
TimeLineID PrevTimeLineID; /* previous TLI we forked off from */
225226
} xl_end_of_recovery;
226227

227228
/*

src/include/catalog/pg_control.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222

2323
/* Version identifier for this pg_control format */
24-
#define PG_CONTROL_VERSION 933
24+
#define PG_CONTROL_VERSION 934
2525

2626
/*
2727
* Body of CheckPoint XLOG records. This is declared here because we keep
@@ -33,6 +33,8 @@ typedef struct CheckPoint
3333
XLogRecPtr redo; /* next RecPtr available when we began to
3434
* create CheckPoint (i.e. REDO start point) */
3535
TimeLineID ThisTimeLineID; /* current TLI */
36+
TimeLineID PrevTimeLineID; /* previous TLI, if this record begins a new
37+
* timeline (equals ThisTimeLineID otherwise) */
3638
bool fullPageWrites; /* current full_page_writes */
3739
uint32 nextXidEpoch; /* higher-order bits of nextXid */
3840
TransactionId nextXid; /* next free XID */

0 commit comments

Comments
 (0)