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.
pull/3/head
Heikki Linnakangas 13 years ago
parent c352ea2d74
commit 7803e9327d
  1. 7
      src/backend/access/rmgrdesc/xlogdesc.c
  2. 36
      src/backend/access/transam/xlog.c
  3. 2
      src/bin/pg_controldata/pg_controldata.c
  4. 4
      src/bin/pg_resetxlog/pg_resetxlog.c
  5. 3
      src/include/access/xlog_internal.h
  6. 4
      src/include/catalog/pg_control.h

@ -41,11 +41,12 @@ xlog_desc(StringInfo buf, uint8 xl_info, char *rec)
CheckPoint *checkpoint = (CheckPoint *) rec;
appendStringInfo(buf, "checkpoint: redo %X/%X; "
"tli %u; fpw %s; xid %u/%u; oid %u; multi %u; offset %u; "
"tli %u; prev tli %u; fpw %s; xid %u/%u; oid %u; multi %u; offset %u; "
"oldest xid %u in DB %u; oldest multi %u in DB %u; "
"oldest running xid %u; %s",
(uint32) (checkpoint->redo >> 32), (uint32) checkpoint->redo,
checkpoint->ThisTimeLineID,
checkpoint->PrevTimeLineID,
checkpoint->fullPageWrites ? "true" : "false",
checkpoint->nextXidEpoch, checkpoint->nextXid,
checkpoint->nextOid,
@ -125,8 +126,8 @@ xlog_desc(StringInfo buf, uint8 xl_info, char *rec)
xl_end_of_recovery xlrec;
memcpy(&xlrec, rec, sizeof(xl_end_of_recovery));
appendStringInfo(buf, "end_of_recovery: tli %u; time %s",
xlrec.ThisTimeLineID,
appendStringInfo(buf, "end_of_recovery: tli %u; prev tli %u; time %s",
xlrec.ThisTimeLineID, xlrec.PrevTimeLineID,
timestamptz_to_str(xlrec.end_time));
}
else

@ -408,7 +408,15 @@ typedef struct XLogCtlData
char *pages; /* buffers for unwritten XLOG pages */
XLogRecPtr *xlblocks; /* 1st byte ptr-s + XLOG_BLCKSZ */
int XLogCacheBlck; /* highest allocated xlog buffer index */
/*
* Shared copy of ThisTimeLineID. Does not change after end-of-recovery.
* If we created a new timeline when the system was started up,
* PrevTimeLineID is the old timeline's ID that we forked off from.
* Otherwise it's equal to ThisTimeLineID.
*/
TimeLineID ThisTimeLineID;
TimeLineID PrevTimeLineID;
/*
* archiveCleanupCommand is read from recovery.conf but needs to be in
@ -613,7 +621,8 @@ static void SetLatestXTime(TimestampTz xtime);
static void SetCurrentChunkStartTime(TimestampTz xtime);
static void CheckRequiredParameterValues(void);
static void XLogReportParameters(void);
static void checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI);
static void checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI,
TimeLineID prevTLI);
static void LocalSetXLogInsertAllowed(void);
static void CreateEndOfRecoveryRecord(void);
static void CheckPointGuts(XLogRecPtr checkPointRedo, int flags);
@ -3896,6 +3905,7 @@ BootStrapXLOG(void)
*/
checkPoint.redo = XLogSegSize + SizeOfXLogLongPHD;
checkPoint.ThisTimeLineID = ThisTimeLineID;
checkPoint.PrevTimeLineID = ThisTimeLineID;
checkPoint.fullPageWrites = fullPageWrites;
checkPoint.nextXidEpoch = 0;
checkPoint.nextXid = FirstNormalTransactionId;
@ -4712,6 +4722,7 @@ StartupXLOG(void)
checkPointLoc,
EndOfLog;
XLogSegNo endLogSegNo;
TimeLineID PrevTimeLineID;
XLogRecord *record;
uint32 freespace;
TransactionId oldestActiveXID;
@ -5431,6 +5442,7 @@ StartupXLOG(void)
if (record->xl_rmid == RM_XLOG_ID)
{
TimeLineID newTLI = ThisTimeLineID;
TimeLineID prevTLI = ThisTimeLineID;
uint8 info = record->xl_info & ~XLR_INFO_MASK;
if (info == XLOG_CHECKPOINT_SHUTDOWN)
@ -5439,6 +5451,7 @@ StartupXLOG(void)
memcpy(&checkPoint, XLogRecGetData(record), sizeof(CheckPoint));
newTLI = checkPoint.ThisTimeLineID;
prevTLI = checkPoint.PrevTimeLineID;
}
else if (info == XLOG_END_OF_RECOVERY)
{
@ -5446,12 +5459,13 @@ StartupXLOG(void)
memcpy(&xlrec, XLogRecGetData(record), sizeof(xl_end_of_recovery));
newTLI = xlrec.ThisTimeLineID;
prevTLI = xlrec.PrevTimeLineID;
}
if (newTLI != ThisTimeLineID)
{
/* Check that it's OK to switch to this TLI */
checkTimeLineSwitch(EndRecPtr, newTLI);
checkTimeLineSwitch(EndRecPtr, newTLI, prevTLI);
/* Following WAL records should be run with new TLI */
ThisTimeLineID = newTLI;
@ -5620,6 +5634,7 @@ StartupXLOG(void)
*
* In a normal crash recovery, we can just extend the timeline we were in.
*/
PrevTimeLineID = ThisTimeLineID;
if (InArchiveRecovery)
{
char reason[200];
@ -5655,6 +5670,7 @@ StartupXLOG(void)
/* Save the selected TimeLineID in shared memory, too */
XLogCtl->ThisTimeLineID = ThisTimeLineID;
XLogCtl->PrevTimeLineID = PrevTimeLineID;
/*
* We are now done reading the old WAL. Turn off archive fetching if it
@ -6690,6 +6706,11 @@ CreateCheckPoint(int flags)
LocalSetXLogInsertAllowed();
checkPoint.ThisTimeLineID = ThisTimeLineID;
if (flags & CHECKPOINT_END_OF_RECOVERY)
checkPoint.PrevTimeLineID = XLogCtl->PrevTimeLineID;
else
checkPoint.PrevTimeLineID = ThisTimeLineID;
checkPoint.fullPageWrites = Insert->fullPageWrites;
/*
@ -6980,7 +7001,11 @@ CreateEndOfRecoveryRecord(void)
elog(ERROR, "can only be used to end recovery");
xlrec.end_time = time(NULL);
LWLockAcquire(WALInsertLock, LW_SHARED);
xlrec.ThisTimeLineID = ThisTimeLineID;
xlrec.PrevTimeLineID = XLogCtl->PrevTimeLineID;
LWLockRelease(WALInsertLock);
LocalSetXLogInsertAllowed();
@ -7535,8 +7560,13 @@ UpdateFullPageWrites(void)
* replay. (Currently, timeline can only change at a shutdown checkpoint).
*/
static void
checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI)
checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI, TimeLineID prevTLI)
{
/* Check that the record agrees on what the current (old) timeline is */
if (prevTLI != ThisTimeLineID)
ereport(PANIC,
(errmsg("unexpected prev timeline ID %u (current timeline ID %u) in checkpoint record",
prevTLI, ThisTimeLineID)));
/*
* The new timeline better be in the list of timelines we expect
* to see, according to the timeline history. It should also not

@ -215,6 +215,8 @@ main(int argc, char *argv[])
xlogfilename);
printf(_("Latest checkpoint's TimeLineID: %u\n"),
ControlFile.checkPointCopy.ThisTimeLineID);
printf(_("Latest checkpoint's PrevTimeLineID: %u\n"),
ControlFile.checkPointCopy.PrevTimeLineID);
printf(_("Latest checkpoint's full_page_writes: %s\n"),
ControlFile.checkPointCopy.fullPageWrites ? _("on") : _("off"));
printf(_("Latest checkpoint's NextXID: %u/%u\n"),

@ -340,7 +340,10 @@ main(int argc, char *argv[])
ControlFile.checkPointCopy.nextMultiOffset = set_mxoff;
if (minXlogTli > ControlFile.checkPointCopy.ThisTimeLineID)
{
ControlFile.checkPointCopy.ThisTimeLineID = minXlogTli;
ControlFile.checkPointCopy.PrevTimeLineID = minXlogTli;
}
if (minXlogSegNo > newXlogSegNo)
newXlogSegNo = minXlogSegNo;
@ -490,6 +493,7 @@ GuessControlValues(void)
ControlFile.checkPointCopy.redo = SizeOfXLogLongPHD;
ControlFile.checkPointCopy.ThisTimeLineID = 1;
ControlFile.checkPointCopy.PrevTimeLineID = 1;
ControlFile.checkPointCopy.fullPageWrites = false;
ControlFile.checkPointCopy.nextXidEpoch = 0;
ControlFile.checkPointCopy.nextXid = FirstNormalTransactionId;

@ -221,7 +221,8 @@ typedef struct xl_restore_point
typedef struct xl_end_of_recovery
{
TimestampTz end_time;
TimeLineID ThisTimeLineID;
TimeLineID ThisTimeLineID; /* new TLI */
TimeLineID PrevTimeLineID; /* previous TLI we forked off from */
} xl_end_of_recovery;
/*

@ -21,7 +21,7 @@
/* Version identifier for this pg_control format */
#define PG_CONTROL_VERSION 933
#define PG_CONTROL_VERSION 934
/*
* Body of CheckPoint XLOG records. This is declared here because we keep
@ -33,6 +33,8 @@ typedef struct CheckPoint
XLogRecPtr redo; /* next RecPtr available when we began to
* create CheckPoint (i.e. REDO start point) */
TimeLineID ThisTimeLineID; /* current TLI */
TimeLineID PrevTimeLineID; /* previous TLI, if this record begins a new
* timeline (equals ThisTimeLineID otherwise) */
bool fullPageWrites; /* current full_page_writes */
uint32 nextXidEpoch; /* higher-order bits of nextXid */
TransactionId nextXid; /* next free XID */

Loading…
Cancel
Save