Commit 6be79966 authored by Heikki Linnakangas's avatar Heikki Linnakangas

Fix the tracking of min recovery point timeline.

Forgot to update it at the right place. Also, consider checkpoint record
that switches to new timelne to be on the new timeline.

This fixes erroneous "requested timeline 2 does not contain minimum recovery
point" errors, pointed out by Amit Kapila while testing another patch.
parent b46c9211
......@@ -605,6 +605,7 @@ 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 LocalSetXLogInsertAllowed(void);
static void CheckPointGuts(XLogRecPtr checkPointRedo, int flags);
static void KeepLogSeg(XLogRecPtr recptr, XLogSegNo *logSegNo);
......@@ -5909,12 +5910,41 @@ StartupXLOG(void)
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);
/*
......@@ -7858,6 +7888,48 @@ UpdateFullPageWrites(void)
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
*
......@@ -7971,44 +8043,13 @@ xlog_redo(XLogRecPtr lsn, XLogRecord *record)
}
/*
* 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);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment