21
21
*
22
22
*
23
23
* IDENTIFICATION
24
- * $PostgreSQL: pgsql/src/backend/executor/nodeBitmapHeapscan.c,v 1.32 2009/01/10 21:08:36 tgl Exp $
24
+ * $PostgreSQL: pgsql/src/backend/executor/nodeBitmapHeapscan.c,v 1.33 2009/01/12 05:10:44 tgl Exp $
25
25
*
26
26
*-------------------------------------------------------------------------
27
27
*/
@@ -67,6 +67,7 @@ BitmapHeapNext(BitmapHeapScanState *node)
67
67
TIDBitmap * tbm ;
68
68
TBMIterator * tbmiterator ;
69
69
TBMIterateResult * tbmres ;
70
+ TBMIterator * prefetch_iterator ;
70
71
OffsetNumber targoffset ;
71
72
TupleTableSlot * slot ;
72
73
@@ -81,6 +82,7 @@ BitmapHeapNext(BitmapHeapScanState *node)
81
82
tbm = node -> tbm ;
82
83
tbmiterator = node -> tbmiterator ;
83
84
tbmres = node -> tbmres ;
85
+ prefetch_iterator = node -> prefetch_iterator ;
84
86
85
87
/*
86
88
* Check if we are evaluating PlanQual for tuple of this relation.
@@ -114,6 +116,15 @@ BitmapHeapNext(BitmapHeapScanState *node)
114
116
/*
115
117
* If we haven't yet performed the underlying index scan, do it, and
116
118
* begin the iteration over the bitmap.
119
+ *
120
+ * For prefetching, we use *two* iterators, one for the pages we are
121
+ * actually scanning and another that runs ahead of the first for
122
+ * prefetching. node->prefetch_pages tracks exactly how many pages
123
+ * ahead the prefetch iterator is. Also, node->prefetch_target tracks
124
+ * the desired prefetch distance, which starts small and increases up
125
+ * to the GUC-controlled maximum, target_prefetch_pages. This is to
126
+ * avoid doing a lot of prefetching in a scan that stops after a few
127
+ * tuples because of a LIMIT.
117
128
*/
118
129
if (tbm == NULL )
119
130
{
@@ -125,6 +136,15 @@ BitmapHeapNext(BitmapHeapScanState *node)
125
136
node -> tbm = tbm ;
126
137
node -> tbmiterator = tbmiterator = tbm_begin_iterate (tbm );
127
138
node -> tbmres = tbmres = NULL ;
139
+
140
+ #ifdef USE_PREFETCH
141
+ if (target_prefetch_pages > 0 )
142
+ {
143
+ node -> prefetch_iterator = prefetch_iterator = tbm_begin_iterate (tbm );
144
+ node -> prefetch_pages = 0 ;
145
+ node -> prefetch_target = -1 ;
146
+ }
147
+ #endif /* USE_PREFETCH */
128
148
}
129
149
130
150
for (;;)
@@ -144,6 +164,22 @@ BitmapHeapNext(BitmapHeapScanState *node)
144
164
break ;
145
165
}
146
166
167
+ #ifdef USE_PREFETCH
168
+ if (node -> prefetch_pages > 0 )
169
+ {
170
+ /* The main iterator has closed the distance by one page */
171
+ node -> prefetch_pages -- ;
172
+ }
173
+ else if (prefetch_iterator )
174
+ {
175
+ /* Do not let the prefetch iterator get behind the main one */
176
+ TBMIterateResult * tbmpre = tbm_iterate (prefetch_iterator );
177
+
178
+ if (tbmpre == NULL || tbmpre -> blockno != tbmres -> blockno )
179
+ elog (ERROR , "prefetch and main iterators are out of sync" );
180
+ }
181
+ #endif /* USE_PREFETCH */
182
+
147
183
/*
148
184
* Ignore any claimed entries past what we think is the end of the
149
185
* relation. (This is probably not necessary given that we got at
@@ -165,14 +201,64 @@ BitmapHeapNext(BitmapHeapScanState *node)
165
201
* Set rs_cindex to first slot to examine
166
202
*/
167
203
scan -> rs_cindex = 0 ;
204
+
205
+ #ifdef USE_PREFETCH
206
+ /*
207
+ * Increase prefetch target if it's not yet at the max. Note
208
+ * that we will increase it to zero after fetching the very
209
+ * first page/tuple, then to one after the second tuple is
210
+ * fetched, then it doubles as later pages are fetched.
211
+ */
212
+ if (node -> prefetch_target >= target_prefetch_pages )
213
+ /* don't increase any further */ ;
214
+ else if (node -> prefetch_target >= target_prefetch_pages / 2 )
215
+ node -> prefetch_target = target_prefetch_pages ;
216
+ else if (node -> prefetch_target > 0 )
217
+ node -> prefetch_target *= 2 ;
218
+ else
219
+ node -> prefetch_target ++ ;
220
+ #endif /* USE_PREFETCH */
168
221
}
169
222
else
170
223
{
171
224
/*
172
225
* Continuing in previously obtained page; advance rs_cindex
173
226
*/
174
227
scan -> rs_cindex ++ ;
228
+
229
+ #ifdef USE_PREFETCH
230
+ /*
231
+ * Try to prefetch at least a few pages even before we get to the
232
+ * second page if we don't stop reading after the first tuple.
233
+ */
234
+ if (node -> prefetch_target < target_prefetch_pages )
235
+ node -> prefetch_target ++ ;
236
+ #endif /* USE_PREFETCH */
237
+ }
238
+
239
+ #ifdef USE_PREFETCH
240
+ /*
241
+ * We issue prefetch requests *after* fetching the current page
242
+ * to try to avoid having prefetching interfere with the main I/O.
243
+ */
244
+ if (prefetch_iterator )
245
+ {
246
+ while (node -> prefetch_pages < node -> prefetch_target )
247
+ {
248
+ TBMIterateResult * tbmpre = tbm_iterate (prefetch_iterator );
249
+
250
+ if (tbmpre == NULL )
251
+ {
252
+ /* No more pages to prefetch */
253
+ tbm_end_iterate (prefetch_iterator );
254
+ node -> prefetch_iterator = prefetch_iterator = NULL ;
255
+ break ;
256
+ }
257
+ node -> prefetch_pages ++ ;
258
+ PrefetchBuffer (scan -> rs_rd , MAIN_FORKNUM , tbmpre -> blockno );
259
+ }
175
260
}
261
+ #endif /* USE_PREFETCH */
176
262
177
263
/*
178
264
* Out of range? If so, nothing more to look at on this page
@@ -379,11 +465,14 @@ ExecBitmapHeapReScan(BitmapHeapScanState *node, ExprContext *exprCtxt)
379
465
380
466
if (node -> tbmiterator )
381
467
tbm_end_iterate (node -> tbmiterator );
468
+ if (node -> prefetch_iterator )
469
+ tbm_end_iterate (node -> prefetch_iterator );
382
470
if (node -> tbm )
383
471
tbm_free (node -> tbm );
384
472
node -> tbm = NULL ;
385
473
node -> tbmiterator = NULL ;
386
474
node -> tbmres = NULL ;
475
+ node -> prefetch_iterator = NULL ;
387
476
388
477
/*
389
478
* Always rescan the input immediately, to ensure we can pass down any
@@ -429,6 +518,8 @@ ExecEndBitmapHeapScan(BitmapHeapScanState *node)
429
518
*/
430
519
if (node -> tbmiterator )
431
520
tbm_end_iterate (node -> tbmiterator );
521
+ if (node -> prefetch_iterator )
522
+ tbm_end_iterate (node -> prefetch_iterator );
432
523
if (node -> tbm )
433
524
tbm_free (node -> tbm );
434
525
@@ -474,6 +565,9 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags)
474
565
scanstate -> tbm = NULL ;
475
566
scanstate -> tbmiterator = NULL ;
476
567
scanstate -> tbmres = NULL ;
568
+ scanstate -> prefetch_iterator = NULL ;
569
+ scanstate -> prefetch_pages = 0 ;
570
+ scanstate -> prefetch_target = 0 ;
477
571
478
572
/*
479
573
* Miscellaneous initialization
0 commit comments