2222#include "miscadmin.h"
2323#include "storage/indexfsm.h"
2424#include "storage/lmgr.h"
25+ #include "storage/read_stream.h"
2526#include "utils/memutils.h"
2627
2728/* Working state needed by gistbulkdelete */
@@ -44,8 +45,7 @@ typedef struct
4445
4546static void gistvacuumscan (IndexVacuumInfo * info , IndexBulkDeleteResult * stats ,
4647 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 );
4949static void gistvacuum_delete_empty_pages (IndexVacuumInfo * info ,
5050 GistVacState * vstate );
5151static bool gistdeletepage (IndexVacuumInfo * info , IndexBulkDeleteResult * stats ,
@@ -129,8 +129,9 @@ gistvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
129129 GistVacState vstate ;
130130 BlockNumber num_pages ;
131131 bool needLock ;
132- BlockNumber blkno ;
133132 MemoryContext oldctx ;
133+ BlockRangeReadStreamPrivate p ;
134+ ReadStream * stream = NULL ;
134135
135136 /*
136137 * Reset fields that track information about the entire index now. This
@@ -208,7 +209,14 @@ gistvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
208209 */
209210 needLock = !RELATION_IS_LOCAL (rel );
210211
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 );
212220 for (;;)
213221 {
214222 /* Get the current relation length */
@@ -219,13 +227,39 @@ gistvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
219227 UnlockRelationForExtension (rel , ExclusiveLock );
220228
221229 /* Quit if we've scanned the whole relation */
222- if (blkno >= num_pages )
230+ if (p . current_blocknum >= num_pages )
223231 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 );
227259 }
228260
261+ read_stream_end (stream );
262+
229263 /*
230264 * If we found any recyclable pages (and recorded them in the FSM), then
231265 * forcibly update the upper-level FSM pages to ensure that searchers can
@@ -260,34 +294,32 @@ gistvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
260294/*
261295 * gistvacuumpage --- VACUUM one page
262296 *
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.
270301 */
271302static void
272- gistvacuumpage (GistVacState * vstate , BlockNumber blkno , BlockNumber orig_blkno )
303+ gistvacuumpage (GistVacState * vstate , Buffer buffer )
273304{
274305 IndexVacuumInfo * info = vstate -> info ;
275306 IndexBulkDeleteCallback callback = vstate -> callback ;
276307 void * callback_state = vstate -> callback_state ;
277308 Relation rel = info -> index ;
278- Buffer buffer ;
309+ BlockNumber orig_blkno = BufferGetBlockNumber ( buffer ) ;
279310 Page page ;
280311 BlockNumber recurse_to ;
281312
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+
282320restart :
283321 recurse_to = InvalidBlockNumber ;
284322
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-
291323 /*
292324 * We are not going to stay here for a long time, aggressively grab an
293325 * exclusive lock.
@@ -450,6 +482,12 @@ gistvacuumpage(GistVacState *vstate, BlockNumber blkno, BlockNumber orig_blkno)
450482 if (recurse_to != InvalidBlockNumber )
451483 {
452484 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 );
453491 goto restart ;
454492 }
455493}
0 commit comments