From f9a53985e0e30659caa41c95c85001c91b3deb5f Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Mon, 30 Dec 2019 16:43:50 +1300
Subject: [PATCH 4/5] Allow PrefetchBuffer() to report the outcome.

Report when a relation's backing file is missing, to prepare
for use during recovery.  This will be used to handle cases of
relations that are referenced in the WAL but have been unlinked
already due to actions covered by WAL records that haven't been
replayed yet, after a crash.

Also report whether a prefetch was actually initiated, so that
callers can limit the number of concurrent I/Os they try to
issue, without counting the prefetch calls that did nothing
because the page was already in our buffers.

Author: Thomas Munro
Discussion: https://postgr.es/m/CA%2BhUKGJ4VJN8ttxScUFM8dOKX0BrBiboo5uz1cq%3DAovOddfHpA%40mail.gmail.com
---
 src/backend/storage/buffer/bufmgr.c |  9 +++++++--
 src/backend/storage/smgr/md.c       |  9 +++++++--
 src/backend/storage/smgr/smgr.c     | 10 +++++++---
 src/include/storage/bufmgr.h        | 12 ++++++++++--
 src/include/storage/md.h            |  2 +-
 src/include/storage/smgr.h          |  2 +-
 6 files changed, 33 insertions(+), 11 deletions(-)

diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 6e0875022c..5dbbcf8111 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -519,7 +519,7 @@ ComputeIoConcurrency(int io_concurrency, double *target)
 	return (new_prefetch_pages >= 0.0 && new_prefetch_pages < (double) INT_MAX);
 }
 
