Skip to content

Commit a5358c1

Browse files
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
1 parent 115a365 commit a5358c1

File tree

1 file changed

+107
-99
lines changed

1 file changed

+107
-99
lines changed

src/backend/executor/nodeBitmapHeapscan.c

+107-99
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include "utils/rel.h"
4949
#include "utils/spccache.h"
5050

51+
static void BitmapTableScanSetup(BitmapHeapScanState *node);
5152
static TupleTableSlot *BitmapHeapNext(BitmapHeapScanState *node);
5253
static inline void BitmapDoneInitializingSharedState(ParallelBitmapHeapState *pstate);
5354
static inline void BitmapAdjustPrefetchIterator(BitmapHeapScanState *node);
@@ -57,6 +58,107 @@ static inline void BitmapPrefetch(BitmapHeapScanState *node,
5758
static bool BitmapShouldInitializeSharedState(ParallelBitmapHeapState *pstate);
5859

5960

61+
/*
62+
* Do the underlying index scan, build the bitmap, set up the parallel state
63+
* needed for parallel workers to iterate through the bitmap, and set up the
64+
* underlying table scan descriptor.
65+
*
66+
* For prefetching, we use *two* iterators, one for the pages we are actually
67+
* scanning and another that runs ahead of the first for prefetching.
68+
* node->prefetch_pages tracks exactly how many pages ahead the prefetch
69+
* iterator is. Also, node->prefetch_target tracks the desired prefetch
70+
* distance, which starts small and increases up to the
71+
* node->prefetch_maximum. This is to avoid doing a lot of prefetching in a
72+
* scan that stops after a few tuples because of a LIMIT.
73+
*/
74+
static void
75+
BitmapTableScanSetup(BitmapHeapScanState *node)
76+
{
77+
TBMIterator tbmiterator = {0};
78+
ParallelBitmapHeapState *pstate = node->pstate;
79+
dsa_area *dsa = node->ss.ps.state->es_query_dsa;
80+
81+
if (!pstate)
82+
{
83+
node->tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node));
84+
85+
if (!node->tbm || !IsA(node->tbm, TIDBitmap))
86+
elog(ERROR, "unrecognized result from subplan");
87+
}
88+
else if (BitmapShouldInitializeSharedState(pstate))
89+
{
90+
/*
91+
* The leader will immediately come out of the function, but others
92+
* will be blocked until leader populates the TBM and wakes them up.
93+
*/
94+
node->tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node));
95+
if (!node->tbm || !IsA(node->tbm, TIDBitmap))
96+
elog(ERROR, "unrecognized result from subplan");
97+
98+
/*
99+
* Prepare to iterate over the TBM. This will return the dsa_pointer
100+
* of the iterator state which will be used by multiple processes to
101+
* iterate jointly.
102+
*/
103+
pstate->tbmiterator = tbm_prepare_shared_iterate(node->tbm);
104+
105+
#ifdef USE_PREFETCH
106+
if (node->prefetch_maximum > 0)
107+
{
108+
pstate->prefetch_iterator =
109+
tbm_prepare_shared_iterate(node->tbm);
110+
}
111+
#endif /* USE_PREFETCH */
112+
113+
/* We have initialized the shared state so wake up others. */
114+
BitmapDoneInitializingSharedState(pstate);
115+
}
116+
117+
tbmiterator = tbm_begin_iterate(node->tbm, dsa,
118+
pstate ?
119+
pstate->tbmiterator :
120+
InvalidDsaPointer);
121+
122+
#ifdef USE_PREFETCH
123+
if (node->prefetch_maximum > 0)
124+
node->prefetch_iterator =
125+
tbm_begin_iterate(node->tbm, dsa,
126+
pstate ?
127+
pstate->prefetch_iterator :
128+
InvalidDsaPointer);
129+
#endif /* USE_PREFETCH */
130+
131+
/*
132+
* If this is the first scan of the underlying table, create the table
133+
* scan descriptor and begin the scan.
134+
*/
135+
if (!node->ss.ss_currentScanDesc)
136+
{
137+
bool need_tuples = false;
138+
139+
/*
140+
* We can potentially skip fetching heap pages if we do not need any
141+
* columns of the table, either for checking non-indexable quals or
142+
* for returning data. This test is a bit simplistic, as it checks
143+
* the stronger condition that there's no qual or return tlist at all.
144+
* But in most cases it's probably not worth working harder than that.
145+
*/
146+
need_tuples = (node->ss.ps.plan->qual != NIL ||
147+
node->ss.ps.plan->targetlist != NIL);
148+
149+
node->ss.ss_currentScanDesc =
150+
table_beginscan_bm(node->ss.ss_currentRelation,
151+
node->ss.ps.state->es_snapshot,
152+
0,
153+
NULL,
154+
need_tuples);
155+
}
156+
157+
node->ss.ss_currentScanDesc->st.rs_tbmiterator = tbmiterator;
158+
node->initialized = true;
159+
}
160+
161+
60162
/* ----------------------------------------------------------------
61163
* BitmapHeapNext
62164
*
@@ -68,121 +170,27 @@ BitmapHeapNext(BitmapHeapScanState *node)
68170
{
69171
ExprContext *econtext;
70172
TableScanDesc scan;
71-
TIDBitmap *tbm;
72173
TupleTableSlot *slot;
174+
175+
#ifdef USE_PREFETCH
73176
ParallelBitmapHeapState *pstate = node->pstate;
74-
dsa_area *dsa = node->ss.ps.state->es_query_dsa;
177+
#endif
75178

76179
/*
77180
* extract necessary information from index scan node
78181
*/
79182
econtext = node->ss.ps.ps_ExprContext;
80183
slot = node->ss.ss_ScanTupleSlot;
81184
scan = node->ss.ss_currentScanDesc;
82-
tbm = node->tbm;
83185

