From f0f3ec44f87b3dd4f7ec3e96e1057bef512cb00a Mon Sep 17 00:00:00 2001 From: Melanie Plageman Date: Tue, 21 May 2024 13:21:08 -0400 Subject: [PATCH v21 16/20] BitmapHeapScan: move per scan setup into a helper Add BitmapTableScanSetup() 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. Much of BitmapHeapNext() code was this setup, so it made sense to put it in a helper function. --- src/backend/executor/nodeBitmapHeapscan.c | 188 +++++++++++----------- 1 file changed, 96 insertions(+), 92 deletions(-) diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c index 12dc75d0d2a..03ef9d7bde7 100644 --- a/src/backend/executor/nodeBitmapHeapscan.c +++ b/src/backend/executor/nodeBitmapHeapscan.c @@ -53,122 +53,126 @@ static TupleTableSlot *BitmapHeapNext(BitmapHeapScanState *node); static inline void BitmapDoneInitializingSharedState(ParallelBitmapHeapState *pstate); static bool BitmapShouldInitializeSharedState(ParallelBitmapHeapState *pstate); - -/* ---------------------------------------------------------------- - * BitmapHeapNext - * - * Retrieve next tuple from the BitmapHeapScan node's currentRelation - * ---------------------------------------------------------------- +/* + * 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. */ -static TupleTableSlot * -BitmapHeapNext(BitmapHeapScanState *node) +static void +BitmapTableScanSetup(BitmapHeapScanState *node) { - ExprContext *econtext; - BitmapTableScanDesc *scan; - TupleTableSlot *slot; ParallelBitmapHeapState *pstate = node->pstate; dsa_area *dsa = node->ss.ps.state->es_query_dsa; + int prefetch_maximum = 0; /* - * extract necessary information from index scan node + * Maximum number of prefetches for the tablespace if configured, + * otherwise the current value of the effective_io_concurrency GUC. */ - econtext = node->ss.ps.ps_ExprContext; - slot = node->ss.ss_ScanTupleSlot; - scan = node->scandesc; +#ifdef USE_PREFETCH + Relation rel = node->ss.ss_currentRelation; + + prefetch_maximum = get_tablespace_io_concurrency(rel->rd_rel->reltablespace); +#endif /* - * If we haven't yet performed the underlying index scan, do it, and begin - * the iteration over the bitmap. + * Scan the index, build the bitmap, and set up shared state for parallel. */ - if (!node->initialized) + if (!pstate) { - int prefetch_maximum = 0; + node->tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node)); + if (!node->tbm || !IsA(node->tbm, TIDBitmap)) + elog(ERROR, "unrecognized result from subplan"); + } + else if (BitmapShouldInitializeSharedState(pstate)) + { /* - * Maximum number of prefetches for the tablespace if configured, - * otherwise the current value of the effective_io_concurrency GUC. + * The leader will immediately come out of the function, but others + * will be blocked until leader populates the TBM and wakes them up. */ -#ifdef USE_PREFETCH - Relation rel = node->ss.ss_currentRelation; - prefetch_maximum = get_tablespace_io_concurrency(rel->rd_rel->reltablespace); -#endif - - 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"); + node->tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node)); + if (!node->tbm || !IsA(node->tbm, TIDBitmap)) + elog(ERROR, "unrecognized result from subplan"); - /* - * Two iterators are used -- one for the pages being scanned and - * one for the blocks being prefetched. - */ + /* + * Two iterators are used -- one for the pages being scanned and one + * for the blocks being prefetched. + */ - /* - * 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); + /* + * 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 (prefetch_maximum > 0) - { - pstate->prefetch_iterator = - tbm_prepare_shared_iterate(node->tbm); - } -#endif - /* We have initialized the shared state so wake up others. */ - BitmapDoneInitializingSharedState(pstate); + if (prefetch_maximum > 0) + { + pstate->prefetch_iterator = + tbm_prepare_shared_iterate(node->tbm); } +#endif + /* We have initialized the shared state so wake up others. */ + BitmapDoneInitializingSharedState(pstate); + } + + /* + * If this is the first scan of the underlying table, create the table + * scan descriptor and begin the scan. + */ + if (!node->scan_in_progress) + { + bool need_tuples = false; /* - * If this is the first scan of the underlying table, create the table - * scan descriptor and begin the scan. + * 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->scan_in_progress) - { - bool need_tuples = false; + need_tuples = (node->ss.ps.plan->qual != NIL || + node->ss.ps.plan->targetlist != NIL); + + node->scandesc = table_beginscan_bm(node->ss.ss_currentRelation, + node->ss.ps.state->es_snapshot, + node->tbm, + pstate, + dsa, + need_tuples, prefetch_maximum); + node->scan_in_progress = true; + } + else + { + /* rescan to release any page pin */ + table_rescan_bm(node->scandesc, node->tbm, pstate, dsa); + } - /* - * 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, - node->tbm, - node->pstate, - dsa, - need_tuples, prefetch_maximum); - node->scandesc = scan; - node->scan_in_progress = true; - } - else - { - /* rescan to release any page pin */ - table_rescan_bm(scan, node->tbm, pstate, dsa); - } + node->initialized = true; +} - node->initialized = true; +/* ---------------------------------------------------------------- + * BitmapHeapNext + * + * Retrieve next tuple from the BitmapHeapScan node's currentRelation + * ---------------------------------------------------------------- + */ +static TupleTableSlot * +BitmapHeapNext(BitmapHeapScanState *node) +{ + ExprContext *econtext = node->ss.ps.ps_ExprContext; + TupleTableSlot *slot = node->ss.ss_ScanTupleSlot; + BitmapTableScanDesc *scan = node->scandesc; + /* + * If we haven't yet performed the underlying index scan, do it, and begin + * the iteration over the bitmap. + */ + if (!node->initialized) + { + BitmapTableScanSetup(node); + scan = node->scandesc; goto new_page; } -- 2.34.1