Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit c1ec02b

Browse files
committed
Reuse BrinDesc and BrinRevmap in brininsert
The brininsert code used to initialize (and destroy) BrinDesc and BrinRevmap for each tuple, which is not free. This patch initializes these structures only once, and reuses them for all inserts in the same command. The data is passed through indexInfo->ii_AmCache. This also introduces an optional AM callback "aminsertcleanup" that allows performing custom cleanup in case simply pfree-ing ii_AmCache is not sufficient (which is the case when the cache contains TupleDesc, Buffers, and so on). Author: Soumyadeep Chakraborty Reviewed-by: Alvaro Herrera, Matthias van de Meent, Tomas Vondra Discussion: https://postgr.es/m/CAE-ML%2B9r2%3DaO1wwji1sBN9gvPz2xRAtFUGfnffpd0ZqyuzjamA%40mail.gmail.com
1 parent 6ec8262 commit c1ec02b

File tree

13 files changed

+113
-12
lines changed

13 files changed

+113
-12
lines changed

contrib/bloom/blutils.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ blhandler(PG_FUNCTION_ARGS)
131131
amroutine->ambuild = blbuild;
132132
amroutine->ambuildempty = blbuildempty;
133133
amroutine->aminsert = blinsert;
134+
amroutine->aminsertcleanup = NULL;
134135
amroutine->ambulkdelete = blbulkdelete;
135136
amroutine->amvacuumcleanup = blvacuumcleanup;
136137
amroutine->amcanreturn = NULL;

doc/src/sgml/indexam.sgml

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ typedef struct IndexAmRoutine
139139
ambuild_function ambuild;
140140
ambuildempty_function ambuildempty;
141141
aminsert_function aminsert;
142+
aminsertcleanup_function aminsertcleanup;
142143
ambulkdelete_function ambulkdelete;
143144
amvacuumcleanup_function amvacuumcleanup;
144145
amcanreturn_function amcanreturn; /* can be NULL */
@@ -359,7 +360,21 @@ aminsert (Relation indexRelation,
359360
within an SQL statement, it can allocate space
360361
in <literal>indexInfo-&gt;ii_Context</literal> and store a pointer to the
361362
data in <literal>indexInfo-&gt;ii_AmCache</literal> (which will be NULL
362-
initially).
363+
initially). After the index insertions complete, the memory will be freed
364+
automatically. If additional cleanup is required (e.g. if the cache contains
365+
buffers and tuple descriptors), the AM may define an optional function
366+
<literal>indexinsertcleanup</literal>, called before the memory is released.
367+
</para>
368+
369+
<para>
370+
<programlisting>
371+
void
372+
aminsertcleanup (IndexInfo *indexInfo);
373+
</programlisting>
374+
Clean up state that was maintained across successive inserts in
375+
<literal>indexInfo-&gt;ii_AmCache</literal>. This is useful if the data
376+
requires additional cleanup steps, and simply releasing the memory is not
377+
sufficient.
363378
</para>
364379

365380
<para>

src/backend/access/brin/brin.c

Lines changed: 64 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,17 @@ typedef struct BrinBuildState
5858
BrinMemTuple *bs_dtuple;
5959
} BrinBuildState;
6060

61+
/*
62+
* We use a BrinInsertState to capture running state spanning multiple
63+
* brininsert invocations, within the same command.
64+
*/
65+
typedef struct BrinInsertState
66+
{
67+
BrinRevmap *bis_rmAccess;
68+
BrinDesc *bis_desc;
69+
BlockNumber bis_pages_per_range;
70+
} BrinInsertState;
71+
6172
/*
6273
* Struct used as "opaque" during index scans
6374
*/
@@ -72,6 +83,7 @@ typedef struct BrinOpaque
7283

7384
static BrinBuildState *initialize_brin_buildstate(Relation idxRel,
7485
BrinRevmap *revmap, BlockNumber pagesPerRange);
86+
static BrinInsertState *initialize_brin_insertstate(Relation idxRel, IndexInfo *indexInfo);
7587
static void terminate_brin_buildstate(BrinBuildState *state);
7688
static void brinsummarize(Relation index, Relation heapRel, BlockNumber pageRange,
7789
bool include_partial, double *numSummarized, double *numExisting);
@@ -117,6 +129,7 @@ brinhandler(PG_FUNCTION_ARGS)
117129
amroutine->ambuild = brinbuild;
118130
amroutine->ambuildempty = brinbuildempty;
119131
amroutine->aminsert = brininsert;
132+
amroutine->aminsertcleanup = brininsertcleanup;
120133
amroutine->ambulkdelete = brinbulkdelete;
121134
amroutine->amvacuumcleanup = brinvacuumcleanup;
122135
amroutine->amcanreturn = NULL;
@@ -140,6 +153,27 @@ brinhandler(PG_FUNCTION_ARGS)
140153
PG_RETURN_POINTER(amroutine);
141154
}
142155

