@@ -67,7 +67,7 @@ static BrinBuildState *initialize_brin_buildstate(Relation idxRel,
6767BrinRevmap * revmap ,BlockNumber pagesPerRange );
6868static void terminate_brin_buildstate (BrinBuildState * state );
6969static void brinsummarize (Relation index ,Relation heapRel ,BlockNumber pageRange ,
70- double * numSummarized ,double * numExisting );
70+ bool include_partial , double * numSummarized ,double * numExisting );
7171static void form_and_insert_tuple (BrinBuildState * state );
7272static void union_tuples (BrinDesc * bdesc ,BrinMemTuple * a ,
7373BrinTuple * b );
@@ -789,7 +789,7 @@ brinvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
789789
790790brin_vacuum_scan (info -> index ,info -> strategy );
791791
792- brinsummarize (info -> index ,heapRel ,BRIN_ALL_BLOCKRANGES ,
792+ brinsummarize (info -> index ,heapRel ,BRIN_ALL_BLOCKRANGES , false,
793793& stats -> num_index_tuples ,& stats -> num_index_tuples );
794794
795795heap_close (heapRel ,AccessShareLock );
@@ -907,7 +907,7 @@ brin_summarize_range(PG_FUNCTION_ARGS)
907907RelationGetRelationName (indexRel ))));
908908
909909/* OK, do it */
910- brinsummarize (indexRel ,heapRel ,heapBlk ,& numSummarized ,NULL );
910+ brinsummarize (indexRel ,heapRel ,heapBlk ,true, & numSummarized ,NULL );
911911
912912relation_close (indexRel ,ShareUpdateExclusiveLock );
913913relation_close (heapRel ,ShareUpdateExclusiveLock );
@@ -1127,7 +1127,8 @@ terminate_brin_buildstate(BrinBuildState *state)
11271127}
11281128
11291129/*
1130- * Summarize the given page range of the given index.
1130+ * On the given BRIN index, summarize the heap page range that corresponds
1131+ * to the heap block number given.
11311132 *
11321133 * This routine can run in parallel with insertions into the heap. To avoid
11331134 * missing those values from the summary tuple, we first insert a placeholder
@@ -1137,6 +1138,12 @@ terminate_brin_buildstate(BrinBuildState *state)
11371138 * update of the index value happens in a loop, so that if somebody updates
11381139 * the placeholder tuple after we read it, we detect the case and try again.
11391140 * This ensures that the concurrently inserted tuples are not lost.
1141+ *
1142+ * A further corner case is this routine being asked to summarize the partial
1143+ * range at the end of the table. heapNumBlocks is the (possibly outdated)
1144+ * table size; if we notice that the requested range lies beyond that size,
1145+ * we re-compute the table size after inserting the placeholder tuple, to
1146+ * avoid missing pages that were appended recently.
11401147 */
11411148static void
11421149summarize_range (IndexInfo * indexInfo ,BrinBuildState * state ,Relation heapRel ,
@@ -1157,6 +1164,33 @@ summarize_range(IndexInfo *indexInfo, BrinBuildState *state, Relation heapRel,
11571164state -> bs_rmAccess ,& phbuf ,
11581165heapBlk ,phtup ,phsz );
11591166
1167+ /*
1168+ * Compute range end. We hold ShareUpdateExclusive lock on table, so it
1169+ * cannot shrink concurrently (but it can grow).
1170+ */
1171+ Assert (heapBlk %state -> bs_pagesPerRange == 0 );
1172+ if (heapBlk + state -> bs_pagesPerRange > heapNumBlks )
1173+ {
1174+ /*
1175+ * If we're asked to scan what we believe to be the final range on the
1176+ * table (i.e. a range that might be partial) we need to recompute our
1177+ * idea of what the latest page is after inserting the placeholder
1178+ * tuple. Anyone that grows the table later will update the
1179+ * placeholder tuple, so it doesn't matter that we won't scan these
1180+ * pages ourselves. Careful: the table might have been extended
1181+ * beyond the current range, so clamp our result.
1182+ *
1183+ * Fortunately, this should occur infrequently.
1184+ */
1185+ scanNumBlks = Min (RelationGetNumberOfBlocks (heapRel )- heapBlk ,
1186+ state -> bs_pagesPerRange );
1187+ }
1188+ else
1189+ {
1190+ /* Easy case: range is known to be complete */
1191+ scanNumBlks = state -> bs_pagesPerRange ;
1192+ }
1193+
11601194/*
11611195 * Execute the partial heap scan covering the heap blocks in the specified
11621196 * page range, summarizing the heap tuples in it. This scan stops just
@@ -1167,8 +1201,6 @@ summarize_range(IndexInfo *indexInfo, BrinBuildState *state, Relation heapRel,
11671201 * by transactions that are still in progress, among other corner cases.
11681202 */
11691203state -> bs_currRangeStart = heapBlk ;
1170- scanNumBlks = heapBlk + state -> bs_pagesPerRange <=heapNumBlks ?
1171- state -> bs_pagesPerRange :heapNumBlks - heapBlk ;
11721204IndexBuildHeapRangeScan (heapRel ,state -> bs_irel ,indexInfo , false, true,
11731205heapBlk ,scanNumBlks ,
11741206brinbuildCallback , (void * )state );
@@ -1232,63 +1264,63 @@ summarize_range(IndexInfo *indexInfo, BrinBuildState *state, Relation heapRel,
12321264 * Summarize page ranges that are not already summarized. If pageRange is
12331265 * BRIN_ALL_BLOCKRANGES then the whole table is scanned; otherwise, only the
12341266 * page range containing the given heap page number is scanned.
1267+ * If include_partial is true, then the partial range at the end of the table
1268+ * is summarized, otherwise not.
12351269 *
12361270 * For each new index tuple inserted, *numSummarized (if not NULL) is
12371271 * incremented; for each existing tuple, *numExisting (if not NULL) is
12381272 * incremented.
12391273 */
12401274static void
12411275brinsummarize (Relation index ,Relation heapRel ,BlockNumber pageRange ,
1242- double * numSummarized ,double * numExisting )
1276+ bool include_partial , double * numSummarized ,double * numExisting )
12431277{
12441278BrinRevmap * revmap ;
12451279BrinBuildState * state = NULL ;
12461280IndexInfo * indexInfo = NULL ;
12471281BlockNumber heapNumBlocks ;
1248- BlockNumber heapBlk ;
12491282BlockNumber pagesPerRange ;
12501283Buffer buf ;
12511284BlockNumber startBlk ;
1252- BlockNumber endBlk ;
1253-
1254- /* determine range of pages to process; nothing to do for an empty table */
1255- heapNumBlocks = RelationGetNumberOfBlocks (heapRel );
1256- if (heapNumBlocks == 0 )
1257- return ;
12581285
12591286revmap = brinRevmapInitialize (index ,& pagesPerRange ,NULL );
12601287
1288+ /* determine range of pages to process */
1289+ heapNumBlocks = RelationGetNumberOfBlocks (heapRel );
12611290if (pageRange == BRIN_ALL_BLOCKRANGES )
1262- {
12631291startBlk = 0 ;
1264- endBlk = heapNumBlocks ;
1265- }
12661292else
1267- {
12681293startBlk = (pageRange /pagesPerRange )* pagesPerRange ;
1294+ if (startBlk >=heapNumBlocks )
1295+ {
12691296/* Nothing to do if start point is beyond end of table */
1270- if (startBlk > heapNumBlocks )
1271- {
1272- brinRevmapTerminate (revmap );
1273- return ;
1274- }
1275- endBlk = startBlk + pagesPerRange ;
1276- if (endBlk > heapNumBlocks )
1277- endBlk = heapNumBlocks ;
1297+ brinRevmapTerminate (revmap );
1298+ return ;
12781299}
12791300
12801301/*
12811302 * Scan the revmap to find unsummarized items.
12821303 */
12831304buf = InvalidBuffer ;
1284- for (heapBlk = startBlk ; heapBlk < endBlk ; heapBlk += pagesPerRange )
1305+ for (; startBlk < heapNumBlocks ; startBlk += pagesPerRange )
12851306{
12861307BrinTuple * tup ;
12871308OffsetNumber off ;
12881309
1310+ /*
1311+ * Unless requested to summarize even a partial range, go away now if
1312+ * we think the next range is partial. Caller would pass true when
1313+ * it is typically run once bulk data loading is done
1314+ * (brin_summarize_new_values), and false when it is typically the
1315+ * result of arbitrarily-scheduled maintenance command (vacuuming).
1316+ */
1317+ if (!include_partial &&
1318+ (startBlk + pagesPerRange > heapNumBlocks ))
1319+ break ;
1320+
12891321CHECK_FOR_INTERRUPTS ();
12901322
1291- tup = brinGetTupleForHeapBlock (revmap ,heapBlk ,& buf ,& off ,NULL ,
1323+ tup = brinGetTupleForHeapBlock (revmap ,startBlk ,& buf ,& off ,NULL ,
12921324BUFFER_LOCK_SHARE ,NULL );
12931325if (tup == NULL )
12941326{
@@ -1301,7 +1333,7 @@ brinsummarize(Relation index, Relation heapRel, BlockNumber pageRange,
13011333pagesPerRange );
13021334indexInfo = BuildIndexInfo (index );
13031335}
1304- summarize_range (indexInfo ,state ,heapRel ,heapBlk ,heapNumBlocks );
1336+ summarize_range (indexInfo ,state ,heapRel ,startBlk ,heapNumBlocks );
13051337
13061338/* and re-initialize state for the next range */
13071339brin_memtuple_initialize (state -> bs_dtuple ,state -> bs_bdesc );