@@ -86,7 +86,7 @@ typedef struct BTParallelScanDescData *BTParallelScanDesc;
86
86
static void btvacuumscan (IndexVacuumInfo * info , IndexBulkDeleteResult * stats ,
87
87
IndexBulkDeleteCallback callback , void * callback_state ,
88
88
BTCycleId cycleid );
89
- static void btvacuumpage (BTVacState * vstate , BlockNumber scanblkno );
89
+ static BlockNumber btvacuumpage (BTVacState * vstate , Buffer buf );
90
90
static BTVacuumPosting btreevacuumposting (BTVacState * vstate ,
91
91
IndexTuple posting ,
92
92
OffsetNumber updatedoffset ,
@@ -991,8 +991,9 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
991
991
Relation rel = info -> index ;
992
992
BTVacState vstate ;
993
993
BlockNumber num_pages ;
994
- BlockNumber scanblkno ;
995
994
bool needLock ;
995
+ BlockRangeReadStreamPrivate p ;
996
+ ReadStream * stream = NULL ;
996
997
997
998
/*
998
999
* Reset fields that track information about the entire index now. This
@@ -1061,9 +1062,18 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
1061
1062
*/
1062
1063
needLock = !RELATION_IS_LOCAL (rel );
1063
1064
1064
- scanblkno = BTREE_METAPAGE + 1 ;
1065
+ p .current_blocknum = BTREE_METAPAGE + 1 ;
1066
+ stream = read_stream_begin_relation (READ_STREAM_FULL ,
1067
+ info -> strategy ,
1068
+ rel ,
1069
+ MAIN_FORKNUM ,
1070
+ block_range_read_stream_cb ,
1071
+ & p ,
1072
+ 0 );
1065
1073
for (;;)
1066
1074
{
1075
+ Buffer buf ;
1076
+
1067
1077
/* Get the current relation length */
1068
1078
if (needLock )
1069
1079
LockRelationForExtension (rel , ExclusiveLock );
@@ -1076,18 +1086,44 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
1076
1086
num_pages );
1077
1087
1078
1088
/* Quit if we've scanned the whole relation */
1079
- if (scanblkno >= num_pages )
1089
+ if (p . current_blocknum >= num_pages )
1080
1090
break ;
1081
- /* Iterate over pages, then loop back to recheck length */
1082
- for (; scanblkno < num_pages ; scanblkno ++ )
1091
+
1092
+
1093
+ p .last_exclusive = num_pages ;
1094
+
1095
+ /* Iterate over pages, then loop back to recheck relation length */
1096
+ while (true)
1083
1097
{
1084
- btvacuumpage (& vstate , scanblkno );
1098
+ BlockNumber current_block ;
1099
+
1100
+ /* call vacuum_delay_point while not holding any buffer lock */
1101
+ vacuum_delay_point (false);
1102
+
1103
+ buf = read_stream_next_buffer (stream , NULL );
1104
+
1105
+ if (!BufferIsValid (buf ))
1106
+ break ;
1107
+
1108
+ current_block = btvacuumpage (& vstate , buf );
1109
+
1085
1110
if (info -> report_progress )
1086
1111
pgstat_progress_update_param (PROGRESS_SCAN_BLOCKS_DONE ,
1087
- scanblkno );
1112
+ current_block );
1088
1113
}
1114
+
1115
+ Assert (read_stream_next_buffer (stream , NULL ) == InvalidBuffer );
1116
+
1117
+ /*
1118
+ * We have to reset the read stream to use it again. After returning
1119
+ * InvalidBuffer, the read stream API won't invoke our callback again
1120
+ * until the stream has been reset.
1121
+ */
1122
+ read_stream_reset (stream );
1089
1123
}
1090
1124
1125
+ read_stream_end (stream );
1126
+
1091
1127
/* Set statistics num_pages field to final size of index */
1092
1128
stats -> num_pages = num_pages ;
1093
1129
@@ -1111,14 +1147,16 @@ btvacuumscan(IndexVacuumInfo *info, IndexBulkDeleteResult *stats,
1111
1147
* btvacuumpage --- VACUUM one page
1112
1148
*
1113
1149
* This processes a single page for btvacuumscan(). In some cases we must
1114
- * backtrack to re-examine and VACUUM pages that were the scanblkno during
1150
+ * backtrack to re-examine and VACUUM pages that were on buf's page during
1115
1151
* a previous call here. This is how we handle page splits (that happened
1116
1152
* after our cycleid was acquired) whose right half page happened to reuse
1117
1153
* a block that we might have processed at some point before it was
1118
1154
* recycled (i.e. before the page split).
1155
+ *
1156
+ * Returns BlockNumber of a scanned page (not backtracked).
1119
1157
*/
1120
- static void
1121
- btvacuumpage (BTVacState * vstate , BlockNumber scanblkno )
1158
+ static BlockNumber
1159
+ btvacuumpage (BTVacState * vstate , Buffer buf )
1122
1160
{
1123
1161
IndexVacuumInfo * info = vstate -> info ;
1124
1162
IndexBulkDeleteResult * stats = vstate -> stats ;
@@ -1129,7 +1167,7 @@ btvacuumpage(BTVacState *vstate, BlockNumber scanblkno)
1129
1167
bool attempt_pagedel ;
1130
1168
BlockNumber blkno ,
1131
1169
backtrack_to ;
1132
- Buffer buf ;
1170
+ BlockNumber scanblkno = BufferGetBlockNumber ( buf ) ;
1133
1171
Page page ;
1134
1172
BTPageOpaque opaque ;
1135
1173
@@ -1140,17 +1178,6 @@ btvacuumpage(BTVacState *vstate, BlockNumber scanblkno)
1140
1178
attempt_pagedel = false;
1141
1179
backtrack_to = P_NONE ;
1142
1180
1143
- /* call vacuum_delay_point while not holding any buffer lock */
1144
- vacuum_delay_point (false);
1145
-
1146
- /*
1147
- * We can't use _bt_getbuf() here because it always applies
1148
- * _bt_checkpage(), which will barf on an all-zero page. We want to
1149
- * recycle all-zero pages, not fail. Also, we want to use a nondefault
1150
- * buffer access strategy.
1151
- */
1152
- buf = ReadBufferExtended (rel , MAIN_FORKNUM , blkno , RBM_NORMAL ,
1153
- info -> strategy );
1154
1181
_bt_lockbuf (rel , buf , BT_READ );
1155
1182
page = BufferGetPage (buf );
1156
1183
opaque = NULL ;
@@ -1186,7 +1213,7 @@ btvacuumpage(BTVacState *vstate, BlockNumber scanblkno)
1186
1213
errmsg_internal ("right sibling %u of scanblkno %u unexpectedly in an inconsistent state in index \"%s\"" ,
1187
1214
blkno , scanblkno , RelationGetRelationName (rel ))));
1188
1215
_bt_relbuf (rel , buf );
1189
- return ;
1216
+ return scanblkno ;
1190
1217
}
1191
1218
1192
1219
/*
@@ -1206,7 +1233,7 @@ btvacuumpage(BTVacState *vstate, BlockNumber scanblkno)
1206
1233
{
1207
1234
/* Done with current scanblkno (and all lower split pages) */
1208
1235
_bt_relbuf (rel , buf );
1209
- return ;
1236
+ return scanblkno ;
1210
1237
}
1211
1238
}
1212
1239
@@ -1437,8 +1464,22 @@ btvacuumpage(BTVacState *vstate, BlockNumber scanblkno)
1437
1464
if (backtrack_to != P_NONE )
1438
1465
{
1439
1466
blkno = backtrack_to ;
1467
+
1468
+ /* check for vacuum delay while not holding any buffer lock */
1469
+ vacuum_delay_point (false);
1470
+
1471
+ /*
1472
+ * We can't use _bt_getbuf() here because it always applies
1473
+ * _bt_checkpage(), which will barf on an all-zero page. We want to
1474
+ * recycle all-zero pages, not fail. Also, we want to use a
1475
+ * nondefault buffer access strategy.
1476
+ */
1477
+ buf = ReadBufferExtended (rel , MAIN_FORKNUM , blkno , RBM_NORMAL ,
1478
+ info -> strategy );
1440
1479
goto backtrack ;
1441
1480
}
1481
+
1482
+ return scanblkno ;
1442
1483
}
1443
1484
1444
1485
/*
0 commit comments