26
26
#include "catalog/pg_am.h"
27
27
#include "miscadmin.h"
28
28
#include "pgstat.h"
29
+ #include "postmaster/autovacuum.h"
29
30
#include "storage/bufmgr.h"
30
31
#include "storage/freespace.h"
31
32
#include "utils/builtins.h"
@@ -60,10 +61,12 @@ typedef struct BrinOpaque
60
61
BrinDesc * bo_bdesc ;
61
62
} BrinOpaque ;
62
63
64
+ #define BRIN_ALL_BLOCKRANGES InvalidBlockNumber
65
+
63
66
static BrinBuildState * initialize_brin_buildstate (Relation idxRel ,
64
67
BrinRevmap * revmap , BlockNumber pagesPerRange );
65
68
static void terminate_brin_buildstate (BrinBuildState * state );
66
- static void brinsummarize (Relation index , Relation heapRel ,
69
+ static void brinsummarize (Relation index , Relation heapRel , BlockNumber pageRange ,
67
70
double * numSummarized , double * numExisting );
68
71
static void form_and_insert_tuple (BrinBuildState * state );
69
72
static void union_tuples (BrinDesc * bdesc , BrinMemTuple * a ,
@@ -126,8 +129,11 @@ brinhandler(PG_FUNCTION_ARGS)
126
129
* with those of the new tuple. If the tuple values are not consistent with
127
130
* the summary tuple, we need to update the index tuple.
128
131
*
132
+ * If autosummarization is enabled, check if we need to summarize the previous
133
+ * page range.
134
+ *
129
135
* If the range is not currently summarized (i.e. the revmap returns NULL for
130
- * it), there's nothing to do.
136
+ * it), there's nothing to do for this tuple .
131
137
*/
132
138
bool
133
139
brininsert (Relation idxRel , Datum * values , bool * nulls ,
@@ -136,30 +142,59 @@ brininsert(Relation idxRel, Datum *values, bool *nulls,
136
142
IndexInfo * indexInfo )
137
143
{
138
144
BlockNumber pagesPerRange ;
145
+ BlockNumber origHeapBlk ;
146
+ BlockNumber heapBlk ;
139
147
BrinDesc * bdesc = (BrinDesc * ) indexInfo -> ii_AmCache ;
140
148
BrinRevmap * revmap ;
141
149
Buffer buf = InvalidBuffer ;
142
150
MemoryContext tupcxt = NULL ;
143
151
MemoryContext oldcxt = CurrentMemoryContext ;
152
+ bool autosummarize = BrinGetAutoSummarize (idxRel );
144
153
145
154
revmap = brinRevmapInitialize (idxRel , & pagesPerRange , NULL );
146
155
156
+ /*
157
+ * origHeapBlk is the block number where the insertion occurred. heapBlk
158
+ * is the first block in the corresponding page range.
159
+ */
160
+ origHeapBlk = ItemPointerGetBlockNumber (heaptid );
161
+ heapBlk = (origHeapBlk / pagesPerRange ) * pagesPerRange ;
162
+
147
163
for (;;)
148
164
{
149
165
bool need_insert = false;
150
166
OffsetNumber off ;
151
167
BrinTuple * brtup ;
152
168
BrinMemTuple * dtup ;
153
- BlockNumber heapBlk ;
154
169
int keyno ;
155
170
156
171
CHECK_FOR_INTERRUPTS ();
157
172
158
- heapBlk = ItemPointerGetBlockNumber (heaptid );
159
- /* normalize the block number to be the first block in the range */
160
- heapBlk = (heapBlk / pagesPerRange ) * pagesPerRange ;
161
- brtup = brinGetTupleForHeapBlock (revmap , heapBlk , & buf , & off , NULL ,
162
- BUFFER_LOCK_SHARE , NULL );
173
+ /*
174
+ * If auto-summarization is enabled and we just inserted the first
175
+ * tuple into the first block of a new non-first page range, request a
176
+ * summarization run of the previous range.
177
+ */
178
+ if (autosummarize &&
179
+ heapBlk > 0 &&
180
+ heapBlk == origHeapBlk &&
181
+ ItemPointerGetOffsetNumber (heaptid ) == FirstOffsetNumber )
182
+ {
183
+ BlockNumber lastPageRange = heapBlk - 1 ;
184
+ BrinTuple * lastPageTuple ;
185
+
186
+ lastPageTuple =
187
+ brinGetTupleForHeapBlock (revmap , lastPageRange , & buf , & off ,
188
+ NULL , BUFFER_LOCK_SHARE , NULL );
189
+ if (!lastPageTuple )
190
+ AutoVacuumRequestWork (AVW_BRINSummarizeRange ,
191
+ RelationGetRelid (idxRel ),
192
+ lastPageRange );
193
+ brin_free_tuple (lastPageTuple );
194
+ }
195
+
196
+ brtup = brinGetTupleForHeapBlock (revmap , heapBlk , & buf , & off ,
197
+ NULL , BUFFER_LOCK_SHARE , NULL );
163
198
164
199
/* if range is unsummarized, there's nothing to do */
165
200
if (!brtup )
@@ -747,7 +782,7 @@ brinvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
747
782
748
783
brin_vacuum_scan (info -> index , info -> strategy );
749
784
750
- brinsummarize (info -> index , heapRel ,
785
+ brinsummarize (info -> index , heapRel , BRIN_ALL_BLOCKRANGES ,
751
786
& stats -> num_index_tuples , & stats -> num_index_tuples );
752
787
753
788
heap_close (heapRel , AccessShareLock );
@@ -765,7 +800,8 @@ brinoptions(Datum reloptions, bool validate)
765
800
BrinOptions * rdopts ;
766
801
int numoptions ;
767
802
static const relopt_parse_elt tab [] = {
768
- {"pages_per_range" , RELOPT_TYPE_INT , offsetof(BrinOptions , pagesPerRange )}
803
+ {"pages_per_range" , RELOPT_TYPE_INT , offsetof(BrinOptions , pagesPerRange )},
804
+ {"autosummarize" , RELOPT_TYPE_BOOL , offsetof(BrinOptions , autosummarize )}
769
805
};
770
806
771
807
options = parseRelOptions (reloptions , validate , RELOPT_KIND_BRIN ,
@@ -791,13 +827,40 @@ brinoptions(Datum reloptions, bool validate)
791
827
*/
792
828
Datum
793
829
brin_summarize_new_values (PG_FUNCTION_ARGS )
830
+ {
831
+ Datum relation = PG_GETARG_DATUM (0 );
832
+
833
+ return DirectFunctionCall2 (brin_summarize_range ,
834
+ relation ,
835
+ Int64GetDatum ((int64 ) BRIN_ALL_BLOCKRANGES ));
836
+ }
837
+
838
+ /*
839
+ * SQL-callable function to summarize the indicated page range, if not already
840
+ * summarized. If the second argument is BRIN_ALL_BLOCKRANGES, all
841
+ * unsummarized ranges are summarized.
842
+ */
843
+ Datum
844
+ brin_summarize_range (PG_FUNCTION_ARGS )
794
845
{
795
846
Oid indexoid = PG_GETARG_OID (0 );
847
+ int64 heapBlk64 = PG_GETARG_INT64 (1 );
848
+ BlockNumber heapBlk ;
796
849
Oid heapoid ;
797
850
Relation indexRel ;
798
851
Relation heapRel ;
799
852
double numSummarized = 0 ;
800
853
854
+ if (heapBlk64 > BRIN_ALL_BLOCKRANGES || heapBlk64 < 0 )
855
+ {
856
+ char * blk = psprintf (INT64_FORMAT , heapBlk64 );
857
+
858
+ ereport (ERROR ,
859
+ (errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
860
+ errmsg ("block number out of range: %s" , blk )));
861
+ }
862
+ heapBlk = (BlockNumber ) heapBlk64 ;
863
+
801
864
/*
802
865
* We must lock table before index to avoid deadlocks. However, if the
803
866
* passed indexoid isn't an index then IndexGetRelation() will fail.
@@ -837,7 +900,7 @@ brin_summarize_new_values(PG_FUNCTION_ARGS)
837
900
RelationGetRelationName (indexRel ))));
838
901
839
902
/* OK, do it */
840
- brinsummarize (indexRel , heapRel , & numSummarized , NULL );
903
+ brinsummarize (indexRel , heapRel , heapBlk , & numSummarized , NULL );
841
904
842
905
relation_close (indexRel , ShareUpdateExclusiveLock );
843
906
relation_close (heapRel , ShareUpdateExclusiveLock );
@@ -1063,17 +1126,17 @@ summarize_range(IndexInfo *indexInfo, BrinBuildState *state, Relation heapRel,
1063
1126
}
1064
1127
1065
1128
/*
1066
- * Scan a complete BRIN index, and summarize each page range that's not already
1067
- * summarized. The index and heap must have been locked by caller in at
1068
- * least ShareUpdateExclusiveLock mode .
1129
+ * Summarize page ranges that are not already summarized. If pageRange is
1130
+ * BRIN_ALL_BLOCKRANGES then the whole table is scanned; otherwise, only the
1131
+ * page range containing the given heap page number is scanned .
1069
1132
*
1070
1133
* For each new index tuple inserted, *numSummarized (if not NULL) is
1071
1134
* incremented; for each existing tuple, *numExisting (if not NULL) is
1072
1135
* incremented.
1073
1136
*/
1074
1137
static void
1075
- brinsummarize (Relation index , Relation heapRel , double * numSummarized ,
1076
- double * numExisting )
1138
+ brinsummarize (Relation index , Relation heapRel , BlockNumber pageRange ,
1139
+ double * numSummarized , double * numExisting )
1077
1140
{
1078
1141
BrinRevmap * revmap ;
1079
1142
BrinBuildState * state = NULL ;
@@ -1082,15 +1145,40 @@ brinsummarize(Relation index, Relation heapRel, double *numSummarized,
1082
1145
BlockNumber heapBlk ;
1083
1146
BlockNumber pagesPerRange ;
1084
1147
Buffer buf ;
1148
+ BlockNumber startBlk ;
1149
+ BlockNumber endBlk ;
1150
+
1151
+ /* determine range of pages to process; nothing to do for an empty table */
1152
+ heapNumBlocks = RelationGetNumberOfBlocks (heapRel );
1153
+ if (heapNumBlocks == 0 )
1154
+ return ;
1085
1155
1086
1156
revmap = brinRevmapInitialize (index , & pagesPerRange , NULL );
1087
1157
1158
+ if (pageRange == BRIN_ALL_BLOCKRANGES )
1159
+ {
1160
+ startBlk = 0 ;
1161
+ endBlk = heapNumBlocks ;
1162
+ }
1163
+ else
1164
+ {
1165
+ startBlk = (pageRange / pagesPerRange ) * pagesPerRange ;
1166
+ /* Nothing to do if start point is beyond end of table */
1167
+ if (startBlk > heapNumBlocks )
1168
+ {
1169
+ brinRevmapTerminate (revmap );
1170
+ return ;
1171
+ }
1172
+ endBlk = startBlk + pagesPerRange ;
1173
+ if (endBlk > heapNumBlocks )
1174
+ endBlk = heapNumBlocks ;
1175
+ }
1176
+
1088
1177
/*
1089
1178
* Scan the revmap to find unsummarized items.
1090
1179
*/
1091
1180
buf = InvalidBuffer ;
1092
- heapNumBlocks = RelationGetNumberOfBlocks (heapRel );
1093
- for (heapBlk = 0 ; heapBlk < heapNumBlocks ; heapBlk += pagesPerRange )
1181
+ for (heapBlk = startBlk ; heapBlk < endBlk ; heapBlk += pagesPerRange )
1094
1182
{
1095
1183
BrinTuple * tup ;
1096
1184
OffsetNumber off ;
0 commit comments