Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd0d9344

Browse files
committed
Fix cache invalidation bug in recovery_prefetch.
XLogPageRead() can retry internally after a pread() system call hassucceeded, in the case of short reads, and page validation failureswhile in standby mode (see commit0668719). Due to an oversight incommit3f1ce97, these cases could leave stale data in the internalcache of xlogreader.c without marking it invalid. The main defenseagainst stale cached data on failure to read a page was in the errorhandling path of the calling function ReadPageInternal(), but thatwasn't quite enough for errors handled internally by XLogPageRead()'sretry loop if we then exited with XLREAD_WOULDBLOCK.1. ReadPageInternal() now marks the cache invalid before calling the page_read callback, by setting state->readLen to 0. It'll be set to a non-zero value only after a successful read. It'll stay valid as long as the caller requests data in the cached range.2. XLogPageRead() no long performs internal retries while reading ahead. While such retries should work, the general philosophy is that we should give up prefetching if anything unusual happens so we can handle it when recovery catches up, to reduce the complexity of the system. Let's do that here too.3. While here, a new function XLogReaderResetError() improves the separation between xlogrecovery.c and xlogreader.c, where the former previously clobbered the latter's internal error buffer directly. The new function makes this more explicit, and also clears a related flag, without which a standby would needlessly retry in the outer function.Thanks to Noah Misch for tracking down the conditions required for arare build farm failure in src/bin/pg_ctl/t/003_promote.pl, andproviding a reproducer.Back-patch to 15.Reported-by: Noah Misch <noah@leadboat.com>Discussion:https://postgr.es/m/20220807003627.GA4168930%40rfd.leadboat.com
1 parentab31318 commitd0d9344

File tree

3 files changed

+31
-6
lines changed

3 files changed

+31
-6
lines changed

‎src/backend/access/transam/xlogreader.c‎

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -986,6 +986,13 @@ ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr, int reqLen)
986986
targetPageOff==state->segoff&&reqLen <=state->readLen)
987987
returnstate->readLen;
988988

989+
/*
990+
* Invalidate contents of internal buffer before read attempt. Just set
991+
* the length to 0, rather than a full XLogReaderInvalReadState(), so we
992+
* don't forget the segment we last successfully read.
993+
*/
994+
state->readLen=0;
995+
989996
/*
990997
* Data is not in our buffer.
991998
*
@@ -1066,11 +1073,8 @@ ReadPageInternal(XLogReaderState *state, XLogRecPtr pageptr, int reqLen)
10661073
returnreadLen;
10671074

10681075
err:
1069-
if (state->errormsg_buf[0]!='\0')
1070-
{
1071-
state->errormsg_deferred= true;
1072-
XLogReaderInvalReadState(state);
1073-
}
1076+
XLogReaderInvalReadState(state);
1077+
10741078
returnXLREAD_FAIL;
10751079
}
10761080

@@ -1322,6 +1326,16 @@ XLogReaderValidatePageHeader(XLogReaderState *state, XLogRecPtr recptr,
13221326
return true;
13231327
}
13241328

1329+
/*
1330+
* Forget about an error produced by XLogReaderValidatePageHeader().
1331+
*/
1332+
void
1333+
XLogReaderResetError(XLogReaderState*state)
1334+
{
1335+
state->errormsg_buf[0]='\0';
1336+
state->errormsg_deferred= false;
1337+
}
1338+
13251339
/*
13261340
* Find the first record with an lsn >= RecPtr.
13271341
*

‎src/backend/access/transam/xlogrecovery.c‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3339,13 +3339,21 @@ XLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr, int reqLen,
33393339
(errmsg_internal("%s",xlogreader->errormsg_buf)));
33403340

33413341
/* reset any error XLogReaderValidatePageHeader() might have set */
3342-
xlogreader->errormsg_buf[0]='\0';
3342+
XLogReaderResetError(xlogreader);
33433343
gotonext_record_is_invalid;
33443344
}
33453345

33463346
returnreadLen;
33473347

33483348
next_record_is_invalid:
3349+
3350+
/*
3351+
* If we're reading ahead, give up fast. Retries and error reporting will
3352+
* be handled by a later read when recovery catches up to this point.
3353+
*/
3354+
if (xlogreader->nonblocking)
3355+
returnXLREAD_WOULDBLOCK;
3356+
33493357
lastSourceFailed= true;
33503358

33513359
if (readFile >=0)

‎src/include/access/xlogreader.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,9 @@ extern DecodedXLogRecord *XLogReadAhead(XLogReaderState *state,
373373
externboolXLogReaderValidatePageHeader(XLogReaderState*state,
374374
XLogRecPtrrecptr,char*phdr);
375375

376+
/* Forget error produced by XLogReaderValidatePageHeader(). */
377+
externvoidXLogReaderResetError(XLogReaderState*state);
378+
376379
/*
377380
* Error information from WALRead that both backend and frontend caller can
378381
* process. Currently only errors from pg_pread can be reported.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp