mirror of
https://github.com/postgres/postgres.git
synced 2025-07-31 22:04:40 +03:00
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
This commit is contained in:
@ -48,6 +48,7 @@
|
|||||||
#include "utils/rel.h"
|
#include "utils/rel.h"
|
||||||
#include "utils/spccache.h"
|
#include "utils/spccache.h"
|
||||||
|
|
||||||
|
static void BitmapTableScanSetup(BitmapHeapScanState *node);
|
||||||
static TupleTableSlot *BitmapHeapNext(BitmapHeapScanState *node);
|
static TupleTableSlot *BitmapHeapNext(BitmapHeapScanState *node);
|
||||||
static inline void BitmapDoneInitializingSharedState(ParallelBitmapHeapState *pstate);
|
static inline void BitmapDoneInitializingSharedState(ParallelBitmapHeapState *pstate);
|
||||||
static inline void BitmapAdjustPrefetchIterator(BitmapHeapScanState *node);
|
static inline void BitmapAdjustPrefetchIterator(BitmapHeapScanState *node);
|
||||||
@ -57,6 +58,107 @@ static inline void BitmapPrefetch(BitmapHeapScanState *node,
|
|||||||
static bool BitmapShouldInitializeSharedState(ParallelBitmapHeapState *pstate);
|
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
|
* BitmapHeapNext
|
||||||
*
|
*
|
||||||
@ -68,10 +170,11 @@ BitmapHeapNext(BitmapHeapScanState *node)
|
|||||||
{
|
{
|
||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
TableScanDesc scan;
|
TableScanDesc scan;
|
||||||
TIDBitmap *tbm;
|
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
|
|
||||||
|
#ifdef USE_PREFETCH
|
||||||
ParallelBitmapHeapState *pstate = node->pstate;
|
ParallelBitmapHeapState *pstate = node->pstate;
|
||||||
dsa_area *dsa = node->ss.ps.state->es_query_dsa;
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* extract necessary information from index scan node
|
* extract necessary information from index scan node
|
||||||
@ -79,110 +182,15 @@ BitmapHeapNext(BitmapHeapScanState *node)
|
|||||||
econtext = node->ss.ps.ps_ExprContext;
|
econtext = node->ss.ps.ps_ExprContext;
|
||||||
slot = node->ss.ss_ScanTupleSlot;
|
slot = node->ss.ss_ScanTupleSlot;
|
||||||
scan = node->ss.ss_currentScanDesc;
|
scan = node->ss.ss_currentScanDesc;
|
||||||
tbm = node->tbm;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we haven't yet performed the underlying index scan, do it, and begin
|
* If we haven't yet performed the underlying index scan, do it, and begin
|
||||||
* the iteration over the bitmap.
|
* 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)
|
if (!node->initialized)
|
||||||
{
|
{
|
||||||
TBMIterator tbmiterator;
|
BitmapTableScanSetup(node);
|
||||||
|
scan = node->ss.ss_currentScanDesc;
|
||||||
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;
|
|
||||||
|
|
||||||
goto new_page;
|
goto new_page;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user