Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 425bef6

Browse files
committed
Fix bug in determining when recovery has reached consistency.
When starting WAL replay from an online checkpoint, the last replayed WAL record variable was initialized using the checkpoint record's location, even though the records between the REDO location and the checkpoint record had not been replayed yet. That was noted as "slightly confusing" but harmless in the comment, but in some cases, it fooled CheckRecoveryConsistency to incorrectly conclude that we had already reached a consistent state immediately at the beginning of WAL replay. That caused the system to accept read-only connections in hot standby mode too early, and also PANICs with message "WAL contains references to invalid pages". Fix by initializing the variables to the REDO location instead. In 9.2 and above, change CheckRecoveryConsistency() to use lastReplayedEndRecPtr variable when checking if backup end location has been reached. It was inconsistently using EndRecPtr for that check, but lastReplayedEndRecPtr when checking min recovery point. It made no difference before this patch, because in all the places where CheckRecoveryConsistency was called the two variables were the same, but it was always an accident waiting to happen, and would have been wrong after this patch anyway. Report and analysis by Tomonari Katsumata, bug #8686. Backpatch to 9.0, where hot standby was introduced.
1 parent a826773 commit 425bef6

File tree

1 file changed

+18
-18
lines changed
  • src/backend/access/transam

1 file changed

+18
-18
lines changed

src/backend/access/transam/xlog.c

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5452,21 +5452,13 @@ StartupXLOG(void)
54525452
}
54535453

54545454
/*
5455-
* Initialize shared replayEndRecPtr, lastReplayedEndRecPtr, and
5456-
* recoveryLastXTime.
5457-
*
5458-
* This is slightly confusing if we're starting from an online
5459-
* checkpoint; we've just read and replayed the checkpoint record, but
5460-
* we're going to start replay from its redo pointer, which precedes
5461-
* the location of the checkpoint record itself. So even though the
5462-
* last record we've replayed is indeed ReadRecPtr, we haven't
5463-
* replayed all the preceding records yet. That's OK for the current
5464-
* use of these variables.
5455+
* Initialize shared variables for tracking progress of WAL replay,
5456+
* as if we had just replayed the record before the REDO location.
54655457
*/
54665458
SpinLockAcquire(&xlogctl->info_lck);
5467-
xlogctl->replayEndRecPtr = ReadRecPtr;
5459+
xlogctl->replayEndRecPtr = checkPoint.redo;
54685460
xlogctl->replayEndTLI = ThisTimeLineID;
5469-
xlogctl->lastReplayedEndRecPtr = EndRecPtr;
5461+
xlogctl->lastReplayedEndRecPtr = checkPoint.redo;
54705462
xlogctl->lastReplayedTLI = ThisTimeLineID;
54715463
xlogctl->recoveryLastXTime = 0;
54725464
xlogctl->currentChunkStartTime = 0;
@@ -6137,18 +6129,26 @@ StartupXLOG(void)
61376129
static void
61386130
CheckRecoveryConsistency(void)
61396131
{
6132+
XLogRecPtr lastReplayedEndRecPtr;
6133+
61406134
/*
61416135
* During crash recovery, we don't reach a consistent state until we've
61426136
* replayed all the WAL.
61436137
*/
61446138
if (XLogRecPtrIsInvalid(minRecoveryPoint))
61456139
return;
61466140

6141+
/*
6142+
* assume that we are called in the startup process, and hence don't need
6143+
* a lock to read lastReplayedEndRecPtr
6144+
*/
6145+
lastReplayedEndRecPtr = XLogCtl->lastReplayedEndRecPtr;
6146+
61476147
/*
61486148
* Have we reached the point where our base backup was completed?
61496149
*/
61506150
if (!XLogRecPtrIsInvalid(ControlFile->backupEndPoint) &&
6151-
ControlFile->backupEndPoint <= EndRecPtr)
6151+
ControlFile->backupEndPoint <= lastReplayedEndRecPtr)
61526152
{
61536153
/*
61546154
* We have reached the end of base backup, as indicated by pg_control.
@@ -6161,8 +6161,8 @@ CheckRecoveryConsistency(void)
61616161

61626162
LWLockAcquire(ControlFileLock, LW_EXCLUSIVE);
61636163

6164-
if (ControlFile->minRecoveryPoint < EndRecPtr)
6165-
ControlFile->minRecoveryPoint = EndRecPtr;
6164+
if (ControlFile->minRecoveryPoint < lastReplayedEndRecPtr)
6165+
ControlFile->minRecoveryPoint = lastReplayedEndRecPtr;
61666166

61676167
ControlFile->backupStartPoint = InvalidXLogRecPtr;
61686168
ControlFile->backupEndPoint = InvalidXLogRecPtr;
@@ -6180,7 +6180,7 @@ CheckRecoveryConsistency(void)
61806180
* consistent yet.
61816181
*/
61826182
if (!reachedConsistency && !ControlFile->backupEndRequired &&
6183-
minRecoveryPoint <= XLogCtl->lastReplayedEndRecPtr &&
6183+
minRecoveryPoint <= lastReplayedEndRecPtr &&
61846184
XLogRecPtrIsInvalid(ControlFile->backupStartPoint))
61856185
{
61866186
/*
@@ -6192,8 +6192,8 @@ CheckRecoveryConsistency(void)
61926192
reachedConsistency = true;
61936193
ereport(LOG,
61946194
(errmsg("consistent recovery state reached at %X/%X",
6195-
(uint32) (XLogCtl->lastReplayedEndRecPtr >> 32),
6196-
(uint32) XLogCtl->lastReplayedEndRecPtr)));
6195+
(uint32) (lastReplayedEndRecPtr >> 32),
6196+
(uint32) lastReplayedEndRecPtr)));
61976197
}
61986198

61996199
/*

0 commit comments

Comments
 (0)