diff options
author | Melanie Plageman <melanieplageman@gmail.com> | 2025-01-30 15:26:55 -0500 |
---|---|---|
committer | Melanie Plageman <melanieplageman@gmail.com> | 2025-01-30 15:28:33 -0500 |
commit | a5358c14b2fe2210a1ac0b836f8d54723043fba2 (patch) | |
tree | 1bba2e0c58b6ee76e167e820af109ef332885127 /src/backend/executor/nodeBitmapHeapscan.c | |
parent | 115a365519bfd53a65bf17d253b26902eff0c337 (diff) | |
download | postgresql-a5358c14b2fe2210a1ac0b836f8d54723043fba2.tar.gz postgresql-a5358c14b2fe2210a1ac0b836f8d54723043fba2.zip |
Move BitmapTableScan per-scan setup into a helper
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
Diffstat (limited to 'src/backend/executor/nodeBitmapHeapscan.c')
-rw-r--r-- | src/backend/executor/nodeBitmapHeapscan.c | 206 |
1 files changed, 107 insertions, 99 deletions
diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c index be616683f98..be0d24d901b 100644 --- a/src/backend/executor/nodeBitmapHeapscan.c +++ b/src/backend/executor/nodeBitmapHeapscan.c @@ -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; } |