diff --git a/src/backend/access/gin/ginvacuum.c b/src/backend/access/gin/ginvacuum.c index c9f143f6c31..d5c8bef5ceb 100644 --- a/src/backend/access/gin/ginvacuum.c +++ b/src/backend/access/gin/ginvacuum.c @@ -22,6 +22,7 @@ #include "storage/indexfsm.h" #include "storage/lmgr.h" #include "storage/predicate.h" +#include "storage/read_stream.h" #include "utils/memutils.h" struct GinVacuumState @@ -693,6 +694,8 @@ ginvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) BlockNumber totFreePages; GinState ginstate; GinStatsData idxStat; + BlockRangeReadStreamPrivate p; + ReadStream *stream; /* * In an autovacuum analyze, we want to clean up pending insertions. @@ -743,6 +746,24 @@ ginvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) totFreePages = 0; + /* Scan all blocks starting from the root using streaming reads */ + p.current_blocknum = GIN_ROOT_BLKNO; + p.last_exclusive = npages; + + /* + * It is safe to use batchmode as block_range_read_stream_cb takes no + * locks. + */ + stream = read_stream_begin_relation(READ_STREAM_MAINTENANCE | + READ_STREAM_FULL | + READ_STREAM_USE_BATCHING, + info->strategy, + index, + MAIN_FORKNUM, + block_range_read_stream_cb, + &p, + 0); + for (blkno = GIN_ROOT_BLKNO; blkno < npages; blkno++) { Buffer buffer; @@ -750,8 +771,8 @@ ginvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) vacuum_delay_point(false); - buffer = ReadBufferExtended(index, MAIN_FORKNUM, blkno, - RBM_NORMAL, info->strategy); + buffer = read_stream_next_buffer(stream, NULL); + LockBuffer(buffer, GIN_SHARE); page = BufferGetPage(buffer); @@ -776,6 +797,9 @@ ginvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats) UnlockReleaseBuffer(buffer); } + Assert(read_stream_next_buffer(stream, NULL) == InvalidBuffer); + read_stream_end(stream); + /* Update the metapage with accurate page and entry counts */ idxStat.nTotalPages = npages; ginUpdateStats(info->index, &idxStat, false);