promote-panic_v3.patch
text/x-patch
Filename: promote-panic_v3.patch
Type: text/x-patch
Part: 0
Patch
Format: unified
Series: patch v3
| File | + | − |
|---|---|---|
| src/backend/access/transam/xlog.c | 54 | 32 |
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index dcfef36591..d86137ae8b 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -821,8 +821,14 @@ static XLogSource XLogReceiptSource = 0; /* XLOG_FROM_* code */
static XLogRecPtr ReadRecPtr; /* start of last record read */
static XLogRecPtr EndRecPtr; /* end+1 of last record read */
-static XLogRecPtr minRecoveryPoint; /* local copy of
- * ControlFile->minRecoveryPoint */
+/*
+ * Local copies of equivalent fields in the control file. When running
+ * crash recovery, minRecoveryPoint is set to InvalidXLogRecPtr as we
+ * expect to replay all the WAL available, and updateMinRecoveryPoint is
+ * switched to false to prevent any updates while replaying records.
+ * Those values are kept consistent as long as crash recovery runs.
+ */
+static XLogRecPtr minRecoveryPoint;
static TimeLineID minRecoveryPointTLI;
static bool updateMinRecoveryPoint = true;
@@ -2707,7 +2713,7 @@ XLogGetReplicationSlotMinimumLSN(void)
static void
UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force)
{
- /* Quick check using our local copy of the variable */
+ /* Check using our local copy of minRecoveryPoint */
if (!updateMinRecoveryPoint || (!force && lsn <= minRecoveryPoint))
return;
@@ -2717,14 +2723,7 @@ UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force)
minRecoveryPoint = ControlFile->minRecoveryPoint;
minRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
- /*
- * An invalid minRecoveryPoint means that we need to recover all the WAL,
- * i.e., we're doing crash recovery. We never modify the control file's
- * value in that case, so we can short-circuit future checks here too.
- */
- if (minRecoveryPoint == 0)
- updateMinRecoveryPoint = false;
- else if (force || minRecoveryPoint < lsn)
+ if (force || minRecoveryPoint < lsn)
{
XLogRecPtr newMinRecoveryPoint;
TimeLineID newMinRecoveryPointTLI;
@@ -3110,7 +3109,7 @@ XLogNeedsFlush(XLogRecPtr record)
*/
if (RecoveryInProgress())
{
- /* Quick exit if already known updated */
+ /* Quick exit if already known to be updated or cannot be updated */
if (record <= minRecoveryPoint || !updateMinRecoveryPoint)
return false;
@@ -3124,20 +3123,8 @@ XLogNeedsFlush(XLogRecPtr record)
minRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
LWLockRelease(ControlFileLock);
- /*
- * An invalid minRecoveryPoint means that we need to recover all the
- * WAL, i.e., we're doing crash recovery. We never modify the control
- * file's value in that case, so we can short-circuit future checks
- * here too.
- */
- if (minRecoveryPoint == 0)
- updateMinRecoveryPoint = false;
-
/* check again */
- if (record <= minRecoveryPoint || !updateMinRecoveryPoint)
- return false;
- else
- return true;
+ return record > minRecoveryPoint;
}
/* Quick exit if already known flushed */
@@ -4269,6 +4256,12 @@ ReadRecord(XLogReaderState *xlogreader, XLogRecPtr RecPtr, int emode,
minRecoveryPoint = ControlFile->minRecoveryPoint;
minRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
+ /*
+ * The startup process can update its local copy of
+ * minRecoveryPoint from this point.
+ */
+ updateMinRecoveryPoint = true;
+
UpdateControlFile();
LWLockRelease(ControlFileLock);
@@ -6892,9 +6885,31 @@ StartupXLOG(void)
/* No need to hold ControlFileLock yet, we aren't up far enough */
UpdateControlFile();
- /* initialize our local copy of minRecoveryPoint */
- minRecoveryPoint = ControlFile->minRecoveryPoint;
- minRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
+ /*
+ * Initialize our local copy of minRecoveryPoint. When doing crash
+ * recovery we want to replay up to the end of WAL. Particularly, in
+ * the case of a promoted standby minRecoveryPoint value in the
+ * control file is only updated after the first checkpoint. However,
+ * if the instance crashes before the first post-recovery checkpoint
+ * is completed then recovery will use a stale location causing the
+ * startup process to think that there are still invalid page
+ * references when checking for data consistency.
+ */
+ if (InArchiveRecovery)
+ {
+ minRecoveryPoint = ControlFile->minRecoveryPoint;
+ minRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
+ }
+ else
+ {
+ /*
+ * We are to run crash recovery. We shouldn't update
+ * minRecoveryPoint until crash recvoery ends.
+ */
+ updateMinRecoveryPoint = false;
+ minRecoveryPoint = InvalidXLogRecPtr;
+ minRecoveryPointTLI = 0;
+ }
/*
* Reset pgstat data, because it may be invalid after recovery.
@@ -7861,6 +7876,8 @@ CheckRecoveryConsistency(void)
if (XLogRecPtrIsInvalid(minRecoveryPoint))
return;
+ Assert(InArchiveRecovery);
+
/*
* assume that we are called in the startup process, and hence don't need
* a lock to read lastReplayedEndRecPtr
@@ -9949,11 +9966,16 @@ xlog_redo(XLogReaderState *record)
* Update minRecoveryPoint to ensure that if recovery is aborted, we
* recover back up to this point before allowing hot standby again.
* This is important if the max_* settings are decreased, to ensure
- * you don't run queries against the WAL preceding the change.
+ * you don't run queries against the WAL preceding the change. The
+ * local copies cannot be updated as long as crash recovery is
+ * happening and we expect all the WAL to be replayed.
*/
- minRecoveryPoint = ControlFile->minRecoveryPoint;
- minRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
- if (minRecoveryPoint != 0 && minRecoveryPoint < lsn)
+ if (InArchiveRecovery)
+ {
+ minRecoveryPoint = ControlFile->minRecoveryPoint;
+ minRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
+ }
+ if (minRecoveryPoint != InvalidXLogRecPtr && minRecoveryPoint < lsn)
{
ControlFile->minRecoveryPoint = lsn;
ControlFile->minRecoveryPointTLI = ThisTimeLineID;