Skip to content

Commit 69273b8

Browse files
Use streaming read I/O in GiST vacuuming
Like c5c239e did for btree vacuuming, make GiST vacuum use the read stream API for sequentially processed pages. Because it is possible for concurrent insertions to relocate unprocessed index entries to already vacuumed pages, GiST vacuum must backtrack and reprocess those pages. These pages are still read with explicit ReadBuffer() calls. Author: Andrey M. Borodin <[email protected]> Reviewed-by: Melanie Plageman <[email protected]> Discussion: https://postgr.es/m/EFEBED92-18D1-4C0F-A4EB-CD47072EF071%40yandex-team.ru
1 parent 3f850c3 commit 69273b8

File tree

1 file changed

+61
-23
lines changed

1 file changed

+61
-23
lines changed

src/backend/access/gist/gistvacuum.c

+61-23
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
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

4546
static 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);
4949
static void gistvacuum_delete_empty_pages(IndexVacuumInfo *info,
5050
GistVacState *vstate);
5151
static 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
*/
271302
static 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+
282320
restart:
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

Comments
 (0)