@@ -957,7 +957,8 @@ terminate_brin_buildstate(BrinBuildState *state)
957
957
}
958
958
959
959
/*
960
- * Summarize the given page range of the given index.
960
+ * On the given BRIN index, summarize the heap page range that corresponds
961
+ * to the heap block number given.
961
962
*
962
963
* This routine can run in parallel with insertions into the heap. To avoid
963
964
* missing those values from the summary tuple, we first insert a placeholder
@@ -967,6 +968,12 @@ terminate_brin_buildstate(BrinBuildState *state)
967
968
* update of the index value happens in a loop, so that if somebody updates
968
969
* the placeholder tuple after we read it, we detect the case and try again.
969
970
* This ensures that the concurrently inserted tuples are not lost.
971
+ *
972
+ * A further corner case is this routine being asked to summarize the partial
973
+ * range at the end of the table. heapNumBlocks is the (possibly outdated)
974
+ * table size; if we notice that the requested range lies beyond that size,
975
+ * we re-compute the table size after inserting the placeholder tuple, to
976
+ * avoid missing pages that were appended recently.
970
977
*/
971
978
static void
972
979
summarize_range (IndexInfo * indexInfo , BrinBuildState * state , Relation heapRel ,
@@ -987,6 +994,33 @@ summarize_range(IndexInfo *indexInfo, BrinBuildState *state, Relation heapRel,
987
994
state -> bs_rmAccess , & phbuf ,
988
995
heapBlk , phtup , phsz );
989
996
997
+ /*
998
+ * Compute range end. We hold ShareUpdateExclusive lock on table, so it
999
+ * cannot shrink concurrently (but it can grow).
1000
+ */
1001
+ Assert (heapBlk % state -> bs_pagesPerRange == 0 );
1002
+ if (heapBlk + state -> bs_pagesPerRange > heapNumBlks )
1003
+ {
1004
+ /*
1005
+ * If we're asked to scan what we believe to be the final range on the
1006
+ * table (i.e. a range that might be partial) we need to recompute our
1007
+ * idea of what the latest page is after inserting the placeholder
1008
+ * tuple. Anyone that grows the table later will update the
1009
+ * placeholder tuple, so it doesn't matter that we won't scan these
1010
+ * pages ourselves. Careful: the table might have been extended
1011
+ * beyond the current range, so clamp our result.
1012
+ *
1013
+ * Fortunately, this should occur infrequently.
1014
+ */
1015
+ scanNumBlks = Min (RelationGetNumberOfBlocks (heapRel ) - heapBlk ,
1016
+ state -> bs_pagesPerRange );
1017
+ }
1018
+ else
1019
+ {
1020
+ /* Easy case: range is known to be complete */
1021
+ scanNumBlks = state -> bs_pagesPerRange ;
1022
+ }
1023
+
990
1024
/*
991
1025
* Execute the partial heap scan covering the heap blocks in the specified
992
1026
* page range, summarizing the heap tuples in it. This scan stops just
@@ -997,8 +1031,6 @@ summarize_range(IndexInfo *indexInfo, BrinBuildState *state, Relation heapRel,
997
1031
* by transactions that are still in progress, among other corner cases.
998
1032
*/
999
1033
state -> bs_currRangeStart = heapBlk ;
1000
- scanNumBlks = heapBlk + state -> bs_pagesPerRange <= heapNumBlks ?
1001
- state -> bs_pagesPerRange : heapNumBlks - heapBlk ;
1002
1034
IndexBuildHeapRangeScan (heapRel , state -> bs_irel , indexInfo , false, true,
1003
1035
heapBlk , scanNumBlks ,
1004
1036
brinbuildCallback , (void * ) state );
@@ -1074,25 +1106,34 @@ brinsummarize(Relation index, Relation heapRel, double *numSummarized,
1074
1106
BrinBuildState * state = NULL ;
1075
1107
IndexInfo * indexInfo = NULL ;
1076
1108
BlockNumber heapNumBlocks ;
1077
- BlockNumber heapBlk ;
1078
1109
BlockNumber pagesPerRange ;
1079
1110
Buffer buf ;
1111
+ BlockNumber startBlk ;
1080
1112
1081
1113
revmap = brinRevmapInitialize (index , & pagesPerRange );
1082
1114
1115
+ /* determine range of pages to process: always start from the beginning */
1116
+ heapNumBlocks = RelationGetNumberOfBlocks (heapRel );
1117
+ startBlk = 0 ;
1118
+
1083
1119
/*
1084
1120
* Scan the revmap to find unsummarized items.
1085
1121
*/
1086
1122
buf = InvalidBuffer ;
1087
- heapNumBlocks = RelationGetNumberOfBlocks (heapRel );
1088
- for (heapBlk = 0 ; heapBlk < heapNumBlocks ; heapBlk += pagesPerRange )
1123
+ for (; startBlk < heapNumBlocks ; startBlk += pagesPerRange )
1089
1124
{
1090
1125
BrinTuple * tup ;
1091
1126
OffsetNumber off ;
1092
1127
1128
+ /*
1129
+ * Go away now if we think the next range is partial.
1130
+ */
1131
+ if (startBlk + pagesPerRange > heapNumBlocks )
1132
+ break ;
1133
+
1093
1134
CHECK_FOR_INTERRUPTS ();
1094
1135
1095
- tup = brinGetTupleForHeapBlock (revmap , heapBlk , & buf , & off , NULL ,
1136
+ tup = brinGetTupleForHeapBlock (revmap , startBlk , & buf , & off , NULL ,
1096
1137
BUFFER_LOCK_SHARE );
1097
1138
if (tup == NULL )
1098
1139
{
@@ -1105,7 +1146,7 @@ brinsummarize(Relation index, Relation heapRel, double *numSummarized,
1105
1146
pagesPerRange );
1106
1147
indexInfo = BuildIndexInfo (index );
1107
1148
}
1108
- summarize_range (indexInfo , state , heapRel , heapBlk , heapNumBlocks );
1149
+ summarize_range (indexInfo , state , heapRel , startBlk , heapNumBlocks );
1109
1150
1110
1151
/* and re-initialize state for the next range */
1111
1152
brin_memtuple_initialize (state -> bs_dtuple , state -> bs_bdesc );
0 commit comments