-void
+PrefetchBufferResult
 SharedPrefetchBuffer(SMgrRelation smgr_reln, ForkNumber forkNum, BlockNumber blockNum)
 {
 #ifdef USE_PREFETCH
@@ -545,7 +545,11 @@ SharedPrefetchBuffer(SMgrRelation smgr_reln, ForkNumber forkNum, BlockNumber blo
 
 	/* If not in buffers, initiate prefetch */
 	if (buf_id < 0)
-		smgrprefetch(smgr_reln, forkNum, blockNum);
+	{
+		if (!smgrprefetch(smgr_reln, forkNum, blockNum))
+			return PREFETCH_BUFFER_NOREL;
+		return PREFETCH_BUFFER_MISS;
+	}
 
 	/*
 	 * If the block *is* in buffers, we do nothing.  This is not really ideal:
@@ -559,6 +563,7 @@ SharedPrefetchBuffer(SMgrRelation smgr_reln, ForkNumber forkNum, BlockNumber blo
 	 * a problem to justify that.
 	 */
 #endif
+	return PREFETCH_BUFFER_HIT;
 }
 
 /*
diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
index c5b771c531..ba12fc2077 100644
--- a/src/backend/storage/smgr/md.c
+++ b/src/backend/storage/smgr/md.c
@@ -525,14 +525,17 @@ mdclose(SMgrRelation reln, ForkNumber forknum)
 /*
  *	mdprefetch() -- Initiate asynchronous read of the specified block of a relation
  */
-void
+bool
 mdprefetch(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum)
 {
 #ifdef USE_PREFETCH
 	off_t		seekpos;
 	MdfdVec    *v;
 
-	v = _mdfd_getseg(reln, forknum, blocknum, false, EXTENSION_FAIL);
+	v = _mdfd_getseg(reln, forknum, blocknum, false,
+					 InRecovery ? EXTENSION_RETURN_NULL : EXTENSION_FAIL);
+	if (v == NULL)
+		return false;
 
 	seekpos = (off_t) BLCKSZ * (blocknum % ((BlockNumber) RELSEG_SIZE));
 
@@ -540,6 +543,8 @@ mdprefetch(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum)
 
 	(void) FilePrefetch(v->mdfd_vfd, seekpos, BLCKSZ, WAIT_EVENT_DATA_FILE_PREFETCH);
 #endif							/* USE_PREFETCH */
+
+	return true;
 }
 
 /*
diff --git a/src/backend/storage/smgr/smgr.c b/src/backend/storage/smgr/smgr.c
index 360b5bf5bf..c39dd533e6 100644
--- a/src/backend/storage/smgr/smgr.c
+++ b/src/backend/storage/smgr/smgr.c
@@ -49,7 +49,7 @@ typedef struct f_smgr
 								bool isRedo);
 	void		(*smgr_extend) (SMgrRelation reln, ForkNumber forknum,
 								BlockNumber blocknum, char *buffer, bool skipFsync);
-	void		(*smgr_prefetch) (SMgrRelation reln, ForkNumber forknum,
+	bool		(*smgr_prefetch) (SMgrRelation reln, ForkNumber forknum,
 								  BlockNumber blocknum);
 	void		(*smgr_read) (SMgrRelation reln, ForkNumber forknum,
 							  BlockNumber blocknum, char *buffer);
@@ -489,11 +489,15 @@ smgrextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
 
 /*
  *	smgrprefetch() -- Initiate asynchronous read of the specified block of a relation.
+ *
+ *		In recovery only, this can return false to indicate that a file
+ *		doesn't	exist (presumably it has been dropped by a later WAL
+ *		record).
  */
-void
+bool
 smgrprefetch(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum)
 {
-	smgrsw[reln->smgr_which].smgr_prefetch(reln, forknum, blocknum);
+	return smgrsw[reln->smgr_which].smgr_prefetch(reln, forknum, blocknum);
 }
 
 /*
diff --git a/src/include/storage/bufmgr.h b/src/include/storage/bufmgr.h
index 89a47afec1..5d7a796ba0 100644
--- a/src/include/storage/bufmgr.h
+++ b/src/include/storage/bufmgr.h
@@ -159,12 +159,20 @@ extern PGDLLIMPORT int32 *LocalRefCount;
  */
 #define BufferGetPage(buffer) ((Page)BufferGetBlock(buffer))
 
+typedef enum PrefetchBufferResult
+{
+	PREFETCH_BUFFER_HIT,
+	PREFETCH_BUFFER_MISS,
+	PREFETCH_BUFFER_NOREL
+} PrefetchBufferResult;
+
 /*
  * prototypes for functions in bufmgr.c
  */
 extern bool ComputeIoConcurrency(int io_concurrency, double *target);
-extern void SharedPrefetchBuffer(SMgrRelation smgr_reln, ForkNumber forkNum,
-								 BlockNumber blockNum);
+extern PrefetchBufferResult SharedPrefetchBuffer(SMgrRelation smgr_reln,
+												 ForkNumber forkNum,
+												 BlockNumber blockNum);
 extern void PrefetchBuffer(Relation reln, ForkNumber forkNum,
 						   BlockNumber blockNum);
 extern Buffer ReadBuffer(Relation reln, BlockNumber blockNum);
diff --git a/src/include/storage/md.h b/src/include/storage/md.h
index ec7630ce3b..07fd1bb7d0 100644
--- a/src/include/storage/md.h
+++ b/src/include/storage/md.h
@@ -28,7 +28,7 @@ extern bool mdexists(SMgrRelation reln, ForkNumber forknum);
 extern void mdunlink(RelFileNodeBackend rnode, ForkNumber forknum, bool isRedo);
 extern void mdextend(SMgrRelation reln, ForkNumber forknum,
 					 BlockNumber blocknum, char *buffer, bool skipFsync);
-extern void mdprefetch(SMgrRelation reln, ForkNumber forknum,
+extern bool mdprefetch(SMgrRelation reln, ForkNumber forknum,
 					   BlockNumber blocknum);
 extern void mdread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
 				   char *buffer);
diff --git a/src/include/storage/smgr.h b/src/include/storage/smgr.h
index 243822137c..dc740443e2 100644
--- a/src/include/storage/smgr.h
+++ b/src/include/storage/smgr.h
@@ -92,7 +92,7 @@ extern void smgrdounlink(SMgrRelation reln, bool isRedo);
 extern void smgrdounlinkall(SMgrRelation *rels, int nrels, bool isRedo);
 extern void smgrextend(SMgrRelation reln, ForkNumber forknum,
 					   BlockNumber blocknum, char *buffer, bool skipFsync);
-extern void smgrprefetch(SMgrRelation reln, ForkNumber forknum,
+extern bool smgrprefetch(SMgrRelation reln, ForkNumber forknum,
 						 BlockNumber blocknum);
 extern void smgrread(SMgrRelation reln, ForkNumber forknum,
 					 BlockNumber blocknum, char *buffer);
-- 
2.20.1

