From d66c526696f6bcb9d6aa0a8b234d51c58866a6ff Mon Sep 17 00:00:00 2001
From: Melanie Plageman <melanieplageman@gmail.com>
Date: Fri, 5 Apr 2024 19:02:38 -0400
Subject: [PATCH v16 17/18] Move BitmapHeapScan initialization to helper

Author: Melanie Plageman
Discussion: https://postgr.es/m/CAAKRu_ZwCwWFeL_H3ia26bP2e7HiKLWt0ZmGXPVwPO6uXq0vaA%40mail.gmail.com
---
 src/backend/executor/nodeBitmapHeapscan.c | 182 +++++++++++-----------
 src/include/access/tableam.h              |   6 +-
 2 files changed, 98 insertions(+), 90 deletions(-)

diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index ae36dfd773..ce47cd51bd 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -109,6 +109,97 @@ bhs_end_iterate(BitmapHeapIterator *iterator)
 	iterator->exhausted = true;
 }
 
+ /*
+  * If we haven't yet performed the underlying index scan, do it, and begin
+  * the iteration over the bitmap.
+  *
+  * For prefetching, we use *two* iterators, one for the pages we are actually
+  * scanning and another that runs ahead of the first for prefetching.
+  * node->prefetch_pages tracks exactly how many pages ahead the prefetch
+  * iterator is.  Also, node->prefetch_target tracks the desired prefetch
+  * distance, which starts small and increases up to the
+  * scan->prefetch_maximum.  This is to avoid doing a lot of prefetching in a
+  * scan that stops after a few tuples because of a LIMIT.
+  */
+static void
+BitmapHeapInitialize(BitmapHeapScanState *node)
+{
+	TIDBitmap  *tbm;
+	ParallelBitmapHeapState *pstate = node->pstate;
+	Relation	rel = node->ss.ss_currentRelation;
+	uint32		extra_flags = 0;
+	bool		pf_maximum = 0;
+
+	/*
+	 * The leader will immediately come out of the function, but others will
+	 * be blocked until leader populates the TBM and wakes them up.
+	 */
+	bool		init_shared_state = node->pstate ?
+		BitmapShouldInitializeSharedState(node->pstate) : false;
+
+	/*
+	 * Maximum number of prefetches for the tablespace if configured,
+	 * otherwise the current value of the effective_io_concurrency GUC.
+	 */
+#ifdef USE_PREFETCH
+	pf_maximum = get_tablespace_io_concurrency(rel->rd_rel->reltablespace);
+#endif
+
+
+	if (!pstate || init_shared_state)
+	{
+		tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node));
+
+		if (!tbm || !IsA(tbm, TIDBitmap))
+			elog(ERROR, "unrecognized result from subplan");
+		node->tbm = tbm;
+
+		if (init_shared_state)
+		{
+			/*
+			 * Prepare to iterate over the TBM. This will return the
+			 * dsa_pointer of the iterator state which will be used by
+			 * multiple processes to iterate jointly.
+			 */
+			pstate->tbmiterator = tbm_prepare_shared_iterate(tbm);
+#ifdef USE_PREFETCH
+			if (pf_maximum > 0)
+			{
+				pstate->prefetch_iterator =
+					tbm_prepare_shared_iterate(tbm);
+			}
+#endif
+			/* We have initialized the shared state so wake up others. */
+			BitmapDoneInitializingSharedState(pstate);
+		}
+	}
+
+	/*
+	 * We can potentially skip fetching heap pages if we do not need any
+	 * columns of the table, either for checking non-indexable quals or for
+	 * returning data.  This test is a bit simplistic, as it checks the
+	 * stronger condition that there's no qual or return tlist at all. But in
+	 * most cases it's probably not worth working harder than that.
+	 */
+	if (node->ss.ps.plan->qual != NIL || node->ss.ps.plan->targetlist != NIL)
+		extra_flags |= SO_NEED_TUPLE;
+
+	/*
+	 * If this is the first scan of the underlying table, create the table
+	 * scan descriptor and begin the scan.
+	 */
+	node->ss.ss_currentScanDesc = table_beginscan_bm(node->ss.ss_currentScanDesc,
+													 rel,
+													 node->ss.ps.state->es_snapshot,
+													 extra_flags,
+													 pf_maximum,
+													 node->tbm,
+													 node->pstate,
+													 node->ss.ps.state->es_query_dsa);
+
+
+	node->initialized = true;
+}
 
 /* ----------------------------------------------------------------
  *		BitmapHeapNext
@@ -121,9 +212,7 @@ BitmapHeapNext(BitmapHeapScanState *node)
 {
 	ExprContext *econtext;
 	TableScanDesc scan;
-	TIDBitmap  *tbm;
 	TupleTableSlot *slot;
-	ParallelBitmapHeapState *pstate = node->pstate;
 
 	/*
 	 * extract necessary information from index scan node
@@ -131,97 +220,16 @@ BitmapHeapNext(BitmapHeapScanState *node)
 	econtext = node->ss.ps.ps_ExprContext;
 	slot = node->ss.ss_ScanTupleSlot;
 	scan = node->ss.ss_currentScanDesc;
-	tbm = node->tbm;
 
 	/*
 	 * If we haven't yet performed the underlying index scan, do it, and begin
-	 * the iteration over the bitmap.
-	 *
-	 * For prefetching, we use *two* iterators, one for the pages we are
-	 * actually scanning and another that runs ahead of the first for
-	 * prefetching.  node->prefetch_pages tracks exactly how many pages ahead
-	 * the prefetch iterator is.  Also, node->prefetch_target tracks the
-	 * desired prefetch distance, which starts small and increases up to the
-	 * node->prefetch_maximum.  This is to avoid doing a lot of prefetching in
-	 * a scan that stops after a few tuples because of a LIMIT.
+	 * the iteration over the bitmap. This happens on rescan as well.
 	 */
 	if (!node->initialized)
 	{
-		Relation	rel = node->ss.ss_currentRelation;
-		uint32		extra_flags = 0;
-		bool		pf_maximum = 0;
-
-		/*
-		 * The leader will immediately come out of the function, but others
-		 * will be blocked until leader populates the TBM and wakes them up.
-		 */
-		bool		init_shared_state = node->pstate ?
-			BitmapShouldInitializeSharedState(node->pstate) : false;
-
-		/*
-		 * Maximum number of prefetches for the tablespace if configured,
-		 * otherwise the current value of the effective_io_concurrency GUC.
-		 */
-#ifdef USE_PREFETCH
-		pf_maximum = get_tablespace_io_concurrency(rel->rd_rel->reltablespace);
-#endif
-
-
-		if (!pstate || init_shared_state)
-		{
-			tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node));
-
-			if (!tbm || !IsA(tbm, TIDBitmap))
-				elog(ERROR, "unrecognized result from subplan");
-			node->tbm = tbm;
-
-			if (init_shared_state)
-			{
-				/*
-				 * Prepare to iterate over the TBM. This will return the
-				 * dsa_pointer of the iterator state which will be used by
-				 * multiple processes to iterate jointly.
-				 */
-				pstate->tbmiterator = tbm_prepare_shared_iterate(tbm);
-#ifdef USE_PREFETCH
-				if (pf_maximum > 0)
-				{
-					pstate->prefetch_iterator =
-						tbm_prepare_shared_iterate(tbm);
-				}
-#endif
-				/* We have initialized the shared state so wake up others. */
-				BitmapDoneInitializingSharedState(pstate);
-			}
-		}
-
-		/*
-		 * We can potentially skip fetching heap pages if we do not need any
-		 * columns of the table, either for checking non-indexable quals or
-		 * for returning data.  This test is a bit simplistic, as it checks
-		 * the stronger condition that there's no qual or return tlist at all.
-		 * But in most cases it's probably not worth working harder than that.
-		 */
-		if (node->ss.ps.plan->qual != NIL || node->ss.ps.plan->targetlist != NIL)
-			extra_flags |= SO_NEED_TUPLE;
-
-		/*
-		 * If this is the first scan of the underlying table, create the table
-		 * scan descriptor and begin the scan.
-		 */
-		scan = table_beginscan_bm(node->ss.ss_currentScanDesc,
-								  rel,
-								  node->ss.ps.state->es_snapshot,
-								  extra_flags,
-								  pf_maximum,
-								  node->tbm,
-								  node->pstate,
-								  node->ss.ps.state->es_query_dsa);
-
-		node->ss.ss_currentScanDesc = scan;
-
-		node->initialized = true;
-
+		BitmapHeapInitialize(node);
+		/* We may have a new scan descriptor */
+		scan = node->ss.ss_currentScanDesc;
 		goto new_page;
 	}
 
diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h
index 9ec0a1da2b..eea7b7ff20 100644
--- a/src/include/access/tableam.h
+++ b/src/include/access/tableam.h
@@ -791,9 +791,9 @@ typedef struct TableAmRoutine
 	 */
 
 	/*
-	 * Prepare to fetch / check / return tuples from `blockno` as part of a
-	 * bitmap table scan. `scan` was started via table_beginscan_bm(). Return
-	 * false if the bitmap is exhausted and true otherwise.
+	 * Prepare to fetch / check / return tuples as part of a bitmap table
+	 * scan. `scan` was started via table_beginscan_bm(). Return false if the
+	 * bitmap is exhausted and true otherwise.
 	 *
 	 * This will typically read and pin the target block, and do the necessary
 	 * work to allow scan_bitmap_next_tuple() to return tuples (e.g. it might
-- 
2.40.1

