@@ -67,7 +67,7 @@ static BrinBuildState *initialize_brin_buildstate(Relation idxRel,
67
67
BrinRevmap * revmap , BlockNumber pagesPerRange );
68
68
static void terminate_brin_buildstate (BrinBuildState * state );
69
69
static void brinsummarize (Relation index , Relation heapRel , BlockNumber pageRange ,
70
- double * numSummarized , double * numExisting );
70
+ bool include_partial , double * numSummarized , double * numExisting );
71
71
static void form_and_insert_tuple (BrinBuildState * state );
72
72
static void union_tuples (BrinDesc * bdesc , BrinMemTuple * a ,
73
73
BrinTuple * b );
@@ -791,7 +791,7 @@ brinvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
791
791
792
792
brin_vacuum_scan (info -> index , info -> strategy );
793
793
794
- brinsummarize (info -> index , heapRel , BRIN_ALL_BLOCKRANGES ,
794
+ brinsummarize (info -> index , heapRel , BRIN_ALL_BLOCKRANGES , false,
795
795
& stats -> num_index_tuples , & stats -> num_index_tuples );
796
796
797
797
heap_close (heapRel , AccessShareLock );
@@ -909,7 +909,7 @@ brin_summarize_range(PG_FUNCTION_ARGS)
909
909
RelationGetRelationName (indexRel ))));
910
910
911
911
/* OK, do it */
912
- brinsummarize (indexRel , heapRel , heapBlk , & numSummarized , NULL );
912
+ brinsummarize (indexRel , heapRel , heapBlk , true, & numSummarized , NULL );
913
913
914
914
relation_close (indexRel , ShareUpdateExclusiveLock );
915
915
relation_close (heapRel , ShareUpdateExclusiveLock );
@@ -1129,7 +1129,8 @@ terminate_brin_buildstate(BrinBuildState *state)
1129
1129
}
1130
1130
1131
1131
/*
1132
- * Summarize the given page range of the given index.
1132
+ * On the given BRIN index, summarize the heap page range that corresponds
1133
+ * to the heap block number given.
1133
1134
*
1134
1135
* This routine can run in parallel with insertions into the heap. To avoid
1135
1136
* missing those values from the summary tuple, we first insert a placeholder
@@ -1139,6 +1140,12 @@ terminate_brin_buildstate(BrinBuildState *state)
1139
1140
* update of the index value happens in a loop, so that if somebody updates
1140
1141
* the placeholder tuple after we read it, we detect the case and try again.
1141
1142
* This ensures that the concurrently inserted tuples are not lost.
1143
+ *
1144
+ * A further corner case is this routine being asked to summarize the partial
1145
+ * range at the end of the table. heapNumBlocks is the (possibly outdated)
1146
+ * table size; if we notice that the requested range lies beyond that size,
1147
+ * we re-compute the table size after inserting the placeholder tuple, to
1148
+ * avoid missing pages that were appended recently.
1142
1149
*/
1143
1150
static void
1144
1151
summarize_range (IndexInfo * indexInfo , BrinBuildState * state , Relation heapRel ,
@@ -1159,6 +1166,33 @@ summarize_range(IndexInfo *indexInfo, BrinBuildState *state, Relation heapRel,
1159
1166
state -> bs_rmAccess , & phbuf ,
1160
1167
heapBlk , phtup , phsz );
1161
1168
1169
+ /*
1170
+ * Compute range end. We hold ShareUpdateExclusive lock on table, so it
1171
+ * cannot shrink concurrently (but it can grow).
1172
+ */
1173
+ Assert (heapBlk % state -> bs_pagesPerRange == 0 );
1174
+ if (heapBlk + state -> bs_pagesPerRange > heapNumBlks )
1175
+ {
1176
+ /*
1177
+ * If we're asked to scan what we believe to be the final range on the
1178
+ * table (i.e. a range that might be partial) we need to recompute our
1179
+ * idea of what the latest page is after inserting the placeholder
1180
+ * tuple. Anyone that grows the table later will update the
1181
+ * placeholder tuple, so it doesn't matter that we won't scan these
1182
+ * pages ourselves. Careful: the table might have been extended
1183
+ * beyond the current range, so clamp our result.
1184
+ *
1185
+ * Fortunately, this should occur infrequently.
1186
+ */
1187
+ scanNumBlks = Min (RelationGetNumberOfBlocks (heapRel ) - heapBlk ,
1188
+ state -> bs_pagesPerRange );
1189
+ }
1190
+ else
1191
+ {
1192
+ /* Easy case: range is known to be complete */
1193
+ scanNumBlks = state -> bs_pagesPerRange ;
1194
+ }
1195
+
1162
1196
/*
1163
1197
* Execute the partial heap scan covering the heap blocks in the specified
1164
1198
* page range, summarizing the heap tuples in it. This scan stops just
@@ -1169,8 +1203,6 @@ summarize_range(IndexInfo *indexInfo, BrinBuildState *state, Relation heapRel,
1169
1203
* by transactions that are still in progress, among other corner cases.
1170
1204
*/
1171
1205
state -> bs_currRangeStart = heapBlk ;
1172
- scanNumBlks = heapBlk + state -> bs_pagesPerRange <= heapNumBlks ?
1173
- state -> bs_pagesPerRange : heapNumBlks - heapBlk ;
1174
1206
IndexBuildHeapRangeScan (heapRel , state -> bs_irel , indexInfo , false, true,
1175
1207
heapBlk , scanNumBlks ,
1176
1208
brinbuildCallback , (void * ) state );
@@ -1234,63 +1266,63 @@ summarize_range(IndexInfo *indexInfo, BrinBuildState *state, Relation heapRel,
1234
1266
* Summarize page ranges that are not already summarized. If pageRange is
1235
1267
* BRIN_ALL_BLOCKRANGES then the whole table is scanned; otherwise, only the
1236
1268
* page range containing the given heap page number is scanned.
1269
+ * If include_partial is true, then the partial range at the end of the table
1270
+ * is summarized, otherwise not.
1237
1271
*
1238
1272
* For each new index tuple inserted, *numSummarized (if not NULL) is
1239
1273
* incremented; for each existing tuple, *numExisting (if not NULL) is
1240
1274
* incremented.
1241
1275
*/
1242
1276
static void
1243
1277
brinsummarize (Relation index , Relation heapRel , BlockNumber pageRange ,
1244
- double * numSummarized , double * numExisting )
1278
+ bool include_partial , double * numSummarized , double * numExisting )
1245
1279
{
1246
1280
BrinRevmap * revmap ;
1247
1281
BrinBuildState * state = NULL ;
1248
1282
IndexInfo * indexInfo = NULL ;
1249
1283
BlockNumber heapNumBlocks ;
1250
- BlockNumber heapBlk ;
1251
1284
BlockNumber pagesPerRange ;
1252
1285
Buffer buf ;
1253
1286
BlockNumber startBlk ;
1254
- BlockNumber endBlk ;
1255
-
1256
- /* determine range of pages to process; nothing to do for an empty table */
1257
- heapNumBlocks = RelationGetNumberOfBlocks (heapRel );
1258
- if (heapNumBlocks == 0 )
1259
- return ;
1260
1287
1261
1288
revmap = brinRevmapInitialize (index , & pagesPerRange , NULL );
1262
1289
1290
+ /* determine range of pages to process */
1291
+ heapNumBlocks = RelationGetNumberOfBlocks (heapRel );
1263
1292
if (pageRange == BRIN_ALL_BLOCKRANGES )
1264
- {
1265
1293
startBlk = 0 ;
1266
- endBlk = heapNumBlocks ;
1267
- }
1268
1294
else
1269
- {
1270
1295
startBlk = (pageRange / pagesPerRange ) * pagesPerRange ;
1296
+ if (startBlk >= heapNumBlocks )
1297
+ {
1271
1298
/* Nothing to do if start point is beyond end of table */
1272
- if (startBlk > heapNumBlocks )
1273
- {
1274
- brinRevmapTerminate (revmap );
1275
- return ;
1276
- }
1277
- endBlk = startBlk + pagesPerRange ;
1278
- if (endBlk > heapNumBlocks )
1279
- endBlk = heapNumBlocks ;
1299
+ brinRevmapTerminate (revmap );
1300
+ return ;
1280
1301
}
1281
1302
1282
1303
/*
1283
1304
* Scan the revmap to find unsummarized items.
1284
1305
*/
1285
1306
buf = InvalidBuffer ;
1286
- for (heapBlk = startBlk ; heapBlk < endBlk ; heapBlk += pagesPerRange )
1307
+ for (; startBlk < heapNumBlocks ; startBlk += pagesPerRange )
1287
1308
{
1288
1309
BrinTuple * tup ;
1289
1310
OffsetNumber off ;
1290
1311
1312
+ /*
1313
+ * Unless requested to summarize even a partial range, go away now if
1314
+ * we think the next range is partial. Caller would pass true when
1315
+ * it is typically run once bulk data loading is done
1316
+ * (brin_summarize_new_values), and false when it is typically the
1317
+ * result of arbitrarily-scheduled maintenance command (vacuuming).
1318
+ */
1319
+ if (!include_partial &&
1320
+ (startBlk + pagesPerRange > heapNumBlocks ))
1321
+ break ;
1322
+
1291
1323
CHECK_FOR_INTERRUPTS ();
1292
1324
1293
- tup = brinGetTupleForHeapBlock (revmap , heapBlk , & buf , & off , NULL ,
1325
+ tup = brinGetTupleForHeapBlock (revmap , startBlk , & buf , & off , NULL ,
1294
1326
BUFFER_LOCK_SHARE , NULL );
1295
1327
if (tup == NULL )
1296
1328
{
@@ -1303,7 +1335,7 @@ brinsummarize(Relation index, Relation heapRel, BlockNumber pageRange,
1303
1335
pagesPerRange );
1304
1336
indexInfo = BuildIndexInfo (index );
1305
1337
}
1306
- summarize_range (indexInfo , state , heapRel , heapBlk , heapNumBlocks );
1338
+ summarize_range (indexInfo , state , heapRel , startBlk , heapNumBlocks );
1307
1339
1308
1340
/* and re-initialize state for the next range */
1309
1341
brin_memtuple_initialize (state -> bs_dtuple , state -> bs_bdesc );
0 commit comments