156+
/*
157+
* Initialize a BrinInsertState to maintain state to be used across multiple
158+
* tuple inserts, within the same command.
159+
*/
160+
static BrinInsertState *
161+
initialize_brin_insertstate(Relation idxRel, IndexInfo *indexInfo)
162+
{
163+
BrinInsertState *bistate;
164+
MemoryContext oldcxt;
165+
166+
oldcxt = MemoryContextSwitchTo(indexInfo->ii_Context);
167+
bistate = palloc0(sizeof(BrinInsertState));
168+
bistate->bis_desc = brin_build_desc(idxRel);
169+
bistate->bis_rmAccess = brinRevmapInitialize(idxRel,
170+
&bistate->bis_pages_per_range);
171+
indexInfo->ii_AmCache = bistate;
172+
MemoryContextSwitchTo(oldcxt);
173+
174+
return bistate;
175+
}
176+
143177
/*
144178
* A tuple in the heap is being inserted. To keep a brin index up to date,
145179
* we need to obtain the relevant index tuple and compare its stored values
@@ -162,14 +196,24 @@ brininsert(Relation idxRel, Datum *values, bool *nulls,
162196
BlockNumber pagesPerRange;
163197
BlockNumber origHeapBlk;
164198
BlockNumber heapBlk;
165-
BrinDesc *bdesc = (BrinDesc *) indexInfo->ii_AmCache;
199+
BrinInsertState *bistate = (BrinInsertState *) indexInfo->ii_AmCache;
166200
BrinRevmap *revmap;
201+
BrinDesc *bdesc;
167202
Buffer buf = InvalidBuffer;
168203
MemoryContext tupcxt = NULL;
169204
MemoryContext oldcxt = CurrentMemoryContext;
170205
bool autosummarize = BrinGetAutoSummarize(idxRel);
171206

172-
revmap = brinRevmapInitialize(idxRel, &pagesPerRange);
207+
/*
208+
* If firt time through in this statement, initialize the insert state
209+
* that we keep for all the inserts in the command.
210+
*/
211+
if (!bistate)
212+
bistate = initialize_brin_insertstate(idxRel, indexInfo);
213+
214+
revmap = bistate->bis_rmAccess;
215+
bdesc = bistate->bis_desc;
216+
pagesPerRange = bistate->bis_pages_per_range;
173217

