]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Move BitmapTableScan per-scan setup into a helper
authorMelanie Plageman <melanieplageman@gmail.com>
Thu, 30 Jan 2025 20:26:55 +0000 (15:26 -0500)
committerMelanie Plageman <melanieplageman@gmail.com>
Thu, 30 Jan 2025 20:28:33 +0000 (15:28 -0500)
Add BitmapTableScanSetup(), a helper which contains all of the code that
must be done on every scan of the table in a bitmap table scan. This
includes scanning the index, building the bitmap, and setting up the
scan descriptors.

Pushing this setup into a helper function makes BitmapHeapNext() more
readable.

Reviewed-by: Nazir Bilal Yavuz <byavuz81@gmail.com>
Discussion: https://postgr.es/m/CAN55FZ1vXu%2BZdT0_MM-i1vbTdfHHf0KR3cK6R5gs6dNNNpyrJw%40mail.gmail.com

src/backend/executor/nodeBitmapHeapscan.c

index be616683f987f71ca7173c2883d74d72696651d9..be0d24d901b5e32fc22d36b9a816ecc2e1373d37 100644 (file)
@@ -48,6 +48,7 @@
 #include "utils/rel.h"
 #include "utils/spccache.h"
 
+static void BitmapTableScanSetup(BitmapHeapScanState *node);
 static TupleTableSlot *BitmapHeapNext(BitmapHeapScanState *node);
 static inline void BitmapDoneInitializingSharedState(ParallelBitmapHeapState *pstate);
 static inline void BitmapAdjustPrefetchIterator(BitmapHeapScanState *node);
