[HACKERS] Caching index AM working data across aminsert calls
От | Tom Lane |
---|---|
Тема | [HACKERS] Caching index AM working data across aminsert calls |
Дата | |
Msg-id | 27568.1486508680@sss.pgh.pa.us обсуждение исходный текст |
Ответы |
Re: [HACKERS] Caching index AM working data across aminsert calls
(Robert Haas <robertmhaas@gmail.com>)
|
Список | pgsql-hackers |
It's always been possible for index AMs to cache data across successive amgettuple calls within a single SQL command: the IndexScanDesc.opaque field is meant for precisely that. However, no comparable facility exists for amortizing setup work across successive aminsert calls. The attached proposed patch adds such a feature and teaches gin, gist, and brin to use it. (The other standard index AMs keep everything they need in the relcache, so there's little to improve there.) The improvement I see from this is fairly modest in a normal build. In an example similar to the gin regression test's main insert query, insert into gin_test_tbl select array[1, 2, g] from generate_series(1, 1000000) g; the overall insertion speed increases perhaps 10%, which is nice but not great. gist and brin are less, maybe 5% or so. However, because most of what happens in the saved work is catalog lookups, the savings in a CLOBBER_CACHE_ALWAYS test build are pretty substantial: the runtime of the gin regression script, on my workstation, goes from 40 minutes to 4 seconds. (Yes, really.) The gist and brin test scripts are less insert-heavy but still lose several minutes apiece. Since the core regression tests are run multiple times (twice serially and once in parallel) in the standard buildfarm cycle, I estimate that this patch would cut over 1.5 hours from the cycle time for a CLOBBER_CACHE_ALWAYS critter running on hardware similar to mine. I think that alone makes it worth doing. The reason this has been hard up to now is that the aminsert function is not passed any useful place to cache per-statement data. What I chose to do in the attached is to add suitable fields to struct IndexInfo and pass that to aminsert. That's not widening the index AM API very much because IndexInfo is already within the ken of ambuild. I figured that this might be a particularly useful way to do it because it means that aminsert also has access to the other data in the IndexInfo struct, which might save it having to recompute some things. And it makes the DDL info available to ambuild and aminsert more similar, which seems good on general principles. I also looked into the idea of using the index relcache entry's rd_amcache field for this purpose, but that fails immediately in a CLOBBER_CACHE_ALWAYS build, because gininsert (at least, probably the other ones too) is not robust against its GinState disappearing from under it mid-insert. Since rd_amcache goes away on a cache flush even if the index is open, that doesn't work. We could maybe fix that by introducing some way for AMs to control the lifetime of rd_amcache, but it would result in a substantially more complex and invasive patch than this one, and I'm unconvinced that it'd be worth the trouble. Thoughts, objections? regards, tom lane diff --git a/contrib/bloom/blinsert.c b/contrib/bloom/blinsert.c index 29bc5ce..913f1f8 100644 *** a/contrib/bloom/blinsert.c --- b/contrib/bloom/blinsert.c *************** blbuildempty(Relation index) *** 190,196 **** */ bool blinsert(Relation index, Datum *values, bool *isnull, ! ItemPointer ht_ctid, Relation heapRel, IndexUniqueCheck checkUnique) { BloomState blstate; BloomTuple *itup; --- 190,198 ---- */ bool blinsert(Relation index, Datum *values, bool *isnull, ! 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 a75a235..39d8d05 100644 *** a/contrib/bloom/bloom.h --- b/contrib/bloom/bloom.h *************** extern bool blvalidate(Oid opclassoid); *** 189,195 **** /* index access method interface functions */ extern bool blinsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, ! IndexUniqueCheck checkUnique); 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, --- 189,196 ---- /* index access method interface functions */ extern bool blinsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, ! 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 5d8e557..9afd7f6 100644 *** a/doc/src/sgml/indexam.sgml --- b/doc/src/sgml/indexam.sgml *************** aminsert (Relation indexRelation, *** 259,265 **** bool *isnull, ItemPointer heap_tid, Relation heapRelation, ! IndexUniqueCheck checkUnique); </programlisting> Insert a new tuple into an existing index. The <literal>values</> and <literal>isnull</> arrays give the key values to be indexed, and --- 259,266 ---- bool *isnull, ItemPointer heap_tid, Relation heapRelation, ! IndexUniqueCheck checkUnique, ! IndexInfo *indexInfo); </programlisting> Insert a new tuple into an existing index. The <literal>values</> and <literal>isnull</> arrays give the key values to be indexed, and *************** aminsert (Relation indexRelation, *** 288,293 **** --- 289,302 ---- </para> <para> + If the index AM wishes to cache data across successive index insertions + within a SQL statement, it can allocate space + in <literal>indexInfo->ii_Context</literal> and store a pointer to the + data in <literal>indexInfo->ii_AmCache</literal> (which will be NULL + initially). + </para> + + <para> <programlisting> IndexBulkDeleteResult * ambulkdelete (IndexVacuumInfo *info, diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index b2afdb7..4ff046b 100644 *** a/src/backend/access/brin/brin.c --- b/src/backend/access/brin/brin.c *************** brinhandler(PG_FUNCTION_ARGS) *** 131,144 **** bool brininsert(Relation idxRel, Datum *values, bool *nulls, ItemPointer heaptid, Relation heapRel, ! IndexUniqueCheck checkUnique) { BlockNumber pagesPerRange; ! BrinDesc *bdesc = NULL; BrinRevmap *revmap; Buffer buf = InvalidBuffer; MemoryContext tupcxt = NULL; ! MemoryContext oldcxt = NULL; revmap = brinRevmapInitialize(idxRel, &pagesPerRange, NULL); --- 131,145 ---- bool brininsert(Relation idxRel, Datum *values, bool *nulls, ItemPointer heaptid, Relation heapRel, ! IndexUniqueCheck checkUnique, ! IndexInfo *indexInfo) { BlockNumber pagesPerRange; ! BrinDesc *bdesc = (BrinDesc *) indexInfo->ii_AmCache; BrinRevmap *revmap; Buffer buf = InvalidBuffer; MemoryContext tupcxt = NULL; ! MemoryContext oldcxt = CurrentMemoryContext; revmap = brinRevmapInitialize(idxRel, &pagesPerRange, NULL); *************** brininsert(Relation idxRel, Datum *value *** 163,176 **** if (!brtup) break; ! /* First time through? */ if (bdesc == NULL) { bdesc = brin_build_desc(idxRel); tupcxt = AllocSetContextCreate(CurrentMemoryContext, "brininsert cxt", ALLOCSET_DEFAULT_SIZES); ! oldcxt = MemoryContextSwitchTo(tupcxt); } dtup = brin_deform_tuple(bdesc, brtup); --- 164,184 ---- if (!brtup) break; ! /* 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); ! MemoryContextSwitchTo(tupcxt); } dtup = brin_deform_tuple(bdesc, brtup); *************** brininsert(Relation idxRel, Datum *value *** 261,272 **** brinRevmapTerminate(revmap); if (BufferIsValid(buf)) ReleaseBuffer(buf); ! if (bdesc != NULL) ! { ! brin_free_desc(bdesc); ! MemoryContextSwitchTo(oldcxt); MemoryContextDelete(tupcxt); - } return false; } --- 269,277 ---- brinRevmapTerminate(revmap); if (BufferIsValid(buf)) ReleaseBuffer(buf); ! 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 03a7235..3d3b9e0 100644 *** a/src/backend/access/gin/gininsert.c --- b/src/backend/access/gin/gininsert.c *************** ginHeapTupleInsert(GinState *ginstate, O *** 482,520 **** bool gininsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, ! IndexUniqueCheck checkUnique) { ! GinState ginstate; MemoryContext oldCtx; MemoryContext insertCtx; int i; 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, (OffsetNumber) (i + 1), values[i], isnull[i], ht_ctid); ! ginHeapTupleFastInsert(&ginstate, &collector); } else { ! for (i = 0; i < ginstate.origTupdesc->natts; i++) ! ginHeapTupleInsert(&ginstate, (OffsetNumber) (i + 1), values[i], isnull[i], ht_ctid); } --- 482,529 ---- bool gininsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, ! IndexUniqueCheck checkUnique, ! IndexInfo *indexInfo) { ! 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); if (GinGetUseFastUpdate(index)) { GinTupleCollector collector; memset(&collector, 0, sizeof(GinTupleCollector)); ! for (i = 0; i < ginstate->origTupdesc->natts; i++) ! ginHeapTupleFastCollect(ginstate, &collector, (OffsetNumber) (i + 1), values[i], isnull[i], ht_ctid); ! ginHeapTupleFastInsert(ginstate, &collector); } else { ! 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 c2247ad..96ead53 100644 *** a/src/backend/access/gist/gist.c --- b/src/backend/access/gist/gist.c *************** *** 18,23 **** --- 18,24 ---- #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" *************** gistbuildempty(Relation index) *** 144,164 **** bool gistinsert(Relation r, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, ! IndexUniqueCheck checkUnique) { IndexTuple itup; - GISTSTATE *giststate; MemoryContext oldCxt; ! giststate = initGISTstate(r); - /* - * 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, --- 145,167 ---- bool gistinsert(Relation r, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, ! IndexUniqueCheck checkUnique, ! IndexInfo *indexInfo) { + GISTSTATE *giststate = (GISTSTATE *) indexInfo->ii_AmCache; IndexTuple itup; MemoryContext oldCxt; ! /* 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); ! } oldCxt = MemoryContextSwitchTo(giststate->tempCxt); itup = gistFormTuple(giststate, r, *************** gistinsert(Relation r, Datum *values, bo *** 169,175 **** /* cleanup */ MemoryContextSwitchTo(oldCxt); ! freeGISTstate(giststate); return false; } --- 172,178 ---- /* cleanup */ MemoryContextSwitchTo(oldCxt); ! MemoryContextReset(giststate->tempCxt); return false; } diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c index 97ad22a..bca77a8 100644 *** a/src/backend/access/hash/hash.c --- b/src/backend/access/hash/hash.c *************** hashbuildCallback(Relation index, *** 232,238 **** bool hashinsert(Relation rel, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, ! IndexUniqueCheck checkUnique) { Datum index_values[1]; bool index_isnull[1]; --- 232,239 ---- bool hashinsert(Relation rel, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, ! 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 496648c..19e7048 100644 *** a/src/backend/access/heap/tuptoaster.c --- b/src/backend/access/heap/tuptoaster.c *************** toast_save_datum(Relation rel, Datum val *** 1604,1610 **** * 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. * * 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. --- 1604,1612 ---- * 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. 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. *************** toast_save_datum(Relation rel, Datum val *** 1617,1623 **** &(toasttup->t_self), toastrel, toastidxs[i]->rd_index->indisunique ? ! UNIQUE_CHECK_YES : UNIQUE_CHECK_NO); } /* --- 1619,1626 ---- &(toasttup->t_self), toastrel, toastidxs[i]->rd_index->indisunique ? ! UNIQUE_CHECK_YES : UNIQUE_CHECK_NO, ! NULL); } /* diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c index ba27c1e..4e7eca7 100644 *** a/src/backend/access/index/indexam.c --- b/src/backend/access/index/indexam.c *************** index_insert(Relation indexRelation, *** 196,202 **** bool *isnull, ItemPointer heap_t_ctid, Relation heapRelation, ! IndexUniqueCheck checkUnique) { RELATION_CHECKS; CHECK_REL_PROCEDURE(aminsert); --- 196,203 ---- bool *isnull, ItemPointer heap_t_ctid, Relation heapRelation, ! IndexUniqueCheck checkUnique, ! IndexInfo *indexInfo) { RELATION_CHECKS; CHECK_REL_PROCEDURE(aminsert); *************** index_insert(Relation indexRelation, *** 208,214 **** return indexRelation->rd_amroutine->aminsert(indexRelation, values, isnull, heap_t_ctid, heapRelation, ! checkUnique); } /* --- 209,215 ---- return indexRelation->rd_amroutine->aminsert(indexRelation, values, isnull, heap_t_ctid, heapRelation, ! checkUnique, indexInfo); } /* diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index 469e7ab..945e563 100644 *** a/src/backend/access/nbtree/nbtree.c --- b/src/backend/access/nbtree/nbtree.c *************** btbuildempty(Relation index) *** 276,282 **** bool btinsert(Relation rel, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, ! IndexUniqueCheck checkUnique) { bool result; IndexTuple itup; --- 276,283 ---- bool btinsert(Relation rel, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, ! 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 b42f4b7..14f8a9e 100644 *** a/src/backend/access/spgist/spginsert.c --- b/src/backend/access/spgist/spginsert.c *************** spgbuildempty(Relation index) *** 206,212 **** bool spginsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, ! IndexUniqueCheck checkUnique) { SpGistState spgstate; MemoryContext oldCtx; --- 206,213 ---- bool spginsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, ! IndexUniqueCheck checkUnique, ! IndexInfo *indexInfo) { SpGistState spgstate; MemoryContext oldCtx; diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 815a694..f8d9214 100644 *** a/src/backend/catalog/index.c --- b/src/backend/catalog/index.c *************** BuildIndexInfo(Relation index) *** 1687,1692 **** --- 1687,1696 ---- 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; } *************** validate_index_heapscan(Relation heapRel *** 3158,3164 **** &rootTuple, heapRelation, indexInfo->ii_Unique ? ! UNIQUE_CHECK_YES : UNIQUE_CHECK_NO); state->tups_inserted += 1; } --- 3162,3169 ---- &rootTuple, heapRelation, indexInfo->ii_Unique ? ! 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 76268e1..abc344a 100644 *** a/src/backend/catalog/indexing.c --- b/src/backend/catalog/indexing.c *************** CatalogIndexInsert(CatalogIndexState ind *** 139,145 **** &(heapTuple->t_self), /* tid of heap tuple */ heapRelation, relationDescs[i]->rd_index->indisunique ? ! UNIQUE_CHECK_YES : UNIQUE_CHECK_NO); } ExecDropSingleTupleTableSlot(slot); --- 139,146 ---- &(heapTuple->t_self), /* tid of heap tuple */ heapRelation, relationDescs[i]->rd_index->indisunique ? ! UNIQUE_CHECK_YES : UNIQUE_CHECK_NO, ! indexInfo); } ExecDropSingleTupleTableSlot(slot); diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c index e5f773d..0e42316 100644 *** a/src/backend/catalog/toasting.c --- b/src/backend/catalog/toasting.c *************** create_toast_table(Relation rel, Oid toa *** 315,320 **** --- 315,322 ---- 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 e9eeacd..e2544e5 100644 *** a/src/backend/commands/constraint.c --- b/src/backend/commands/constraint.c *************** unique_key_recheck(PG_FUNCTION_ARGS) *** 165,171 **** * index will know about. */ index_insert(indexRel, values, isnull, &(new_row->t_self), ! trigdata->tg_relation, UNIQUE_CHECK_EXISTING); } else { --- 165,172 ---- * index will know about. */ index_insert(indexRel, values, isnull, &(new_row->t_self), ! trigdata->tg_relation, UNIQUE_CHECK_EXISTING, ! indexInfo); } else { diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index f4814c0..265e9b3 100644 *** a/src/backend/commands/indexcmds.c --- b/src/backend/commands/indexcmds.c *************** CheckIndexCompatible(Oid oldId, *** 183,188 **** --- 183,190 ---- 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)); *************** DefineIndex(Oid relationId, *** 562,567 **** --- 564,571 ---- 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 8d119f6..5242dee 100644 *** a/src/backend/executor/execIndexing.c --- b/src/backend/executor/execIndexing.c *************** ExecInsertIndexTuples(TupleTableSlot *sl *** 391,397 **** isnull, /* null flags */ tupleid, /* tid of heap tuple */ heapRelation, /* heap relation */ ! checkUnique); /* type of uniqueness check to do */ /* * If the index has an associated exclusion constraint, check that. --- 391,398 ---- isnull, /* null flags */ tupleid, /* tid of heap tuple */ heapRelation, /* heap relation */ ! 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 e91e41d..b0730bf 100644 *** a/src/include/access/amapi.h --- b/src/include/access/amapi.h *************** typedef bool (*aminsert_function) (Relat *** 72,78 **** bool *isnull, ItemPointer heap_tid, Relation heapRelation, ! IndexUniqueCheck checkUnique); /* bulk delete */ typedef IndexBulkDeleteResult *(*ambulkdelete_function) (IndexVacuumInfo *info, --- 72,79 ---- bool *isnull, ItemPointer heap_tid, Relation heapRelation, ! 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 4031260..abe8877 100644 *** a/src/include/access/brin_internal.h --- b/src/include/access/brin_internal.h *************** extern IndexBuildResult *brinbuild(Relat *** 89,95 **** extern void brinbuildempty(Relation index); extern bool brininsert(Relation idxRel, Datum *values, bool *nulls, ItemPointer heaptid, Relation heapRel, ! IndexUniqueCheck checkUnique); 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, --- 89,96 ---- extern void brinbuildempty(Relation index); extern bool brininsert(Relation idxRel, Datum *values, bool *nulls, ItemPointer heaptid, Relation heapRel, ! 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 51466b9..f467b18 100644 *** a/src/include/access/genam.h --- b/src/include/access/genam.h *************** *** 21,26 **** --- 21,29 ---- #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 */ *************** extern bool index_insert(Relation indexR *** 131,137 **** Datum *values, bool *isnull, ItemPointer heap_t_ctid, Relation heapRelation, ! IndexUniqueCheck checkUnique); extern IndexScanDesc index_beginscan(Relation heapRelation, Relation indexRelation, --- 134,141 ---- Datum *values, bool *isnull, ItemPointer heap_t_ctid, Relation heapRelation, ! 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 d46274e..7e1557e 100644 *** a/src/include/access/gin_private.h --- b/src/include/access/gin_private.h *************** extern IndexBuildResult *ginbuild(Relati *** 617,623 **** extern void ginbuildempty(Relation index); extern bool gininsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, ! IndexUniqueCheck checkUnique); extern void ginEntryInsert(GinState *ginstate, OffsetNumber attnum, Datum key, GinNullCategory category, ItemPointerData *items, uint32 nitem, --- 617,624 ---- extern void ginbuildempty(Relation index); extern bool gininsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, ! 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 60a770a..a4d3e7c 100644 *** a/src/include/access/gist_private.h --- b/src/include/access/gist_private.h *************** typedef struct GiSTOptions *** 426,432 **** extern void gistbuildempty(Relation index); extern bool gistinsert(Relation r, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, ! IndexUniqueCheck checkUnique); extern MemoryContext createTempGistContext(void); extern GISTSTATE *initGISTstate(Relation index); extern void freeGISTstate(GISTSTATE *giststate); --- 426,433 ---- extern void gistbuildempty(Relation index); extern bool gistinsert(Relation r, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, ! 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 c045585..3bf587b 100644 *** a/src/include/access/hash.h --- b/src/include/access/hash.h *************** extern IndexBuildResult *hashbuild(Relat *** 277,283 **** extern void hashbuildempty(Relation index); extern bool hashinsert(Relation rel, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, ! IndexUniqueCheck checkUnique); extern bool hashgettuple(IndexScanDesc scan, ScanDirection dir); extern int64 hashgetbitmap(IndexScanDesc scan, TIDBitmap *tbm); extern IndexScanDesc hashbeginscan(Relation rel, int nkeys, int norderbys); --- 277,284 ---- extern void hashbuildempty(Relation index); extern bool hashinsert(Relation rel, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, ! 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 011a72e..70ff3aa 100644 *** a/src/include/access/nbtree.h --- b/src/include/access/nbtree.h *************** extern IndexBuildResult *btbuild(Relatio *** 659,665 **** extern void btbuildempty(Relation index); extern bool btinsert(Relation rel, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, ! IndexUniqueCheck checkUnique); extern IndexScanDesc btbeginscan(Relation rel, int nkeys, int norderbys); extern bool btgettuple(IndexScanDesc scan, ScanDirection dir); extern int64 btgetbitmap(IndexScanDesc scan, TIDBitmap *tbm); --- 659,666 ---- extern void btbuildempty(Relation index); extern bool btinsert(Relation rel, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, ! 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 aaf78bc..c69af63 100644 *** a/src/include/access/spgist.h --- b/src/include/access/spgist.h *************** extern IndexBuildResult *spgbuild(Relati *** 191,197 **** extern void spgbuildempty(Relation index); extern bool spginsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, ! IndexUniqueCheck checkUnique); /* spgscan.c */ extern IndexScanDesc spgbeginscan(Relation rel, int keysz, int orderbysz); --- 191,198 ---- extern void spgbuildempty(Relation index); extern bool spginsert(Relation index, Datum *values, bool *isnull, ItemPointer ht_ctid, Relation heapRel, ! 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 f9bcdd6..42c6c58 100644 *** a/src/include/nodes/execnodes.h --- b/src/include/nodes/execnodes.h *************** *** 52,57 **** --- 52,59 ---- * 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. *************** typedef struct IndexInfo *** 76,81 **** --- 78,85 ---- bool ii_ReadyForInserts; bool ii_Concurrent; bool ii_BrokenHotChain; + void *ii_AmCache; + MemoryContext ii_Context; } IndexInfo; /* ---------------- -- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers
В списке pgsql-hackers по дате отправления:
Предыдущее
От: "Jonathan S. Katz"Дата:
Сообщение: Re: [HACKERS] Press Release Draft - 2016-02-09 Cumulative Update
Следующее
От: Alvaro HerreraДата:
Сообщение: Re: [HACKERS] Press Release Draft - 2016-02-09 Cumulative Update