174218
/*
175219
* origHeapBlk is the block number where the insertion occurred. heapBlk
@@ -228,14 +272,6 @@ brininsert(Relation idxRel, Datum *values, bool *nulls,
228272
if (!brtup)
229273
break;
230274

231-
/* First time through in this statement? */
232-
if (bdesc == NULL)
233-
{
234-
MemoryContextSwitchTo(indexInfo->ii_Context);
235-
bdesc = brin_build_desc(idxRel);
236-
indexInfo->ii_AmCache = (void *) bdesc;
237-
MemoryContextSwitchTo(oldcxt);
238-
}
239275
/* First time through in this brininsert call? */
240276
if (tupcxt == NULL)
241277
{
@@ -306,7 +342,6 @@ brininsert(Relation idxRel, Datum *values, bool *nulls,
306342
break;
307343
}
308344

309-
brinRevmapTerminate(revmap);
310345
if (BufferIsValid(buf))
311346
ReleaseBuffer(buf);
312347
MemoryContextSwitchTo(oldcxt);
@@ -316,6 +351,24 @@ brininsert(Relation idxRel, Datum *values, bool *nulls,
316351
return false;
317352
}
318353

354+
/*
355+
* Callback to clean up the BrinInsertState once all tuple inserts are done.
356+
*/
357+
void
358+
brininsertcleanup(IndexInfo *indexInfo)
359+
{
360+
BrinInsertState *bistate = (BrinInsertState *) indexInfo->ii_AmCache;
361+
362+
Assert(bistate);
363+
/*
364+
* Clean up the revmap. Note that the brinDesc has already been cleaned up
365+
* as part of its own memory context.
366+
*/
367+
brinRevmapTerminate(bistate->bis_rmAccess);
368+
bistate->bis_rmAccess = NULL;
369+
bistate->bis_desc = NULL;
370+
}
371+
319372
/*
320373
* Initialize state for a BRIN index scan.
321374
*

src/backend/access/gin/ginutil.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ ginhandler(PG_FUNCTION_ARGS)
6464
amroutine->ambuild = ginbuild;
6565
amroutine->ambuildempty = ginbuildempty;
6666
amroutine->aminsert = gininsert;
67+
amroutine->aminsertcleanup = NULL;
6768
amroutine->ambulkdelete = ginbulkdelete;
6869
amroutine->amvacuumcleanup = ginvacuumcleanup;
6970
amroutine->amcanreturn = NULL;

src/backend/access/gist/gist.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ gisthandler(PG_FUNCTION_ARGS)
8686
amroutine->ambuild = gistbuild;
8787
amroutine->ambuildempty = gistbuildempty;
8888
amroutine->aminsert = gistinsert;
89+
amroutine->aminsertcleanup = NULL;
8990
amroutine->ambulkdelete = gistbulkdelete;
9091
amroutine->amvacuumcleanup = gistvacuumcleanup;
9192
amroutine->amcanreturn = gistcanreturn;

src/backend/access/hash/hash.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ hashhandler(PG_FUNCTION_ARGS)
8383
amroutine->ambuild = hashbuild;
8484
amroutine->ambuildempty = hashbuildempty;
8585
amroutine->aminsert = hashinsert;
86+
amroutine->aminsertcleanup = NULL;
8687
amroutine->ambulkdelete = hashbulkdelete;
8788
amroutine->amvacuumcleanup = hashvacuumcleanup;
8889
amroutine->amcanreturn = NULL;

src/backend/access/index/indexam.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,21 @@ index_insert(Relation indexRelation,
196196
indexInfo);
197197
}
198198

199+
/* -------------------------
200+
* index_insert_cleanup - clean up after all index inserts are done
201+
* -------------------------
202+
*/
203+
void
204+
index_insert_cleanup(Relation indexRelation,
205+
IndexInfo *indexInfo)
206+
{
207+
RELATION_CHECKS;
208+
Assert(indexInfo);
209+
210+
if (indexRelation->rd_indam->aminsertcleanup)
211+
indexRelation->rd_indam->aminsertcleanup(indexInfo);
212+
}
213+
199214
/*
200215
* index_beginscan - start a scan of an index with amgettuple
201216
*

src/backend/access/nbtree/nbtree.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ bthandler(PG_FUNCTION_ARGS)
122122
amroutine->ambuild = btbuild;
123123
amroutine->ambuildempty = btbuildempty;
124124
amroutine->aminsert = btinsert;
125+
amroutine->aminsertcleanup = NULL;
125126
amroutine->ambulkdelete = btbulkdelete;
126127
amroutine->amvacuumcleanup = btvacuumcleanup;
127128
amroutine->amcanreturn = btcanreturn;

src/backend/access/spgist/spgutils.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ spghandler(PG_FUNCTION_ARGS)
7070
amroutine->ambuild = spgbuild;
7171
amroutine->ambuildempty = spgbuildempty;
7272
amroutine->aminsert = spginsert;
73+
amroutine->aminsertcleanup = NULL;
7374
amroutine->ambulkdelete = spgbulkdelete;
7475
amroutine->amvacuumcleanup = spgvacuumcleanup;
7576
amroutine->amcanreturn = spgcanreturn;

src/backend/executor/execIndexing.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,15 +233,20 @@ ExecCloseIndices(ResultRelInfo *resultRelInfo)
233233
int i;
234234
int numIndices;
235235
RelationPtr indexDescs;
236+
IndexInfo **indexInfos;
236237

237238
numIndices = resultRelInfo->ri_NumIndices;
238239
indexDescs = resultRelInfo->ri_IndexRelationDescs;
240+
indexInfos = resultRelInfo->ri_IndexRelationInfo;
239241

240242
for (i = 0; i < numIndices; i++)
241243
{
242244
if (indexDescs[i] == NULL)
243245
continue; /* shouldn't happen? */
244246

247+
/* Give the index a chance to do some post-insert cleanup */
248+
index_insert_cleanup(indexDescs[i], indexInfos[i]);
249+
245250
/* Drop lock acquired by ExecOpenIndices */
246251
index_close(indexDescs[i], RowExclusiveLock);
247252
}

src/include/access/amapi.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ typedef bool (*aminsert_function) (Relation indexRelation,
113113
bool indexUnchanged,
114114
struct IndexInfo *indexInfo);
115115

116+
/* cleanup after insert */
117+
typedef void (*aminsertcleanup_function) (struct IndexInfo *indexInfo);
118+
116119
/* bulk delete */
117120
typedef IndexBulkDeleteResult *(*ambulkdelete_function) (IndexVacuumInfo *info,
118121
IndexBulkDeleteResult *stats,
@@ -261,6 +264,7 @@ typedef struct IndexAmRoutine
261264
ambuild_function ambuild;
262265
ambuildempty_function ambuildempty;
263266
aminsert_function aminsert;
267+
aminsertcleanup_function aminsertcleanup;
264268
ambulkdelete_function ambulkdelete;
265269
amvacuumcleanup_function amvacuumcleanup;
266270
amcanreturn_function amcanreturn; /* can be NULL */

src/include/access/brin_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ extern bool brininsert(Relation idxRel, Datum *values, bool *nulls,
9696
IndexUniqueCheck checkUnique,
9797
bool indexUnchanged,
9898
struct IndexInfo *indexInfo);
99+
extern void brininsertcleanup(struct IndexInfo *indexInfo);
99100
extern IndexScanDesc brinbeginscan(Relation r, int nkeys, int norderbys);
100101
extern int64 bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm);
101102
extern void brinrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys,

src/include/access/genam.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ extern bool index_insert(Relation indexRelation,
148148
IndexUniqueCheck checkUnique,
149149
bool indexUnchanged,
150150
struct IndexInfo *indexInfo);
151+
extern void index_insert_cleanup(Relation indexRelation,
152+
struct IndexInfo *indexInfo);
151153

152154
extern IndexScanDesc index_beginscan(Relation heapRelation,
153155
Relation indexRelation,

0 commit comments

Comments
 (0)