diff --git a/contrib/bloom/blinsert.c b/contrib/bloom/blinsert.c index 29bc5cea79..913f1f8a51 100644 --- a/contrib/bloom/blinsert.c +++ b/contrib/bloom/blinsert.c @@ -190,7 +190,9 @@ blbuildempty(Relation index) */ bool blinsert(Relation index, Datum *values, bool *isnull, - ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique) + ItemPointer ht_ctid, Relation heapRel, + IndexUniqueCheck checkUnique, + IndexInfo *indexInfo) { BloomState blstate; BloomTuple *itup; diff --git a/contrib/bloom/bloom.h b/contrib/bloom/bloom.h index a75a235a4f..39d8d05c5d 100644 --- a/contrib/bloom/bloom.h +++ b/contrib/bloom/bloom.h @@ -189,7 +189,8 @@ extern bool blvalidate(Oid opclassoid); /* index access method interface functions */ extern bool blinsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, - IndexUniqueCheck checkUnique); + IndexUniqueCheck checkUnique, + struct IndexInfo *indexInfo); extern IndexScanDesc blbeginscan(Relation r, int nkeys, int norderbys); extern int64 blgetbitmap(IndexScanDesc scan, TIDBitmap *tbm); extern void blrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, diff --git a/doc/src/sgml/indexam.sgml b/doc/src/sgml/indexam.sgml index 5d8e557460..9afd7f6417 100644 --- a/doc/src/sgml/indexam.sgml +++ b/doc/src/sgml/indexam.sgml @@ -259,7 +259,8 @@ aminsert (Relation indexRelation, bool *isnull, ItemPointer heap_tid, Relation heapRelation, - IndexUniqueCheck checkUnique); + IndexUniqueCheck checkUnique, + IndexInfo *indexInfo); Insert a new tuple into an existing index. The values and isnull arrays give the key values to be indexed, and @@ -287,6 +288,14 @@ aminsert (Relation indexRelation, indexed, aminsert should just return without doing anything. + + If the index AM wishes to cache data across successive index insertions + within a SQL statement, it can allocate space + in indexInfo->ii_Context and store a pointer to the + data in indexInfo->ii_AmCache (which will be NULL + initially). + + IndexBulkDeleteResult * diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index b2afdb7bed..4ff046b4b0 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -131,14 +131,15 @@ brinhandler(PG_FUNCTION_ARGS) bool brininsert(Relation idxRel, Datum *values, bool *nulls, ItemPointer heaptid, Relation heapRel, - IndexUniqueCheck checkUnique) + IndexUniqueCheck checkUnique, + IndexInfo *indexInfo) { BlockNumber pagesPerRange; - BrinDesc *bdesc = NULL; + BrinDesc *bdesc = (BrinDesc *) indexInfo->ii_AmCache; BrinRevmap *revmap; Buffer buf = InvalidBuffer; MemoryContext tupcxt = NULL; - MemoryContext oldcxt = NULL; + MemoryContext oldcxt = CurrentMemoryContext; revmap = brinRevmapInitialize(idxRel, &pagesPerRange, NULL); @@ -163,14 +164,21 @@ brininsert(Relation idxRel, Datum *values, bool *nulls, if (!brtup) break; - /* First time through? */ + /* First time through in this statement? */ if (bdesc == NULL) { + MemoryContextSwitchTo(indexInfo->ii_Context); bdesc = brin_build_desc(idxRel); + indexInfo->ii_AmCache = (void *) bdesc; + MemoryContextSwitchTo(oldcxt); + } + /* First time through in this brininsert call? */ + if (tupcxt == NULL) + { tupcxt = AllocSetContextCreate(CurrentMemoryContext, "brininsert cxt", ALLOCSET_DEFAULT_SIZES); - oldcxt = MemoryContextSwitchTo(tupcxt); + MemoryContextSwitchTo(tupcxt); } dtup = brin_deform_tuple(bdesc, brtup); @@ -261,12 +269,9 @@ brininsert(Relation idxRel, Datum *values, bool *nulls, brinRevmapTerminate(revmap); if (BufferIsValid(buf)) ReleaseBuffer(buf); - if (bdesc != NULL) - { - brin_free_desc(bdesc); - MemoryContextSwitchTo(oldcxt); + MemoryContextSwitchTo(oldcxt); + if (tupcxt != NULL) MemoryContextDelete(tupcxt); - } return false; } diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c index 03a7235a0a..3d3b9e0840 100644 --- a/src/backend/access/gin/gininsert.c +++ b/src/backend/access/gin/gininsert.c @@ -482,39 +482,48 @@ ginHeapTupleInsert(GinState *ginstate, OffsetNumber attnum, bool gininsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, - IndexUniqueCheck checkUnique) + IndexUniqueCheck checkUnique, + IndexInfo *indexInfo) { - GinState ginstate; + GinState *ginstate = (GinState *) indexInfo->ii_AmCache; MemoryContext oldCtx; MemoryContext insertCtx; int i; + /* Initialize GinState cache if first call in this statement */ + if (ginstate == NULL) + { + oldCtx = MemoryContextSwitchTo(indexInfo->ii_Context); + ginstate = (GinState *) palloc(sizeof(GinState)); + initGinState(ginstate, index); + indexInfo->ii_AmCache = (void *) ginstate; + MemoryContextSwitchTo(oldCtx); + } + insertCtx = AllocSetContextCreate(CurrentMemoryContext, "Gin insert temporary context", ALLOCSET_DEFAULT_SIZES); oldCtx = MemoryContextSwitchTo(insertCtx); - initGinState(&ginstate, index); - if (GinGetUseFastUpdate(index)) { GinTupleCollector collector; memset(&collector, 0, sizeof(GinTupleCollector)); - for (i = 0; i < ginstate.origTupdesc->natts; i++) - ginHeapTupleFastCollect(&ginstate, &collector, + for (i = 0; i < ginstate->origTupdesc->natts; i++) + ginHeapTupleFastCollect(ginstate, &collector, (OffsetNumber) (i + 1), values[i], isnull[i], ht_ctid); - ginHeapTupleFastInsert(&ginstate, &collector); + ginHeapTupleFastInsert(ginstate, &collector); } else { - for (i = 0; i < ginstate.origTupdesc->natts; i++) - ginHeapTupleInsert(&ginstate, (OffsetNumber) (i + 1), + for (i = 0; i < ginstate->origTupdesc->natts; i++) + ginHeapTupleInsert(ginstate, (OffsetNumber) (i + 1), values[i], isnull[i], ht_ctid); } diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index c2247ad2f7..96ead531ea 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -18,6 +18,7 @@ #include "access/gistscan.h" #include "catalog/pg_collation.h" #include "miscadmin.h" +#include "nodes/execnodes.h" #include "utils/builtins.h" #include "utils/index_selfuncs.h" #include "utils/memutils.h" @@ -144,21 +145,23 @@ gistbuildempty(Relation index) bool gistinsert(Relation r, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, - IndexUniqueCheck checkUnique) + IndexUniqueCheck checkUnique, + IndexInfo *indexInfo) { + GISTSTATE *giststate = (GISTSTATE *) indexInfo->ii_AmCache; IndexTuple itup; - GISTSTATE *giststate; MemoryContext oldCxt; - giststate = initGISTstate(r); + /* Initialize GISTSTATE cache if first call in this statement */ + if (giststate == NULL) + { + oldCxt = MemoryContextSwitchTo(indexInfo->ii_Context); + giststate = initGISTstate(r); + giststate->tempCxt = createTempGistContext(); + indexInfo->ii_AmCache = (void *) giststate; + MemoryContextSwitchTo(oldCxt); + } - /* - * We use the giststate's scan context as temp context too. This means - * that any memory leaked by the support functions is not reclaimed until - * end of insert. In most cases, we aren't going to call the support - * functions very many times before finishing the insert, so this seems - * cheaper than resetting a temp context for each function call. - */ oldCxt = MemoryContextSwitchTo(giststate->tempCxt); itup = gistFormTuple(giststate, r, @@ -169,7 +172,7 @@ gistinsert(Relation r, Datum *values, bool *isnull, /* cleanup */ MemoryContextSwitchTo(oldCxt); - freeGISTstate(giststate); + MemoryContextReset(giststate->tempCxt); return false; } diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c index 97ad22aa6f..bca77a80c3 100644 --- a/src/backend/access/hash/hash.c +++ b/src/backend/access/hash/hash.c @@ -232,7 +232,8 @@ hashbuildCallback(Relation index, bool hashinsert(Relation rel, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, - IndexUniqueCheck checkUnique) + IndexUniqueCheck checkUnique, + IndexInfo *indexInfo) { Datum index_values[1]; bool index_isnull[1]; diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c index 496648c42f..19e7048002 100644 --- a/src/backend/access/heap/tuptoaster.c +++ b/src/backend/access/heap/tuptoaster.c @@ -1604,7 +1604,9 @@ toast_save_datum(Relation rel, Datum value, * Create the index entry. We cheat a little here by not using * FormIndexDatum: this relies on the knowledge that the index columns * are the same as the initial columns of the table for all the - * indexes. + * indexes. We also cheat by not providing an IndexInfo: this is okay + * for now because btree doesn't need one, but we might have to be + * more honest someday. * * Note also that there had better not be any user-created index on * the TOAST table, since we don't bother to update anything else. @@ -1617,7 +1619,8 @@ toast_save_datum(Relation rel, Datum value, &(toasttup->t_self), toastrel, toastidxs[i]->rd_index->indisunique ? - UNIQUE_CHECK_YES : UNIQUE_CHECK_NO); + UNIQUE_CHECK_YES : UNIQUE_CHECK_NO, + NULL); } /* diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c index ba27c1e86d..4e7eca73cc 100644 --- a/src/backend/access/index/indexam.c +++ b/src/backend/access/index/indexam.c @@ -196,7 +196,8 @@ index_insert(Relation indexRelation, bool *isnull, ItemPointer heap_t_ctid, Relation heapRelation, - IndexUniqueCheck checkUnique) + IndexUniqueCheck checkUnique, + IndexInfo *indexInfo) { RELATION_CHECKS; CHECK_REL_PROCEDURE(aminsert); @@ -208,7 +209,7 @@ index_insert(Relation indexRelation, return indexRelation->rd_amroutine->aminsert(indexRelation, values, isnull, heap_t_ctid, heapRelation, - checkUnique); + checkUnique, indexInfo); } /* diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index 469e7abe4d..945e563fcc 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -276,7 +276,8 @@ btbuildempty(Relation index) bool btinsert(Relation rel, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, - IndexUniqueCheck checkUnique) + IndexUniqueCheck checkUnique, + IndexInfo *indexInfo) { bool result; IndexTuple itup; diff --git a/src/backend/access/spgist/spginsert.c b/src/backend/access/spgist/spginsert.c index b42f4b7139..14f8a9ee8e 100644 --- a/src/backend/access/spgist/spginsert.c +++ b/src/backend/access/spgist/spginsert.c @@ -206,7 +206,8 @@ spgbuildempty(Relation index) bool spginsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, - IndexUniqueCheck checkUnique) + IndexUniqueCheck checkUnique, + IndexInfo *indexInfo) { SpGistState spgstate; MemoryContext oldCtx; diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 815a694cfc..f8d92145e8 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -1687,6 +1687,10 @@ BuildIndexInfo(Relation index) ii->ii_Concurrent = false; ii->ii_BrokenHotChain = false; + /* set up for possible use by index AM */ + ii->ii_AmCache = NULL; + ii->ii_Context = CurrentMemoryContext; + return ii; } @@ -3158,7 +3162,8 @@ validate_index_heapscan(Relation heapRelation, &rootTuple, heapRelation, indexInfo->ii_Unique ? - UNIQUE_CHECK_YES : UNIQUE_CHECK_NO); + UNIQUE_CHECK_YES : UNIQUE_CHECK_NO, + indexInfo); state->tups_inserted += 1; } diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c index 76268e1d2a..abc344ad69 100644 --- a/src/backend/catalog/indexing.c +++ b/src/backend/catalog/indexing.c @@ -139,7 +139,8 @@ CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple) &(heapTuple->t_self), /* tid of heap tuple */ heapRelation, relationDescs[i]->rd_index->indisunique ? - UNIQUE_CHECK_YES : UNIQUE_CHECK_NO); + UNIQUE_CHECK_YES : UNIQUE_CHECK_NO, + indexInfo); } ExecDropSingleTupleTableSlot(slot); diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c index e5f773d51d..0e4231668d 100644 --- a/src/backend/catalog/toasting.c +++ b/src/backend/catalog/toasting.c @@ -315,6 +315,8 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, indexInfo->ii_ReadyForInserts = true; indexInfo->ii_Concurrent = false; indexInfo->ii_BrokenHotChain = false; + indexInfo->ii_AmCache = NULL; + indexInfo->ii_Context = CurrentMemoryContext; collationObjectId[0] = InvalidOid; collationObjectId[1] = InvalidOid; diff --git a/src/backend/commands/constraint.c b/src/backend/commands/constraint.c index e9eeacd03a..e2544e51ed 100644 --- a/src/backend/commands/constraint.c +++ b/src/backend/commands/constraint.c @@ -165,7 +165,8 @@ unique_key_recheck(PG_FUNCTION_ARGS) * index will know about. */ index_insert(indexRel, values, isnull, &(new_row->t_self), - trigdata->tg_relation, UNIQUE_CHECK_EXISTING); + trigdata->tg_relation, UNIQUE_CHECK_EXISTING, + indexInfo); } else { diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index f4814c095b..265e9b33f7 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -183,6 +183,8 @@ CheckIndexCompatible(Oid oldId, indexInfo->ii_ExclusionOps = NULL; indexInfo->ii_ExclusionProcs = NULL; indexInfo->ii_ExclusionStrats = NULL; + indexInfo->ii_AmCache = NULL; + indexInfo->ii_Context = CurrentMemoryContext; typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid)); collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid)); classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid)); @@ -562,6 +564,8 @@ DefineIndex(Oid relationId, indexInfo->ii_ReadyForInserts = !stmt->concurrent; indexInfo->ii_Concurrent = stmt->concurrent; indexInfo->ii_BrokenHotChain = false; + indexInfo->ii_AmCache = NULL; + indexInfo->ii_Context = CurrentMemoryContext; typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid)); collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid)); diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c index 8d119f6a19..5242dee006 100644 --- a/src/backend/executor/execIndexing.c +++ b/src/backend/executor/execIndexing.c @@ -391,7 +391,8 @@ ExecInsertIndexTuples(TupleTableSlot *slot, isnull, /* null flags */ tupleid, /* tid of heap tuple */ heapRelation, /* heap relation */ - checkUnique); /* type of uniqueness check to do */ + checkUnique, /* type of uniqueness check to do */ + indexInfo); /* index AM may need this */ /* * If the index has an associated exclusion constraint, check that. diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h index e91e41dc0f..b0730bfefa 100644 --- a/src/include/access/amapi.h +++ b/src/include/access/amapi.h @@ -72,7 +72,8 @@ typedef bool (*aminsert_function) (Relation indexRelation, bool *isnull, ItemPointer heap_tid, Relation heapRelation, - IndexUniqueCheck checkUnique); + IndexUniqueCheck checkUnique, + struct IndexInfo *indexInfo); /* bulk delete */ typedef IndexBulkDeleteResult *(*ambulkdelete_function) (IndexVacuumInfo *info, diff --git a/src/include/access/brin_internal.h b/src/include/access/brin_internal.h index 40312604f8..abe887788b 100644 --- a/src/include/access/brin_internal.h +++ b/src/include/access/brin_internal.h @@ -89,7 +89,8 @@ extern IndexBuildResult *brinbuild(Relation heap, Relation index, extern void brinbuildempty(Relation index); extern bool brininsert(Relation idxRel, Datum *values, bool *nulls, ItemPointer heaptid, Relation heapRel, - IndexUniqueCheck checkUnique); + IndexUniqueCheck checkUnique, + struct IndexInfo *indexInfo); extern IndexScanDesc brinbeginscan(Relation r, int nkeys, int norderbys); extern int64 bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm); extern void brinrescan(IndexScanDesc scan, ScanKey scankey, int nscankeys, diff --git a/src/include/access/genam.h b/src/include/access/genam.h index 51466b96e8..f467b18a9c 100644 --- a/src/include/access/genam.h +++ b/src/include/access/genam.h @@ -21,6 +21,9 @@ #include "utils/relcache.h" #include "utils/snapshot.h" +/* We don't want this file to depend on execnodes.h. */ +struct IndexInfo; + /* * Struct for statistics returned by ambuild */ @@ -131,7 +134,8 @@ extern bool index_insert(Relation indexRelation, Datum *values, bool *isnull, ItemPointer heap_t_ctid, Relation heapRelation, - IndexUniqueCheck checkUnique); + IndexUniqueCheck checkUnique, + struct IndexInfo *indexInfo); extern IndexScanDesc index_beginscan(Relation heapRelation, Relation indexRelation, diff --git a/src/include/access/gin_private.h b/src/include/access/gin_private.h index d46274ee85..7e1557ea85 100644 --- a/src/include/access/gin_private.h +++ b/src/include/access/gin_private.h @@ -617,7 +617,8 @@ extern IndexBuildResult *ginbuild(Relation heap, Relation index, extern void ginbuildempty(Relation index); extern bool gininsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, - IndexUniqueCheck checkUnique); + IndexUniqueCheck checkUnique, + struct IndexInfo *indexInfo); extern void ginEntryInsert(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h index f4beeb9209..873c52a1a2 100644 --- a/src/include/access/gist_private.h +++ b/src/include/access/gist_private.h @@ -426,7 +426,8 @@ typedef struct GiSTOptions extern void gistbuildempty(Relation index); extern bool gistinsert(Relation r, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, - IndexUniqueCheck checkUnique); + IndexUniqueCheck checkUnique, + struct IndexInfo *indexInfo); extern MemoryContext createTempGistContext(void); extern GISTSTATE *initGISTstate(Relation index); extern void freeGISTstate(GISTSTATE *giststate); diff --git a/src/include/access/hash.h b/src/include/access/hash.h index c0455851f4..3bf587b1b7 100644 --- a/src/include/access/hash.h +++ b/src/include/access/hash.h @@ -277,7 +277,8 @@ extern IndexBuildResult *hashbuild(Relation heap, Relation index, extern void hashbuildempty(Relation index); extern bool hashinsert(Relation rel, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, - IndexUniqueCheck checkUnique); + IndexUniqueCheck checkUnique, + struct IndexInfo *indexInfo); extern bool hashgettuple(IndexScanDesc scan, ScanDirection dir); extern int64 hashgetbitmap(IndexScanDesc scan, TIDBitmap *tbm); extern IndexScanDesc hashbeginscan(Relation rel, int nkeys, int norderbys); diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h index b2517623aa..344ef9933c 100644 --- a/src/include/access/nbtree.h +++ b/src/include/access/nbtree.h @@ -659,7 +659,8 @@ extern IndexBuildResult *btbuild(Relation heap, Relation index, extern void btbuildempty(Relation index); extern bool btinsert(Relation rel, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, - IndexUniqueCheck checkUnique); + IndexUniqueCheck checkUnique, + struct IndexInfo *indexInfo); extern IndexScanDesc btbeginscan(Relation rel, int nkeys, int norderbys); extern bool btgettuple(IndexScanDesc scan, ScanDirection dir); extern int64 btgetbitmap(IndexScanDesc scan, TIDBitmap *tbm); diff --git a/src/include/access/spgist.h b/src/include/access/spgist.h index 6f59c0bbc5..ee7480ad39 100644 --- a/src/include/access/spgist.h +++ b/src/include/access/spgist.h @@ -191,7 +191,8 @@ extern IndexBuildResult *spgbuild(Relation heap, Relation index, extern void spgbuildempty(Relation index); extern bool spginsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, - IndexUniqueCheck checkUnique); + IndexUniqueCheck checkUnique, + struct IndexInfo *indexInfo); /* spgscan.c */ extern IndexScanDesc spgbeginscan(Relation rel, int keysz, int orderbysz); diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index f9bcdd63de..42c6c58ff9 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -52,6 +52,8 @@ * ReadyForInserts is it valid for inserts? * Concurrent are we doing a concurrent index build? * BrokenHotChain did we detect any broken HOT chains? + * AmCache private cache area for index AM + * Context memory context holding this IndexInfo * * ii_Concurrent and ii_BrokenHotChain are used only during index build; * they're conventionally set to false otherwise. @@ -76,6 +78,8 @@ typedef struct IndexInfo bool ii_ReadyForInserts; bool ii_Concurrent; bool ii_BrokenHotChain; + void *ii_AmCache; + MemoryContext ii_Context; } IndexInfo; /* ----------------