aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/access/nbtree/nbtree.c91
1 files changed, 66 insertions, 25 deletions
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index c0a8833e068..353600414a2 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -86,7 +86,7 @@ typedef struct BTParallelScanDescData *BTParallelScanDesc;
static void btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
IndexBulkDeleteCallback callback, void *callback_state,
BTCycleId cycleid);
-static void btvacuumpage(BTVacState *vstate, BlockNumber scanblkno);
+static BlockNumber btvacuumpage(BTVacState *vstate, Buffer buf);
static BTVacuumPosting btreevacuumposting(BTVacState *vstate,
IndexTuple posting,
OffsetNumber updatedoffset,
@@ -991,8 +991,9 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
Relation rel = info->index;
BTVacState vstate;
BlockNumber num_pages;
- BlockNumber scanblkno;
bool needLock;
+ BlockRangeReadStreamPrivate p;
+ ReadStream *stream = NULL;
/*
* Reset fields that track information about the entire index now. This
@@ -1061,9 +1062,18 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
*/
needLock = !RELATION_IS_LOCAL(rel);
- scanblkno = BTREE_METAPAGE + 1;
+ p.current_blocknum = BTREE_METAPAGE + 1;
+ stream = read_stream_begin_relation(READ_STREAM_FULL,
+ info->strategy,
+ rel,
+ MAIN_FORKNUM,
+ block_range_read_stream_cb,
+ &p,
+ 0);
for (;;)
{
+ Buffer buf;
+
/* Get the current relation length */
if (needLock)
LockRelationForExtension(rel, ExclusiveLock);
@@ -1076,18 +1086,44 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
num_pages);
/* Quit if we've scanned the whole relation */
- if (scanblkno >= num_pages)
+ if (p.current_blocknum >= num_pages)
break;
- /* Iterate over pages, then loop back to recheck length */
- for (; scanblkno < num_pages; scanblkno++)
+
+
+ p.last_exclusive = num_pages;
+
+ /* Iterate over pages, then loop back to recheck relation length */
+ while (true)
{
- btvacuumpage(&vstate, scanblkno);
+ BlockNumber current_block;
+
+ /* call vacuum_delay_point while not holding any buffer lock */
+ vacuum_delay_point(false);
+
+ buf = read_stream_next_buffer(stream, NULL);
+
+ if (!BufferIsValid(buf))
+ break;
+
+ current_block = btvacuumpage(&vstate, buf);
+
if (info->report_progress)
pgstat_progress_update_param(PROGRESS_SCAN_BLOCKS_DONE,
- scanblkno);
+ current_block);
}
+
+ Assert(read_stream_next_buffer(stream, NULL) == InvalidBuffer);
+
+ /*
+ * We have to reset the read stream to use it again. After returning
+ * InvalidBuffer, the read stream API won't invoke our callback again
+ * until the stream has been reset.
+ */
+ read_stream_reset(stream);
}
+ read_stream_end(stream);
+
/* Set statistics num_pages field to final size of index */
stats->num_pages = num_pages;
@@ -1111,14 +1147,16 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
* btvacuumpage --- VACUUM one page
*
* This processes a single page for btvacuumscan(). In some cases we must
- * backtrack to re-examine and VACUUM pages that were the scanblkno during
+ * backtrack to re-examine and VACUUM pages that were on buf's page during
* a previous call here. This is how we handle page splits (that happened
* after our cycleid was acquired) whose right half page happened to reuse
* a block that we might have processed at some point before it was
* recycled (i.e. before the page split).
+ *
+ * Returns BlockNumber of a scanned page (not backtracked).
*/
-static void
-btvacuumpage(BTVacState *vstate, BlockNumber scanblkno)
+static BlockNumber
+btvacuumpage(BTVacState *vstate, Buffer buf)
{
IndexVacuumInfo *info = vstate->info;
IndexBulkDeleteResult *stats = vstate->stats;
@@ -1129,7 +1167,7 @@ btvacuumpage(BTVacState *vstate, BlockNumber scanblkno)
bool attempt_pagedel;
BlockNumber blkno,
backtrack_to;
- Buffer buf;
+ BlockNumber scanblkno = BufferGetBlockNumber(buf);
Page page;
BTPageOpaque opaque;
@@ -1140,17 +1178,6 @@ backtrack:
attempt_pagedel = false;
backtrack_to = P_NONE;
- /* call vacuum_delay_point while not holding any buffer lock */
- vacuum_delay_point(false);
-
- /*
- * We can't use _bt_getbuf() here because it always applies
- * _bt_checkpage(), which will barf on an all-zero page. We want to
- * recycle all-zero pages, not fail. Also, we want to use a nondefault
- * buffer access strategy.
- */
- buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
- info->strategy);
_bt_lockbuf(rel, buf, BT_READ);
page = BufferGetPage(buf);
opaque = NULL;
@@ -1186,7 +1213,7 @@ backtrack:
errmsg_internal("right sibling %u of scanblkno %u unexpectedly in an inconsistent state in index \"%s\"",
blkno, scanblkno, RelationGetRelationName(rel))));
_bt_relbuf(rel, buf);
- return;
+ return scanblkno;
}
/*
@@ -1206,7 +1233,7 @@ backtrack:
{
/* Done with current scanblkno (and all lower split pages) */
_bt_relbuf(rel, buf);
- return;
+ return scanblkno;
}
}
@@ -1437,8 +1464,22 @@ backtrack:
if (backtrack_to != P_NONE)
{
blkno = backtrack_to;
+
+ /* check for vacuum delay while not holding any buffer lock */
+ vacuum_delay_point(false);
+
+ /*
+ * We can't use _bt_getbuf() here because it always applies
+ * _bt_checkpage(), which will barf on an all-zero page. We want to
+ * recycle all-zero pages, not fail. Also, we want to use a
+ * nondefault buffer access strategy.
+ */
+ buf = ReadBufferExtended(rel, MAIN_FORKNUM, blkno, RBM_NORMAL,
+ info->strategy);
goto backtrack;
}
+
+ return scanblkno;
}
/*