@@ -57,6 +58,107 @@ static inline void BitmapPrefetch(BitmapHeapScanState *node,
 static bool BitmapShouldInitializeSharedState(ParallelBitmapHeapState *pstate);
 
 
+/*
+ * Do the underlying index scan, build the bitmap, set up the parallel state
+ * needed for parallel workers to iterate through the bitmap, and set up the
+ * underlying table scan descriptor.
+ *
+ * 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.
+ */
+static void
+BitmapTableScanSetup(BitmapHeapScanState *node)
+{
+       TBMIterator tbmiterator = {0};
+       ParallelBitmapHeapState *pstate = node->pstate;
+       dsa_area   *dsa = node->ss.ps.state->es_query_dsa;
+
+       if (!pstate)
+       {
+               node->tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node));
+
+               if (!node->tbm || !IsA(node->tbm, TIDBitmap))
+                       elog(ERROR, "unrecognized result from subplan");
+       }
+       else if (BitmapShouldInitializeSharedState(pstate))
+       {
+               /*
+                * The leader will immediately come out of the function, but others
+                * will be blocked until leader populates the TBM and wakes them up.
+                */
+               node->tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node));
+               if (!node->tbm || !IsA(node->tbm, TIDBitmap))
+                       elog(ERROR, "unrecognized result from subplan");
+
+               /*
+                * 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(node->tbm);
+
+#ifdef USE_PREFETCH
+               if (node->prefetch_maximum > 0)
+               {
+                       pstate->prefetch_iterator =
+                               tbm_prepare_shared_iterate(node->tbm);
+               }
+#endif                                                 /* USE_PREFETCH */
+
+               /* We have initialized the shared state so wake up others. */
+               BitmapDoneInitializingSharedState(pstate);
+       }
+
+       tbmiterator = tbm_begin_iterate(node->tbm, dsa,
+                                                                       pstate ?
+                                                                       pstate->tbmiterator :
+                                                                       InvalidDsaPointer);
+
+#ifdef USE_PREFETCH
+       if (node->prefetch_maximum > 0)
+               node->prefetch_iterator =
+                       tbm_begin_iterate(node->tbm, dsa,
+                                                         pstate ?
+                                                         pstate->prefetch_iterator :
+                                                         InvalidDsaPointer);
+#endif                                                 /* USE_PREFETCH */
+
+       /*
+        * If this is the first scan of the underlying table, create the table
+        * scan descriptor and begin the scan.
+        */
+       if (!node->ss.ss_currentScanDesc)
+       {
+               bool            need_tuples = false;
+
+               /*
+                * 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.
+                */
+               need_tuples = (node->ss.ps.plan->qual != NIL ||
+                                          node->ss.ps.plan->targetlist != NIL);
+
+               node->ss.ss_currentScanDesc =
+                       table_beginscan_bm(node->ss.ss_currentRelation,
+                                                          node->ss.ps.state->es_snapshot,
+                                                          0,
+                                                          NULL,
+                                                          need_tuples);
+       }
+
+       node->ss.ss_currentScanDesc->st.rs_tbmiterator = tbmiterator;
+       node->initialized = true;
+}
+
+
 /* ----------------------------------------------------------------
  *             BitmapHeapNext
  *
@@ -68,10 +170,11 @@ BitmapHeapNext(BitmapHeapScanState *node)
 {
        ExprContext *econtext;
        TableScanDesc scan;
-       TIDBitmap  *tbm;
        TupleTableSlot *slot;
+
+#ifdef USE_PREFETCH
        ParallelBitmapHeapState *pstate = node->pstate;
-       dsa_area   *dsa = node->ss.ps.state->es_query_dsa;
+#endif
 
        /*
         * extract necessary information from index scan node
@@ -79,110 +182,15 @@ 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.
         */
        if (!node->initialized)
        {
-               TBMIterator tbmiterator;
-
-               if (!pstate)
-               {
-                       tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node));
-
-                       if (!tbm || !IsA(tbm, TIDBitmap))
-                               elog(ERROR, "unrecognized result from subplan");
-
-                       node->tbm = tbm;
-               }
-               else if (BitmapShouldInitializeSharedState(pstate))
-               {
-                       /*
-                        * The leader will immediately come out of the function, but
-                        * others will be blocked until leader populates the TBM and wakes
-                        * them up.
-                        */
-                       tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node));
-                       if (!tbm || !IsA(tbm, TIDBitmap))
-                               elog(ERROR, "unrecognized result from subplan");
-
-                       node->tbm = tbm;
-
-                       /*
-                        * 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 (node->prefetch_maximum > 0)
-                       {
-                               pstate->prefetch_iterator =
-                                       tbm_prepare_shared_iterate(tbm);
-                       }
-#endif                                                 /* USE_PREFETCH */
-
-                       /* We have initialized the shared state so wake up others. */
-                       BitmapDoneInitializingSharedState(pstate);
-               }
-
-               tbmiterator = tbm_begin_iterate(tbm, dsa,
-                                                                               pstate ?
-                                                                               pstate->tbmiterator :
-                                                                               InvalidDsaPointer);
-
-#ifdef USE_PREFETCH
-               if (node->prefetch_maximum > 0)
-                       node->prefetch_iterator =
-                               tbm_begin_iterate(tbm, dsa,
-                                                                 pstate ?
-                                                                 pstate->prefetch_iterator :
-                                                                 InvalidDsaPointer);
-#endif                                                 /* USE_PREFETCH */
-
-               /*
-                * If this is the first scan of the underlying table, create the table
-                * scan descriptor and begin the scan.
-                */
-               if (!scan)
-               {
-                       bool            need_tuples = false;
-
-                       /*
-                        * 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.
-                        */
-                       need_tuples = (node->ss.ps.plan->qual != NIL ||
-                                                  node->ss.ps.plan->targetlist != NIL);
-
-                       scan = table_beginscan_bm(node->ss.ss_currentRelation,
-                                                                         node->ss.ps.state->es_snapshot,
-                                                                         0,
-                                                                         NULL,
-                                                                         need_tuples);
-
-                       node->ss.ss_currentScanDesc = scan;
-               }
-
-               scan->st.rs_tbmiterator = tbmiterator;
-               node->initialized = true;
-
+               BitmapTableScanSetup(node);
+               scan = node->ss.ss_currentScanDesc;
                goto new_page;
        }