84186
/*
85187
* If we haven't yet performed the underlying index scan, do it, and begin
86188
* the iteration over the bitmap.
87-
*
88-
* For prefetching, we use *two* iterators, one for the pages we are
89-
* actually scanning and another that runs ahead of the first for
90-
* prefetching. node->prefetch_pages tracks exactly how many pages ahead
91-
* the prefetch iterator is. Also, node->prefetch_target tracks the
92-
* desired prefetch distance, which starts small and increases up to the
93-
* node->prefetch_maximum. This is to avoid doing a lot of prefetching in
94-
* a scan that stops after a few tuples because of a LIMIT.
95189
*/
96190
if (!node->initialized)
97191
{
98-
TBMIterator tbmiterator;
99-
100-
if (!pstate)
101-
{
102-
tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node));
103-
104-
if (!tbm || !IsA(tbm, TIDBitmap))
105-
elog(ERROR, "unrecognized result from subplan");
106-
107-
node->tbm = tbm;
108-
}
109-
else if (BitmapShouldInitializeSharedState(pstate))
110-
{
111-
/*
112-
* The leader will immediately come out of the function, but
113-
* others will be blocked until leader populates the TBM and wakes
114-
* them up.
115-
*/
116-
tbm = (TIDBitmap *) MultiExecProcNode(outerPlanState(node));
117-
if (!tbm || !IsA(tbm, TIDBitmap))
118-
elog(ERROR, "unrecognized result from subplan");
119-
120-
node->tbm = tbm;
121-
122-
/*
123-
* Prepare to iterate over the TBM. This will return the
124-
* dsa_pointer of the iterator state which will be used by
125-
* multiple processes to iterate jointly.
126-
*/
127-
pstate->tbmiterator = tbm_prepare_shared_iterate(tbm);
128-
129-
#ifdef USE_PREFETCH
130-
if (node->prefetch_maximum > 0)
131-
{
132-
pstate->prefetch_iterator =
133-
tbm_prepare_shared_iterate(tbm);
134-
}
135-
#endif /* USE_PREFETCH */
136-
137-
/* We have initialized the shared state so wake up others. */
138-
BitmapDoneInitializingSharedState(pstate);
139-
}
140-
141-
tbmiterator = tbm_begin_iterate(tbm, dsa,
142-
pstate ?
143-
pstate->tbmiterator :
144-
InvalidDsaPointer);
145-
146-
#ifdef USE_PREFETCH
147-
if (node->prefetch_maximum > 0)
148-
node->prefetch_iterator =
149-
tbm_begin_iterate(tbm, dsa,
150-
pstate ?
151-
pstate->prefetch_iterator :
152-
InvalidDsaPointer);
153-
#endif /* USE_PREFETCH */
154-
155-
/*
156-
* If this is the first scan of the underlying table, create the table
157-
* scan descriptor and begin the scan.
158-
*/
159-
if (!scan)
160-
{
161-
bool need_tuples = false;
162-
163-
/*
164-
* We can potentially skip fetching heap pages if we do not need
165-
* any columns of the table, either for checking non-indexable
166-
* quals or for returning data. This test is a bit simplistic, as
167-
* it checks the stronger condition that there's no qual or return
168-
* tlist at all. But in most cases it's probably not worth working
169-
* harder than that.
170-
*/
171-
need_tuples = (node->ss.ps.plan->qual != NIL ||
172-
node->ss.ps.plan->targetlist != NIL);
173-
174-
scan = table_beginscan_bm(node->ss.ss_currentRelation,
175-
node->ss.ps.state->es_snapshot,
176-
0,
177-
NULL,
178-
need_tuples);
179-
180-
node->ss.ss_currentScanDesc = scan;
181-
}
182-
183-
scan->st.rs_tbmiterator = tbmiterator;
184-
node->initialized = true;
185-
192+
BitmapTableScanSetup(node);
193+
scan = node->ss.ss_currentScanDesc;
186194
goto new_page;
187195
}
188196

0 commit comments

Comments
 (0)