@@ -27,6 +27,7 @@ typedef struct
27
27
{
28
28
GinState ginstate ;
29
29
double indtuples ;
30
+ GinStatsData buildStats ;
30
31
MemoryContext tmpCtx ;
31
32
MemoryContext funcCtx ;
32
33
BuildAccumulator accum ;
@@ -97,8 +98,10 @@ createPostingTree(Relation index, ItemPointerData *items, uint32 nitems)
97
98
* GinFormTuple().
98
99
*/
99
100
static IndexTuple
100
- addItemPointersToTuple (Relation index , GinState * ginstate , GinBtreeStack * stack ,
101
- IndexTuple old , ItemPointerData * items , uint32 nitem , bool isBuild )
101
+ addItemPointersToTuple (Relation index , GinState * ginstate ,
102
+ GinBtreeStack * stack , IndexTuple old ,
103
+ ItemPointerData * items , uint32 nitem ,
104
+ GinStatsData * buildStats )
102
105
{
103
106
Datum key = gin_index_getattr (ginstate , old );
104
107
OffsetNumber attnum = gintuple_get_attrnum (ginstate , old );
@@ -128,30 +131,41 @@ addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
128
131
GinSetPostingTree (res , postingRoot );
129
132
130
133
gdi = prepareScanPostingTree (index , postingRoot , FALSE);
131
- gdi -> btree .isBuild = isBuild ;
134
+ gdi -> btree .isBuild = ( buildStats != NULL ) ;
132
135
133
- insertItemPointer (gdi , items , nitem );
136
+ ginInsertItemPointer (gdi , items , nitem , buildStats );
134
137
135
138
pfree (gdi );
139
+
140
+ /* During index build, count the newly-added data page */
141
+ if (buildStats )
142
+ buildStats -> nDataPages ++ ;
136
143
}
137
144
138
145
return res ;
139
146
}
140
147
141
148
/*
142
149
* Inserts only one entry to the index, but it can add more than 1 ItemPointer.
150
+ *
151
+ * During an index build, buildStats is non-null and the counters
152
+ * it contains should be incremented as needed.
143
153
*/
144
154
void
145
155
ginEntryInsert (Relation index , GinState * ginstate ,
146
156
OffsetNumber attnum , Datum value ,
147
157
ItemPointerData * items , uint32 nitem ,
148
- bool isBuild )
158
+ GinStatsData * buildStats )
149
159
{
150
160
GinBtreeData btree ;
151
161
GinBtreeStack * stack ;
152
162
IndexTuple itup ;
153
163
Page page ;
154
164
165
+ /* During index build, count the to-be-inserted entry */
166
+ if (buildStats )
167
+ buildStats -> nEntries ++ ;
168
+
155
169
prepareEntryScan (& btree , index , attnum , value , ginstate );
156
170
157
171
stack = ginFindLeafPage (& btree , NULL );
@@ -174,14 +188,15 @@ ginEntryInsert(Relation index, GinState *ginstate,
174
188
175
189
/* insert into posting tree */
176
190
gdi = prepareScanPostingTree (index , rootPostingTree , FALSE);
177
- gdi -> btree .isBuild = isBuild ;
178
- insertItemPointer (gdi , items , nitem );
191
+ gdi -> btree .isBuild = ( buildStats != NULL ) ;
192
+ ginInsertItemPointer (gdi , items , nitem , buildStats );
179
193
pfree (gdi );
180
194
181
195
return ;
182
196
}
183
197
184
- itup = addItemPointersToTuple (index , ginstate , stack , itup , items , nitem , isBuild );
198
+ itup = addItemPointersToTuple (index , ginstate , stack , itup ,
199
+ items , nitem , buildStats );
185
200
186
201
btree .isDelete = TRUE;
187
202
}
@@ -195,13 +210,14 @@ ginEntryInsert(Relation index, GinState *ginstate,
195
210
/* Add the rest, making a posting tree if necessary */
196
211
IndexTuple previtup = itup ;
197
212
198
- itup = addItemPointersToTuple (index , ginstate , stack , previtup , items + 1 , nitem - 1 , isBuild );
213
+ itup = addItemPointersToTuple (index , ginstate , stack , previtup ,
214
+ items + 1 , nitem - 1 , buildStats );
199
215
pfree (previtup );
200
216
}
201
217
}
202
218
203
219
btree .entry = itup ;
204
- ginInsertValue (& btree , stack );
220
+ ginInsertValue (& btree , stack , buildStats );
205
221
pfree (itup );
206
222
}
207
223
@@ -260,7 +276,8 @@ ginBuildCallback(Relation index, HeapTuple htup, Datum *values,
260
276
{
261
277
/* there could be many entries, so be willing to abort here */
262
278
CHECK_FOR_INTERRUPTS ();
263
- ginEntryInsert (index , & buildstate -> ginstate , attnum , entry , list , nlist , TRUE);
279
+ ginEntryInsert (index , & buildstate -> ginstate , attnum , entry ,
280
+ list , nlist , & buildstate -> buildStats );
264
281
}
265
282
266
283
MemoryContextReset (buildstate -> tmpCtx );
@@ -292,6 +309,8 @@ ginbuild(PG_FUNCTION_ARGS)
292
309
RelationGetRelationName (index ));
293
310
294
311
initGinState (& buildstate .ginstate , index );
312
+ buildstate .indtuples = 0 ;
313
+ memset (& buildstate .buildStats , 0 , sizeof (GinStatsData ));
295
314
296
315
/* initialize the meta page */
297
316
MetaBuffer = GinNewBuffer (index );
@@ -331,8 +350,8 @@ ginbuild(PG_FUNCTION_ARGS)
331
350
UnlockReleaseBuffer (RootBuffer );
332
351
END_CRIT_SECTION ();
333
352
334
- /* build the index */
335
- buildstate .indtuples = 0 ;
353
+ /* count the root as first entry page */
354
+ buildstate .buildStats . nEntryPages ++ ;
336
355
337
356
/*
338
357
* create a temporary memory context that is reset once for each tuple
@@ -367,12 +386,19 @@ ginbuild(PG_FUNCTION_ARGS)
367
386
{
368
387
/* there could be many entries, so be willing to abort here */
369
388
CHECK_FOR_INTERRUPTS ();
370
- ginEntryInsert (index , & buildstate .ginstate , attnum , entry , list , nlist , TRUE);
389
+ ginEntryInsert (index , & buildstate .ginstate , attnum , entry ,
390
+ list , nlist , & buildstate .buildStats );
371
391
}
372
392
MemoryContextSwitchTo (oldCtx );
373
393
374
394
MemoryContextDelete (buildstate .tmpCtx );
375
395
396
+ /*
397
+ * Update metapage stats
398
+ */
399
+ buildstate .buildStats .nTotalPages = RelationGetNumberOfBlocks (index );
400
+ ginUpdateStats (index , & buildstate .buildStats );
401
+
376
402
/*
377
403
* Return statistics
378
404
*/
@@ -401,7 +427,7 @@ ginHeapTupleInsert(Relation index, GinState *ginstate, OffsetNumber attnum, Datu
401
427
return 0 ;
402
428
403
429
for (i = 0 ; i < nentries ; i ++ )
404
- ginEntryInsert (index , ginstate , attnum , entries [i ], item , 1 , FALSE );
430
+ ginEntryInsert (index , ginstate , attnum , entries [i ], item , 1 , NULL );
405
431
406
432
return nentries ;
407
433
}
0 commit comments