aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2013-02-11 18:13:09 +0200
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2013-02-11 18:16:25 +0200
commit7803e9327db3788f68d820c19f4081afb79edd12 (patch)
tree8d9e4668125df8023c4a59e9060b19dcb5b940d6 /src
parentc352ea2d74c4e317bf2a1471ec1f750f9f072276 (diff)
downloadpostgresql-7803e9327db3788f68d820c19f4081afb79edd12.tar.gz
postgresql-7803e9327db3788f68d820c19f4081afb79edd12.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/rmgrdesc/xlogdesc.c7
-rw-r--r--src/backend/access/transam/xlog.c36
-rw-r--r--src/bin/pg_controldata/pg_controldata.c2
-rw-r--r--src/bin/pg_resetxlog/pg_resetxlog.c4
-rw-r--r--src/include/access/xlog_internal.h3
-rw-r--r--src/include/catalog/pg_control.h4
6 files changed, 48 insertions, 8 deletions
diff --git a/src/backend/access/rmgrdesc/xlogdesc.c b/src/backend/access/rmgrdesc/xlogdesc.c
index 69012985161..b22e66e5795 100644
--- a/src/backend/access/rmgrdesc/xlogdesc.c
+++ b/src/backend/access/rmgrdesc/xlogdesc.c
@@ -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
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index f0df2977a12..3155238c58d 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -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
diff --git a/src/bin/pg_controldata/pg_controldata.c b/src/bin/pg_controldata/pg_controldata.c
index 67ebc88dcdd..33725154fd7 100644
--- a/src/bin/pg_controldata/pg_controldata.c
+++ b/src/bin/pg_controldata/pg_controldata.c
@@ -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"),
diff --git a/src/bin/pg_resetxlog/pg_resetxlog.c b/src/bin/pg_resetxlog/pg_resetxlog.c
index 8e7fe7eb72e..272813eaabf 100644
--- a/src/bin/pg_resetxlog/pg_resetxlog.c
+++ b/src/bin/pg_resetxlog/pg_resetxlog.c
@@ -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;
diff --git a/src/include/access/xlog_internal.h b/src/include/access/xlog_internal.h
index 34c659314ce..16b53e37260 100644
--- a/src/include/access/xlog_internal.h
+++ b/src/include/access/xlog_internal.h
@@ -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;
/*
diff --git a/src/include/catalog/pg_control.h b/src/include/catalog/pg_control.h
index ec8cea7c86e..0c647e77ad7 100644
--- a/src/include/catalog/pg_control.h
+++ b/src/include/catalog/pg_control.h
@@ -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 */