Skip to content

Commit 65f3940

Browse files
committed
Ensure correct minimum consistent point on standbys
Startup process has improved its calculation of incorrect minimum consistent point in 8d68ee6, which ensures that all WAL available gets replayed when doing crash recovery, and has introduced an incorrect calculation of the minimum recovery point for non-startup processes, which can cause incorrect page references on a standby when for example the background writer flushed a couple of pages on-disk but was not updating the control file to let a subsequent crash recovery replay to where it should have. The only case where this has been reported to be a problem is when a standby needs to calculate the latest removed xid when replaying a btree deletion record, so one would need connections on a standby that happen just after recovery has thought it reached a consistent point. Using a background worker which is started after the consistent point is reached would be the easiest way to get into problems if it connects to a database. Having clients which attempt to connect periodically could also be a problem, but the odds of seeing this problem are much lower. The fix used is pretty simple, as the idea is to give access to the minimum recovery point written in the control file to non-startup processes so as they use a reference, while the startup process still initializes its own references of the minimum consistent point so as the original problem with incorrect page references happening post-promotion with a crash do not show up. Reported-by: Alexander Kukushkin Diagnosed-by: Alexander Kukushkin Author: Michael Paquier Reviewed-by: Kyotaro Horiguchi, Alexander Kukushkin Discussion: https://postgr.es/m/153492341830.1368.3936905691758473953@wrigleys.postgresql.org Backpatch-through: 9.3
1 parent 9f3ade1 commit 65f3940

File tree

1 file changed

+25
-6
lines changed
  • src/backend/access/transam

1 file changed

+25
-6
lines changed

src/backend/access/transam/xlog.c

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1860,9 +1860,13 @@ UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force)
18601860
* i.e., we're doing crash recovery. We never modify the control file's
18611861
* value in that case, so we can short-circuit future checks here too. The
18621862
* local values of minRecoveryPoint and minRecoveryPointTLI should not be
1863-
* updated until crash recovery finishes.
1863+
* updated until crash recovery finishes. We only do this for the startup
1864+
* process as it should not update its own reference of minRecoveryPoint
1865+
* until it has finished crash recovery to make sure that all WAL
1866+
* available is replayed in this case. This also saves from extra locks
1867+
* taken on the control file from the startup process.
18641868
*/
1865-
if (XLogRecPtrIsInvalid(minRecoveryPoint))
1869+
if (XLogRecPtrIsInvalid(minRecoveryPoint) && InRecovery)
18661870
{
18671871
updateMinRecoveryPoint = false;
18681872
return;
@@ -1874,7 +1878,9 @@ UpdateMinRecoveryPoint(XLogRecPtr lsn, bool force)
18741878
minRecoveryPoint = ControlFile->minRecoveryPoint;
18751879
minRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
18761880

1877-
if (force || minRecoveryPoint < lsn)
1881+
if (XLogRecPtrIsInvalid(minRecoveryPoint))
1882+
updateMinRecoveryPoint = false;
1883+
else if (force || minRecoveryPoint < lsn)
18781884
{
18791885
/* use volatile pointer to prevent code rearrangement */
18801886
volatile XLogCtlData *xlogctl = XLogCtl;
@@ -2218,9 +2224,11 @@ XLogNeedsFlush(XLogRecPtr record)
22182224
* An invalid minRecoveryPoint means that we need to recover all the
22192225
* WAL, i.e., we're doing crash recovery. We never modify the control
22202226
* file's value in that case, so we can short-circuit future checks
2221-
* here too.
2227+
* here too. This triggers a quick exit path for the startup process,
2228+
* which cannot update its local copy of minRecoveryPoint as long as
2229+
* it has not replayed all WAL available when doing crash recovery.
22222230
*/
2223-
if (XLogRecPtrIsInvalid(minRecoveryPoint))
2231+
if (XLogRecPtrIsInvalid(minRecoveryPoint) && InRecovery)
22242232
updateMinRecoveryPoint = false;
22252233

22262234
/* Quick exit if already known to be updated or cannot be updated */
@@ -2237,8 +2245,19 @@ XLogNeedsFlush(XLogRecPtr record)
22372245
minRecoveryPointTLI = ControlFile->minRecoveryPointTLI;
22382246
LWLockRelease(ControlFileLock);
22392247

2248+
/*
2249+
* Check minRecoveryPoint for any other process than the startup
2250+
* process doing crash recovery, which should not update the control
2251+
* file value if crash recovery is still running.
2252+
*/
2253+
if (XLogRecPtrIsInvalid(minRecoveryPoint))
2254+
updateMinRecoveryPoint = false;
2255+
22402256
/* check again */
2241-
return record > minRecoveryPoint;
2257+
if (record <= minRecoveryPoint || !updateMinRecoveryPoint)
2258+
return false;
2259+
else
2260+
return true;
22422261
}
22432262

22442263
/* Quick exit if already known flushed */

0 commit comments

Comments
 (0)