22
22
#include "miscadmin.h"
23
23
#include "storage/indexfsm.h"
24
24
#include "storage/lmgr.h"
25
+ #include "storage/read_stream.h"
25
26
#include "utils/memutils.h"
26
27
27
28
/* Working state needed by gistbulkdelete */
@@ -44,8 +45,7 @@ typedef struct
44
45
45
46
static void gistvacuumscan (IndexVacuumInfo * info , IndexBulkDeleteResult * stats ,
46
47
IndexBulkDeleteCallback callback , void * callback_state );
47
- static void gistvacuumpage (GistVacState * vstate , BlockNumber blkno ,
48
- BlockNumber orig_blkno );
48
+ static void gistvacuumpage (GistVacState * vstate , Buffer buffer );
49
49
static void gistvacuum_delete_empty_pages (IndexVacuumInfo * info ,
50
50
GistVacState * vstate );
51
51
static bool gistdeletepage (IndexVacuumInfo * info , IndexBulkDeleteResult * stats ,
@@ -129,8 +129,9 @@ gistvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
129
129
GistVacState vstate ;
130
130
BlockNumber num_pages ;
131
131
bool needLock ;
132
- BlockNumber blkno ;
133
132
MemoryContext oldctx ;
133
+ BlockRangeReadStreamPrivate p ;
134
+ ReadStream * stream = NULL ;
134
135
135
136
/*
136
137
* Reset fields that track information about the entire index now. This
@@ -208,7 +209,14 @@ gistvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
208
209
*/
209
210
needLock = !RELATION_IS_LOCAL (rel );
210
211
211
- blkno = GIST_ROOT_BLKNO ;
212
+ p .current_blocknum = GIST_ROOT_BLKNO ;
213
+ stream = read_stream_begin_relation (READ_STREAM_FULL ,
214
+ info -> strategy ,
215
+ rel ,
216
+ MAIN_FORKNUM ,
217
+ block_range_read_stream_cb ,
218
+ & p ,
219
+ 0 );
212
220
for (;;)
213
221
{
214
222
/* Get the current relation length */
@@ -219,13 +227,39 @@ gistvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
219
227
UnlockRelationForExtension (rel , ExclusiveLock );
220
228
221
229
/* Quit if we've scanned the whole relation */
222
- if (blkno >= num_pages )
230
+ if (p . current_blocknum >= num_pages )
223
231
break ;
224
- /* Iterate over pages, then loop back to recheck length */
225
- for (; blkno < num_pages ; blkno ++ )
226
- gistvacuumpage (& vstate , blkno , blkno );
232
+
233
+ p .last_exclusive = num_pages ;
234
+
235
+ /* Iterate over pages, then loop back to recheck relation length */
236
+ while (true)
237
+ {
238
+ Buffer buf ;
239
+
240
+ /* call vacuum_delay_point while not holding any buffer lock */
241
+ vacuum_delay_point (false);
242
+
243
+ buf = read_stream_next_buffer (stream , NULL );
244
+
245
+ if (!BufferIsValid (buf ))
246
+ break ;
247
+
248
+ gistvacuumpage (& vstate , buf );
249
+ }
250
+
251
+ Assert (read_stream_next_buffer (stream , NULL ) == InvalidBuffer );
252
+
253
+ /*
254
+ * We have to reset the read stream to use it again. After returning
255
+ * InvalidBuffer, the read stream API won't invoke our callback again
256
+ * until the stream has been reset.
257
+ */
258
+ read_stream_reset (stream );
227
259
}
228
260
261
+ read_stream_end (stream );
262
+
229
263
/*
230
264
* If we found any recyclable pages (and recorded them in the FSM), then
231
265
* forcibly update the upper-level FSM pages to ensure that searchers can
@@ -260,34 +294,32 @@ gistvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
260
294
/*
261
295
* gistvacuumpage --- VACUUM one page
262
296
*
263
- * This processes a single page for gistbulkdelete(). In some cases we
264
- * must go back and re-examine previously-scanned pages; this routine
265
- * recurses when necessary to handle that case.
266
- *
267
- * blkno is the page to process. orig_blkno is the highest block number
268
- * reached by the outer gistvacuumscan loop (the same as blkno, unless we
269
- * are recursing to re-examine a previous page).
297
+ * This processes a single page for gistbulkdelete(). `buffer` contains the
298
+ * page to process. In some cases we must go back and reexamine
299
+ * previously-scanned pages; this routine recurses when necessary to handle
300
+ * that case.
270
301
*/
271
302
static void
272
- gistvacuumpage (GistVacState * vstate , BlockNumber blkno , BlockNumber orig_blkno )
303
+ gistvacuumpage (GistVacState * vstate , Buffer buffer )
273
304
{
274
305
IndexVacuumInfo * info = vstate -> info ;
275
306
IndexBulkDeleteCallback callback = vstate -> callback ;
276
307
void * callback_state = vstate -> callback_state ;
277
308
Relation rel = info -> index ;
278
- Buffer buffer ;
309
+ BlockNumber orig_blkno = BufferGetBlockNumber ( buffer ) ;
279
310
Page page ;
280
311
BlockNumber recurse_to ;
281
312
313
+ /*
314
+ * orig_blkno is the highest block number reached by the outer
315
+ * gistvacuumscan() loop. This will be the same as blkno unless we are
316
+ * recursing to reexamine a previous page.
317
+ */
318
+ BlockNumber blkno = orig_blkno ;
319
+
282
320
restart :
283
321
recurse_to = InvalidBlockNumber ;
284
322
285
- /* call vacuum_delay_point while not holding any buffer lock */
286
- vacuum_delay_point (false);
287
-
288
- buffer = ReadBufferExtended (rel , MAIN_FORKNUM , blkno , RBM_NORMAL ,
289
- info -> strategy );
290
-
291
323
/*
292
324
* We are not going to stay here for a long time, aggressively grab an
293
325
* exclusive lock.
@@ -450,6 +482,12 @@ gistvacuumpage(GistVacState *vstate, BlockNumber blkno, BlockNumber orig_blkno)
450
482
if (recurse_to != InvalidBlockNumber )
451
483
{
452
484
blkno = recurse_to ;
485
+
486
+ /* check for vacuum delay while not holding any buffer lock */
487
+ vacuum_delay_point (false);
488
+
489
+ buffer = ReadBufferExtended (rel , MAIN_FORKNUM , blkno , RBM_NORMAL ,
490
+ info -> strategy );
453
491
goto restart ;
454
492
}
455
493
}
0 commit comments