From e488e20f7c364ba1adaae8d1f6ea92a7f5d0bda6 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Mon, 11 Apr 2022 17:16:24 +1200
Subject: [PATCH] Don't retry restore_command while reading ahead.

Suppress further attempts to read ahead in the WAL if we run out of
data, until records already decoded have been replayed.  When replaying
from archives, this avoids repeatedly retrying the restore_command until
after we've slept for 5 seconds.

When replaying from a network stream, this makes us less aggressive in
theory, but we probably can't benefit from being more aggressive yet
anyway as the flushedUpto variable doesn't advance until we run out of
data (though we could improve that in future).

While here, fix a potential off-by one confusion with the
no_readahead_until mechanism: we suppress readahead until after the
record that begins at that LSN has been replayed (ie we are replaying a
higher LSN), so change < to <=.

Defect in commit 5dc0418f.

Reported-by: Andres Freund <andres@anarazel.de>
Discussion: https://postgr.es/m/20220409005910.alw46xqmmgny2sgr%40alap3.anarazel.de
---
 src/backend/access/transam/xlogprefetcher.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/src/backend/access/transam/xlogprefetcher.c b/src/backend/access/transam/xlogprefetcher.c
index f3428888d2..43e82b65c2 100644
--- a/src/backend/access/transam/xlogprefetcher.c
+++ b/src/backend/access/transam/xlogprefetcher.c
@@ -487,8 +487,8 @@ XLogPrefetcherNextBlock(uintptr_t pgsr_private, XLogRecPtr *lsn)
 			 */
 			nonblocking = XLogReaderHasQueuedRecordOrError(reader);
 
-			/* Certain records act as barriers for all readahead. */
-			if (nonblocking && replaying_lsn < prefetcher->no_readahead_until)
+			/* Readahead is disabled until we replay past a certain point. */
+			if (nonblocking && replaying_lsn <= prefetcher->no_readahead_until)
 				return LRQ_NEXT_AGAIN;
 
 			record = XLogReadAhead(prefetcher->reader, nonblocking);
@@ -496,8 +496,13 @@ XLogPrefetcherNextBlock(uintptr_t pgsr_private, XLogRecPtr *lsn)
 			{
 				/*
 				 * We can't read any more, due to an error or lack of data in
-				 * nonblocking mode.
+				 * nonblocking mode.  Don't try to read ahead again until we've
+				 * replayed everything already decoded.
 				 */
+				if (nonblocking && prefetcher->reader->decode_queue_tail)
+					prefetcher->no_readahead_until =
+						prefetcher->reader->decode_queue_tail->lsn;
+
 				return LRQ_NEXT_AGAIN;
 			}
 
-- 
2.30.2

