static void SetCurrentChunkStartTime(TimestampTz xtime);
static void CheckRequiredParameterValues(void);
static void XLogReportParameters(void);
+static void checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI);
static void LocalSetXLogInsertAllowed(void);
static void CheckPointGuts(XLogRecPtr checkPointRedo, int flags);
static void KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo);
LWLockRelease(XidGenLock);
}
+ /*
+ * Before replaying this record, check if it is a shutdown
+ * checkpoint record that causes the current timeline to
+ * change. The checkpoint record is already considered to be
+ * part of the new timeline, so we update ThisTimeLineID
+ * before replaying it. That's important so that replayEndTLI,
+ * which is recorded as the minimum recovery point's TLI if
+ * recovery stops after this record, is set correctly.
+ */
+ if (record->xl_rmid == RM_XLOG_ID &&
+ (record->xl_info & ~XLR_INFO_MASK) == XLOG_CHECKPOINT_SHUTDOWN)
+ {
+ CheckPoint checkPoint;
+ TimeLineID newTLI;
+
+ memcpy(&checkPoint, XLogRecGetData(record), sizeof(CheckPoint));
+ newTLI = checkPoint.ThisTimeLineID;
+
+ if (newTLI != ThisTimeLineID)
+ {
+ /* Check that it's OK to switch to this TLI */
+ checkTimeLineSwitch(EndRecPtr, newTLI);
+
+ /* Following WAL records should be run with new TLI */
+ ThisTimeLineID = newTLI;
+ }
+ }
+
/*
* Update shared replayEndRecPtr before replaying this record,
* so that XLogFlush will update minRecoveryPoint correctly.
*/
SpinLockAcquire(&xlogctl->info_lck);
xlogctl->replayEndRecPtr = EndRecPtr;
+ xlogctl->replayEndTLI = ThisTimeLineID;
SpinLockRelease(&xlogctl->info_lck);
/*
END_CRIT_SECTION();
}
+/*
+ * Check that it's OK to switch to new timeline during recovery.
+ *
+ * 'lsn' is the address of the shutdown checkpoint record we're about to
+ * replay. (Currently, timeline can only change at a shutdown checkpoint).
+ */
+static void
+checkTimeLineSwitch(XLogRecPtr lsn, TimeLineID newTLI)
+{
+ /*
+ * The new timeline better be in the list of timelines we expect
+ * to see, according to the timeline history. It should also not
+ * decrease.
+ */
+ if (newTLI < ThisTimeLineID || !tliInHistory(newTLI, expectedTLEs))
+ ereport(PANIC,
+ (errmsg("unexpected timeline ID %u (after %u) in checkpoint record",
+ newTLI, ThisTimeLineID)));
+
+ /*
+ * If we have not yet reached min recovery point, and we're about
+ * to switch to a timeline greater than the timeline of the min
+ * recovery point: trouble. After switching to the new timeline,
+ * we could not possibly visit the min recovery point on the
+ * correct timeline anymore. This can happen if there is a newer
+ * timeline in the archive that branched before the timeline the
+ * min recovery point is on, and you attempt to do PITR to the
+ * new timeline.
+ */
+ if (!XLogRecPtrIsInvalid(minRecoveryPoint) &&
+ XLByteLT(lsn, minRecoveryPoint) &&
+ newTLI > minRecoveryPointTLI)
+ ereport(PANIC,
+ (errmsg("unexpected timeline ID %u in checkpoint record, before reaching minimum recovery point %X/%X on timeline %u",
+ newTLI,
+ (uint32) (minRecoveryPoint >> 32),
+ (uint32) minRecoveryPoint,
+ minRecoveryPointTLI)));
+
+ /* Looks good */
+}
+
/*
* XLOG resource manager's routines
*
}
/*
- * TLI may change in a shutdown checkpoint.
+ * We should've already switched to the new TLI before replaying this
+ * record.
*/
if (checkPoint.ThisTimeLineID != ThisTimeLineID)
- {
- /*
- * The new timeline better be in the list of timelines we expect
- * to see, according to the timeline history. It should also not
- * decrease.
- */
- if (checkPoint.ThisTimeLineID < ThisTimeLineID ||
- !tliInHistory(checkPoint.ThisTimeLineID, expectedTLEs))
- ereport(PANIC,
- (errmsg("unexpected timeline ID %u (after %u) in checkpoint record",
- checkPoint.ThisTimeLineID, ThisTimeLineID)));
-
- /*
- * If we have not yet reached min recovery point, and we're about
- * to switch to a timeline greater than the timeline of the min
- * recovery point: trouble. After switching to the new timeline,
- * we could not possibly visit the min recovery point on the
- * correct timeline anymore. This can happen if there is a newer
- * timeline in the archive that branched before the timeline the
- * min recovery point is on, and you attempt to do PITR to the
- * new timeline.
- */
- if (!XLogRecPtrIsInvalid(minRecoveryPoint) &&
- XLByteLT(lsn, minRecoveryPoint) &&
- checkPoint.ThisTimeLineID > minRecoveryPointTLI)
- ereport(PANIC,
- (errmsg("unexpected timeline ID %u in checkpoint record, before reaching minimum recovery point %X/%X on timeline %u",
- checkPoint.ThisTimeLineID,
- (uint32) (minRecoveryPoint >> 32),
- (uint32) minRecoveryPoint,
- minRecoveryPointTLI)));
-
- /* Following WAL records should be run with new TLI */
- ThisTimeLineID = checkPoint.ThisTimeLineID;
- }
+ ereport(PANIC,
+ (errmsg("unexpected timeline ID %u (should be %u) in checkpoint record",
+ checkPoint.ThisTimeLineID, ThisTimeLineID)));
RecoveryRestartPoint(&checkPoint);
}