From c1c9537f045ba7293416711347c7113fa8ec33f9 Mon Sep 17 00:00:00 2001
From: Melanie Plageman <melanieplageman@gmail.com>
Date: Fri, 5 Apr 2024 02:50:42 -0400
Subject: [PATCH v15 12/13] Move BitmapHeapScan initialization to helper

Author: Melanie Plageman
Discussion: https://postgr.es/m/CAAKRu_ZwCwWFeL_H3ia26bP2e7HiKLWt0ZmGXPVwPO6uXq0vaA%40mail.gmail.com
---
 src/backend/executor/nodeBitmapHeapscan.c | 170 ++++++++++++----------
 1 file changed, 92 insertions(+), 78 deletions(-)

diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c
index d22a433f06..aaeece6697 100644
--- a/src/backend/executor/nodeBitmapHeapscan.c
+++ b/src/backend/executor/nodeBitmapHeapscan.c
@@ -109,6 +109,94 @@ bhs_end_iterate(BitmapHeapIterator *iterator)
 }
 
 
+ /*
+  * 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)
+{
+	Relation	rel = node->ss.ss_currentRelation;
+	bool		pf_maximum = 0;
+	bool		init_shared_state = false;
+	uint32		extra_flags = 0;
+
+	Assert(!node->initialized);
+
+	/*
+	 * The leader will immediately come out of the function, but others will
+	 * be blocked until leader populates the TBM and wakes them up.
+	 */
+	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 (!node->pstate || init_shared_state)
+	{
+		node->tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node));
+
+		if (!node->tbm || !IsA(node->tbm, TIDBitmap))
+			elog(ERROR, "unrecognized result from subplan");
+
+		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.
+			 */
+			node->pstate->tbmiterator = tbm_prepare_shared_iterate(node->tbm);
+
+#ifdef USE_PREFETCH
+			if (pf_maximum > 0)
+			{
+				node->pstate->prefetch_iterator =
+					tbm_prepare_shared_iterate(node->tbm);
+			}
+#endif
+			/* We have initialized the shared state so wake up others. */
+			BitmapDoneInitializingSharedState(node->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;
+
+	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
  *
@@ -124,88 +212,14 @@ BitmapHeapNext(BitmapHeapScanState *node)
 
 	/*
 	 * 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.
+	 * the iteration over the bitmap. This happens on rescan as well.
 	 */
 	if (!node->initialized)
 	{
-		Relation	rel = node->ss.ss_currentRelation;
-		bool		pf_maximum = 0;
-		bool		init_shared_state = false;
-		uint32		extra_flags = 0;
-
-		/*
-		 * The leader will immediately come out of the function, but others
-		 * will be blocked until leader populates the TBM and wakes them up.
-		 */
-		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 (!node->pstate || init_shared_state)
-		{
-			node->tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node));
-
-			if (!node->tbm || !IsA(node->tbm, TIDBitmap))
-				elog(ERROR, "unrecognized result from subplan");
-
-			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.
-				 */
-				node->pstate->tbmiterator = tbm_prepare_shared_iterate(node->tbm);
-
-#ifdef USE_PREFETCH
-				if (pf_maximum > 0)
-				{
-					node->pstate->prefetch_iterator =
-						tbm_prepare_shared_iterate(node->tbm);
-				}
-#endif
-				/* We have initialized the shared state so wake up others. */
-				BitmapDoneInitializingSharedState(node->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;
-
-		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;
 	}
 
-- 
2.40.1

