diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/access/brin/brin.c | 1 | ||||
-rw-r--r-- | src/backend/access/gin/ginutil.c | 1 | ||||
-rw-r--r-- | src/backend/access/gist/gist.c | 1 | ||||
-rw-r--r-- | src/backend/access/hash/hash.c | 1 | ||||
-rw-r--r-- | src/backend/access/heap/heapam.c | 48 | ||||
-rw-r--r-- | src/backend/access/heap/heapam_handler.c | 19 | ||||
-rw-r--r-- | src/backend/access/nbtree/nbtree.c | 1 | ||||
-rw-r--r-- | src/backend/access/spgist/spgutils.c | 1 | ||||
-rw-r--r-- | src/backend/access/table/tableam.c | 2 | ||||
-rw-r--r-- | src/backend/catalog/index.c | 9 | ||||
-rw-r--r-- | src/backend/catalog/indexing.c | 35 | ||||
-rw-r--r-- | src/backend/commands/copyfrom.c | 5 | ||||
-rw-r--r-- | src/backend/commands/indexcmds.c | 10 | ||||
-rw-r--r-- | src/backend/executor/execIndexing.c | 37 | ||||
-rw-r--r-- | src/backend/executor/execReplication.c | 9 | ||||
-rw-r--r-- | src/backend/executor/nodeModifyTable.c | 13 | ||||
-rw-r--r-- | src/backend/nodes/makefuncs.c | 7 | ||||
-rw-r--r-- | src/backend/utils/cache/relcache.c | 70 |
18 files changed, 204 insertions, 66 deletions
diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index b5a5fa7b334..53e4721a54e 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -109,6 +109,7 @@ brinhandler(PG_FUNCTION_ARGS) amroutine->amcanparallel = false; amroutine->amcaninclude = false; amroutine->amusemaintenanceworkmem = false; + amroutine->amsummarizing = true; amroutine->amparallelvacuumoptions = VACUUM_OPTION_PARALLEL_CLEANUP; amroutine->amkeytype = InvalidOid; diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c index f05128ecf50..03fec1704e9 100644 --- a/src/backend/access/gin/ginutil.c +++ b/src/backend/access/gin/ginutil.c @@ -56,6 +56,7 @@ ginhandler(PG_FUNCTION_ARGS) amroutine->amcanparallel = false; amroutine->amcaninclude = false; amroutine->amusemaintenanceworkmem = true; + amroutine->amsummarizing = false; amroutine->amparallelvacuumoptions = VACUUM_OPTION_PARALLEL_BULKDEL | VACUUM_OPTION_PARALLEL_CLEANUP; amroutine->amkeytype = InvalidOid; diff --git a/src/backend/access/gist/gist.c b/src/backend/access/gist/gist.c index ba394f08f61..ea72bcce1bc 100644 --- a/src/backend/access/gist/gist.c +++ b/src/backend/access/gist/gist.c @@ -78,6 +78,7 @@ gisthandler(PG_FUNCTION_ARGS) amroutine->amcanparallel = false; amroutine->amcaninclude = true; amroutine->amusemaintenanceworkmem = false; + amroutine->amsummarizing = false; amroutine->amparallelvacuumoptions = VACUUM_OPTION_PARALLEL_BULKDEL | VACUUM_OPTION_PARALLEL_COND_CLEANUP; amroutine->amkeytype = InvalidOid; diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c index eb258337d69..fc5d97f606e 100644 --- a/src/backend/access/hash/hash.c +++ b/src/backend/access/hash/hash.c @@ -75,6 +75,7 @@ hashhandler(PG_FUNCTION_ARGS) amroutine->amcanparallel = false; amroutine->amcaninclude = false; amroutine->amusemaintenanceworkmem = false; + amroutine->amsummarizing = false; amroutine->amparallelvacuumoptions = VACUUM_OPTION_PARALLEL_BULKDEL; amroutine->amkeytype = INT4OID; diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 4f50e0dd347..cf4b917eb4b 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -2924,11 +2924,13 @@ simple_heap_delete(Relation relation, ItemPointer tid) TM_Result heap_update(Relation relation, ItemPointer otid, HeapTuple newtup, CommandId cid, Snapshot crosscheck, bool wait, - TM_FailureData *tmfd, LockTupleMode *lockmode) + TM_FailureData *tmfd, LockTupleMode *lockmode, + TU_UpdateIndexes *update_indexes) { TM_Result result; TransactionId xid = GetCurrentTransactionId(); Bitmapset *hot_attrs; + Bitmapset *sum_attrs; Bitmapset *key_attrs; Bitmapset *id_attrs; Bitmapset *interesting_attrs; @@ -2951,6 +2953,7 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup, bool have_tuple_lock = false; bool iscombo; bool use_hot_update = false; + bool summarized_update = false; bool key_intact; bool all_visible_cleared = false; bool all_visible_cleared_new = false; @@ -2996,12 +2999,16 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup, * Note that we get copies of each bitmap, so we need not worry about * relcache flush happening midway through. */ - hot_attrs = RelationGetIndexAttrBitmap(relation, INDEX_ATTR_BITMAP_ALL); + hot_attrs = RelationGetIndexAttrBitmap(relation, + INDEX_ATTR_BITMAP_HOT_BLOCKING); + sum_attrs = RelationGetIndexAttrBitmap(relation, + INDEX_ATTR_BITMAP_SUMMARIZED); key_attrs = RelationGetIndexAttrBitmap(relation, INDEX_ATTR_BITMAP_KEY); id_attrs = RelationGetIndexAttrBitmap(relation, INDEX_ATTR_BITMAP_IDENTITY_KEY); interesting_attrs = NULL; interesting_attrs = bms_add_members(interesting_attrs, hot_attrs); + interesting_attrs = bms_add_members(interesting_attrs, sum_attrs); interesting_attrs = bms_add_members(interesting_attrs, key_attrs); interesting_attrs = bms_add_members(interesting_attrs, id_attrs); @@ -3311,7 +3318,10 @@ l2: UnlockTupleTuplock(relation, &(oldtup.t_self), *lockmode); if (vmbuffer != InvalidBuffer) ReleaseBuffer(vmbuffer); + *update_indexes = TU_None; + bms_free(hot_attrs); + bms_free(sum_attrs); bms_free(key_attrs); bms_free(id_attrs); bms_free(modified_attrs); @@ -3633,7 +3643,19 @@ l2: * changed. */ if (!bms_overlap(modified_attrs, hot_attrs)) + { use_hot_update = true; + + /* + * If none of the columns that are used in hot-blocking indexes + * were updated, we can apply HOT, but we do still need to check + * if we need to update the summarizing indexes, and update those + * indexes if the columns were updated, or we may fail to detect + * e.g. value bound changes in BRIN minmax indexes. + */ + if (bms_overlap(modified_attrs, sum_attrs)) + summarized_update = true; + } } else { @@ -3793,10 +3815,27 @@ l2: heap_freetuple(heaptup); } + /* + * If it is a HOT update, the update may still need to update summarized + * indexes, lest we fail to update those summaries and get incorrect + * results (for example, minmax bounds of the block may change with this + * update). + */ + if (use_hot_update) + { + if (summarized_update) + *update_indexes = TU_Summarizing; + else + *update_indexes = TU_None; + } + else + *update_indexes = TU_All; + if (old_key_tuple != NULL && old_key_copied) heap_freetuple(old_key_tuple); bms_free(hot_attrs); + bms_free(sum_attrs); bms_free(key_attrs); bms_free(id_attrs); bms_free(modified_attrs); @@ -3951,7 +3990,8 @@ HeapDetermineColumnsInfo(Relation relation, * via ereport(). */ void -simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup) +simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup, + TU_UpdateIndexes *update_indexes) { TM_Result result; TM_FailureData tmfd; @@ -3960,7 +4000,7 @@ simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup) result = heap_update(relation, otid, tup, GetCurrentCommandId(true), InvalidSnapshot, true /* wait for commit */ , - &tmfd, &lockmode); + &tmfd, &lockmode, update_indexes); switch (result) { case TM_SelfModified: diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index c4b1916d36e..1ce7c6b9713 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -314,7 +314,7 @@ static TM_Result heapam_tuple_update(Relation relation, ItemPointer otid, TupleTableSlot *slot, CommandId cid, Snapshot snapshot, Snapshot crosscheck, bool wait, TM_FailureData *tmfd, - LockTupleMode *lockmode, bool *update_indexes) + LockTupleMode *lockmode, TU_UpdateIndexes *update_indexes) { bool shouldFree = true; HeapTuple tuple = ExecFetchSlotHeapTuple(slot, true, &shouldFree); @@ -325,7 +325,7 @@ heapam_tuple_update(Relation relation, ItemPointer otid, TupleTableSlot *slot, tuple->t_tableOid = slot->tts_tableOid; result = heap_update(relation, otid, tuple, cid, crosscheck, wait, - tmfd, lockmode); + tmfd, lockmode, update_indexes); ItemPointerCopy(&tuple->t_self, &slot->tts_tid); /* @@ -334,9 +334,20 @@ heapam_tuple_update(Relation relation, ItemPointer otid, TupleTableSlot *slot, * Note: heap_update returns the tid (location) of the new tuple in the * t_self field. * - * If it's a HOT update, we mustn't insert new index entries. + * If the update is not HOT, we must update all indexes. If the update + * is HOT, it could be that we updated summarized columns, so we either + * update only summarized indexes, or none at all. */ - *update_indexes = result == TM_Ok && !HeapTupleIsHeapOnly(tuple); + if (result != TM_Ok) + { + Assert(*update_indexes == TU_None); + *update_indexes = TU_None; + } + else if (!HeapTupleIsHeapOnly(tuple)) + Assert(*update_indexes == TU_All); + else + Assert((*update_indexes == TU_Summarizing) || + (*update_indexes == TU_None)); if (shouldFree) pfree(tuple); diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c index 3f7b541e9d2..a68dd07534f 100644 --- a/src/backend/access/nbtree/nbtree.c +++ b/src/backend/access/nbtree/nbtree.c @@ -114,6 +114,7 @@ bthandler(PG_FUNCTION_ARGS) amroutine->amcanparallel = true; amroutine->amcaninclude = true; amroutine->amusemaintenanceworkmem = false; + amroutine->amsummarizing = false; amroutine->amparallelvacuumoptions = VACUUM_OPTION_PARALLEL_BULKDEL | VACUUM_OPTION_PARALLEL_COND_CLEANUP; amroutine->amkeytype = InvalidOid; diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c index 3761f2c193b..4e7ff1d1603 100644 --- a/src/backend/access/spgist/spgutils.c +++ b/src/backend/access/spgist/spgutils.c @@ -62,6 +62,7 @@ spghandler(PG_FUNCTION_ARGS) amroutine->amcanparallel = false; amroutine->amcaninclude = true; amroutine->amusemaintenanceworkmem = false; + amroutine->amsummarizing = false; amroutine->amparallelvacuumoptions = VACUUM_OPTION_PARALLEL_BULKDEL | VACUUM_OPTION_PARALLEL_COND_CLEANUP; amroutine->amkeytype = InvalidOid; diff --git a/src/backend/access/table/tableam.c b/src/backend/access/table/tableam.c index ef0d34fceee..a5e6c92f35e 100644 --- a/src/backend/access/table/tableam.c +++ b/src/backend/access/table/tableam.c @@ -345,7 +345,7 @@ void simple_table_tuple_update(Relation rel, ItemPointer otid, TupleTableSlot *slot, Snapshot snapshot, - bool *update_indexes) + TU_UpdateIndexes *update_indexes) { TM_Result result; TM_FailureData tmfd; diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 7777e7ec770..33e3d0ec055 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -1383,7 +1383,8 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, oldInfo->ii_Unique, oldInfo->ii_NullsNotDistinct, false, /* not ready for inserts */ - true); + true, + indexRelation->rd_indam->amsummarizing); /* * Extract the list of column names and the column numbers for the new @@ -2455,7 +2456,8 @@ BuildIndexInfo(Relation index) indexStruct->indisunique, indexStruct->indnullsnotdistinct, indexStruct->indisready, - false); + false, + index->rd_indam->amsummarizing); /* fill in attribute numbers */ for (i = 0; i < numAtts; i++) @@ -2515,7 +2517,8 @@ BuildDummyIndexInfo(Relation index) indexStruct->indisunique, indexStruct->indnullsnotdistinct, indexStruct->indisready, - false); + false, + index->rd_indam->amsummarizing); /* fill in attribute numbers */ for (i = 0; i < numAtts; i++) diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c index bb7cc3601c7..feddff654e6 100644 --- a/src/backend/catalog/indexing.c +++ b/src/backend/catalog/indexing.c @@ -72,7 +72,8 @@ CatalogCloseIndexes(CatalogIndexState indstate) * This is effectively a cut-down version of ExecInsertIndexTuples. */ static void -CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple) +CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple, + TU_UpdateIndexes updateIndexes) { int i; int numIndexes; @@ -82,6 +83,7 @@ CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple) IndexInfo **indexInfoArray; Datum values[INDEX_MAX_KEYS]; bool isnull[INDEX_MAX_KEYS]; + bool onlySummarized = (updateIndexes == TU_Summarizing); /* * HOT update does not require index inserts. But with asserts enabled we @@ -89,10 +91,13 @@ CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple) * table/index. */ #ifndef USE_ASSERT_CHECKING - if (HeapTupleIsHeapOnly(heapTuple)) + if (HeapTupleIsHeapOnly(heapTuple) && !onlySummarized) return; #endif + /* When only updating summarized indexes, the tuple has to be HOT. */ + Assert((!onlySummarized) || HeapTupleIsHeapOnly(heapTuple)); + /* * Get information from the state structure. Fall out if nothing to do. */ @@ -135,7 +140,7 @@ CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple) /* see earlier check above */ #ifdef USE_ASSERT_CHECKING - if (HeapTupleIsHeapOnly(heapTuple)) + if (HeapTupleIsHeapOnly(heapTuple) && !onlySummarized) { Assert(!ReindexIsProcessingIndex(RelationGetRelid(index))); continue; @@ -143,6 +148,13 @@ CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple) #endif /* USE_ASSERT_CHECKING */ /* + * Skip insertions into non-summarizing indexes if we only need + * to update summarizing indexes. + */ + if (onlySummarized && !indexInfo->ii_Summarizing) + continue; + + /* * FormIndexDatum fills in its values and isnull parameters with the * appropriate values for the column(s) of the index. */ @@ -228,7 +240,7 @@ CatalogTupleInsert(Relation heapRel, HeapTuple tup) simple_heap_insert(heapRel, tup); - CatalogIndexInsert(indstate, tup); + CatalogIndexInsert(indstate, tup, TU_All); CatalogCloseIndexes(indstate); } @@ -248,7 +260,7 @@ CatalogTupleInsertWithInfo(Relation heapRel, HeapTuple tup, simple_heap_insert(heapRel, tup); - CatalogIndexInsert(indstate, tup); + CatalogIndexInsert(indstate, tup, TU_All); } /* @@ -279,7 +291,7 @@ CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot, tuple = ExecFetchSlotHeapTuple(slot[i], true, &should_free); tuple->t_tableOid = slot[i]->tts_tableOid; - CatalogIndexInsert(indstate, tuple); + CatalogIndexInsert(indstate, tuple, TU_All); if (should_free) heap_freetuple(tuple); @@ -301,14 +313,15 @@ void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup) { CatalogIndexState indstate; + TU_UpdateIndexes updateIndexes = TU_All; CatalogTupleCheckConstraints(heapRel, tup); indstate = CatalogOpenIndexes(heapRel); - simple_heap_update(heapRel, otid, tup); + simple_heap_update(heapRel, otid, tup, &updateIndexes); - CatalogIndexInsert(indstate, tup); + CatalogIndexInsert(indstate, tup, updateIndexes); CatalogCloseIndexes(indstate); } @@ -324,11 +337,13 @@ void CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup, CatalogIndexState indstate) { + TU_UpdateIndexes updateIndexes = TU_All; + CatalogTupleCheckConstraints(heapRel, tup); - simple_heap_update(heapRel, otid, tup); + simple_heap_update(heapRel, otid, tup, &updateIndexes); - CatalogIndexInsert(indstate, tup); + CatalogIndexInsert(indstate, tup, updateIndexes); } /* diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c index 321a7fad854..80bca79cd0e 100644 --- a/src/backend/commands/copyfrom.c +++ b/src/backend/commands/copyfrom.c @@ -435,7 +435,7 @@ CopyMultiInsertBufferFlush(CopyMultiInsertInfo *miinfo, recheckIndexes = ExecInsertIndexTuples(resultRelInfo, buffer->slots[i], estate, false, - false, NULL, NIL); + false, NULL, NIL, false); ExecARInsertTriggers(estate, resultRelInfo, slots[i], recheckIndexes, cstate->transition_capture); @@ -1248,7 +1248,8 @@ CopyFrom(CopyFromState cstate) false, false, NULL, - NIL); + NIL, + false); } /* AFTER ROW INSERT Triggers */ diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 16ec0b114e6..ff48f44c66f 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -184,6 +184,7 @@ CheckIndexCompatible(Oid oldId, Form_pg_am accessMethodForm; IndexAmRoutine *amRoutine; bool amcanorder; + bool amsummarizing; int16 *coloptions; IndexInfo *indexInfo; int numberOfAttributes; @@ -222,6 +223,7 @@ CheckIndexCompatible(Oid oldId, ReleaseSysCache(tuple); amcanorder = amRoutine->amcanorder; + amsummarizing = amRoutine->amsummarizing; /* * Compute the operator classes, collations, and exclusion operators for @@ -232,7 +234,8 @@ CheckIndexCompatible(Oid oldId, * ii_NumIndexKeyAttrs with same value. */ indexInfo = makeIndexInfo(numberOfAttributes, numberOfAttributes, - accessMethodId, NIL, NIL, false, false, false, false); + accessMethodId, NIL, NIL, false, false, + false, false, amsummarizing); typeObjectId = palloc_array(Oid, numberOfAttributes); collationObjectId = palloc_array(Oid, numberOfAttributes); classObjectId = palloc_array(Oid, numberOfAttributes); @@ -550,6 +553,7 @@ DefineIndex(Oid relationId, Form_pg_am accessMethodForm; IndexAmRoutine *amRoutine; bool amcanorder; + bool amissummarizing; amoptions_function amoptions; bool partitioned; bool safe_index; @@ -866,6 +870,7 @@ DefineIndex(Oid relationId, amcanorder = amRoutine->amcanorder; amoptions = amRoutine->amoptions; + amissummarizing = amRoutine->amsummarizing; pfree(amRoutine); ReleaseSysCache(tuple); @@ -897,7 +902,8 @@ DefineIndex(Oid relationId, stmt->unique, stmt->nulls_not_distinct, !concurrent, - concurrent); + concurrent, + amissummarizing); typeObjectId = palloc_array(Oid, numberOfAttributes); collationObjectId = palloc_array(Oid, numberOfAttributes); diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c index 6e88e72813f..da28e5e40ca 100644 --- a/src/backend/executor/execIndexing.c +++ b/src/backend/executor/execIndexing.c @@ -259,15 +259,24 @@ ExecCloseIndices(ResultRelInfo *resultRelInfo) * into all the relations indexing the result relation * when a heap tuple is inserted into the result relation. * - * When 'update' is true, executor is performing an UPDATE - * that could not use an optimization like heapam's HOT (in - * more general terms a call to table_tuple_update() took - * place and set 'update_indexes' to true). Receiving this - * hint makes us consider if we should pass down the - * 'indexUnchanged' hint in turn. That's something that we - * figure out for each index_insert() call iff 'update' is - * true. (When 'update' is false we already know not to pass - * the hint to any index.) + * When 'update' is true and 'onlySummarizing' is false, + * executor is performing an UPDATE that could not use an + * optimization like heapam's HOT (in more general terms a + * call to table_tuple_update() took place and set + * 'update_indexes' to TUUI_All). Receiving this hint makes + * us consider if we should pass down the 'indexUnchanged' + * hint in turn. That's something that we figure out for + * each index_insert() call iff 'update' is true. + * (When 'update' is false we already know not to pass the + * hint to any index.) + * + * If onlySummarizing is set, an equivalent optimization to + * HOT has been applied and any updated columns are indexed + * only by summarizing indexes (or in more general terms a + * call to table_tuple_update() took place and set + * 'update_indexes' to TUUI_Summarizing). We can (and must) + * therefore only update the indexes that have + * 'amsummarizing' = true. * * Unique and exclusion constraints are enforced at the same * time. This returns a list of index OIDs for any unique or @@ -287,7 +296,8 @@ ExecInsertIndexTuples(ResultRelInfo *resultRelInfo, bool update, bool noDupErr, bool *specConflict, - List *arbiterIndexes) + List *arbiterIndexes, + bool onlySummarizing) { ItemPointer tupleid = &slot->tts_tid; List *result = NIL; @@ -343,6 +353,13 @@ ExecInsertIndexTuples(ResultRelInfo *resultRelInfo, if (!indexInfo->ii_ReadyForInserts) continue; + /* + * Skip processing of non-summarizing indexes if we only + * update summarizing indexes + */ + if (onlySummarizing && !indexInfo->ii_Summarizing) + continue; + /* Check for partial index */ if (indexInfo->ii_Predicate != NIL) { diff --git a/src/backend/executor/execReplication.c b/src/backend/executor/execReplication.c index fa8628e3e1b..c4bc69f1e55 100644 --- a/src/backend/executor/execReplication.c +++ b/src/backend/executor/execReplication.c @@ -491,7 +491,7 @@ ExecSimpleRelationInsert(ResultRelInfo *resultRelInfo, if (resultRelInfo->ri_NumIndices > 0) recheckIndexes = ExecInsertIndexTuples(resultRelInfo, slot, estate, false, false, - NULL, NIL); + NULL, NIL, false); /* AFTER ROW INSERT Triggers */ ExecARInsertTriggers(estate, resultRelInfo, slot, @@ -539,7 +539,7 @@ ExecSimpleRelationUpdate(ResultRelInfo *resultRelInfo, if (!skip_tuple) { List *recheckIndexes = NIL; - bool update_indexes; + TU_UpdateIndexes update_indexes; /* Compute stored generated columns */ if (rel->rd_att->constr && @@ -556,10 +556,11 @@ ExecSimpleRelationUpdate(ResultRelInfo *resultRelInfo, simple_table_tuple_update(rel, tid, slot, estate->es_snapshot, &update_indexes); - if (resultRelInfo->ri_NumIndices > 0 && update_indexes) + if (resultRelInfo->ri_NumIndices > 0 && (update_indexes != TU_None)) recheckIndexes = ExecInsertIndexTuples(resultRelInfo, slot, estate, true, false, - NULL, NIL); + NULL, NIL, + (update_indexes == TU_Summarizing)); /* AFTER ROW UPDATE Triggers */ ExecARUpdateTriggers(estate, resultRelInfo, diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 3fa2b930a52..3a673895082 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -110,8 +110,8 @@ typedef struct ModifyTableContext typedef struct UpdateContext { bool updated; /* did UPDATE actually occur? */ - bool updateIndexes; /* index update required? */ bool crossPartUpdate; /* was it a cross-partition update? */ + TU_UpdateIndexes updateIndexes; /* Which index updates are required? */ /* * Lock mode to acquire on the latest tuple version before performing @@ -1099,7 +1099,8 @@ ExecInsert(ModifyTableContext *context, recheckIndexes = ExecInsertIndexTuples(resultRelInfo, slot, estate, false, true, &specConflict, - arbiterIndexes); + arbiterIndexes, + false); /* adjust the tuple's state accordingly */ table_tuple_complete_speculative(resultRelationDesc, slot, @@ -1138,7 +1139,8 @@ ExecInsert(ModifyTableContext *context, if (resultRelInfo->ri_NumIndices > 0) recheckIndexes = ExecInsertIndexTuples(resultRelInfo, slot, estate, false, - false, NULL, NIL); + false, NULL, NIL, + false); } } @@ -2118,11 +2120,12 @@ ExecUpdateEpilogue(ModifyTableContext *context, UpdateContext *updateCxt, List *recheckIndexes = NIL; /* insert index entries for tuple if necessary */ - if (resultRelInfo->ri_NumIndices > 0 && updateCxt->updateIndexes) + if (resultRelInfo->ri_NumIndices > 0 && (updateCxt->updateIndexes != TU_None)) recheckIndexes = ExecInsertIndexTuples(resultRelInfo, slot, context->estate, true, false, - NULL, NIL); + NULL, NIL, + (updateCxt->updateIndexes == TU_Summarizing)); /* AFTER ROW UPDATE Triggers */ ExecARUpdateTriggers(context->estate, resultRelInfo, diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c index fe67baf1420..216383ca239 100644 --- a/src/backend/nodes/makefuncs.c +++ b/src/backend/nodes/makefuncs.c @@ -743,7 +743,8 @@ make_ands_implicit(Expr *clause) */ IndexInfo * makeIndexInfo(int numattrs, int numkeyattrs, Oid amoid, List *expressions, - List *predicates, bool unique, bool nulls_not_distinct, bool isready, bool concurrent) + List *predicates, bool unique, bool nulls_not_distinct, + bool isready, bool concurrent, bool summarizing) { IndexInfo *n = makeNode(IndexInfo); @@ -757,6 +758,10 @@ makeIndexInfo(int numattrs, int numkeyattrs, Oid amoid, List *expressions, n->ii_CheckedUnchanged = false; n->ii_IndexUnchanged = false; n->ii_Concurrent = concurrent; + n->ii_Summarizing = summarizing; + + /* summarizing indexes cannot contain non-key attributes */ + Assert(!summarizing || (numkeyattrs == numattrs)); /* expressions */ n->ii_Expressions = expressions; diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 13f79873733..40140de9589 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -2440,10 +2440,11 @@ RelationDestroyRelation(Relation relation, bool remember_tupdesc) list_free_deep(relation->rd_fkeylist); list_free(relation->rd_indexlist); list_free(relation->rd_statlist); - bms_free(relation->rd_indexattr); bms_free(relation->rd_keyattr); bms_free(relation->rd_pkattr); bms_free(relation->rd_idattr); + bms_free(relation->rd_hotblockingattr); + bms_free(relation->rd_summarizedattr); if (relation->rd_pubdesc) pfree(relation->rd_pubdesc); if (relation->rd_options) @@ -5167,10 +5168,11 @@ RelationGetIndexPredicate(Relation relation) Bitmapset * RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind) { - Bitmapset *indexattrs; /* indexed columns */ Bitmapset *uindexattrs; /* columns in unique indexes */ Bitmapset *pkindexattrs; /* columns in the primary index */ Bitmapset *idindexattrs; /* columns in the replica identity */ + Bitmapset *hotblockingattrs; /* columns with HOT blocking indexes */ + Bitmapset *summarizedattrs; /* columns with summarizing indexes */ List *indexoidlist; List *newindexoidlist; Oid relpkindex; @@ -5179,18 +5181,20 @@ RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind) MemoryContext oldcxt; /* Quick exit if we already computed the result. */ - if (relation->rd_indexattr != NULL) + if (relation->rd_attrsvalid) { switch (attrKind) { - case INDEX_ATTR_BITMAP_ALL: - return bms_copy(relation->rd_indexattr); case INDEX_ATTR_BITMAP_KEY: return bms_copy(relation->rd_keyattr); case INDEX_ATTR_BITMAP_PRIMARY_KEY: return bms_copy(relation->rd_pkattr); case INDEX_ATTR_BITMAP_IDENTITY_KEY: return bms_copy(relation->rd_idattr); + case INDEX_ATTR_BITMAP_HOT_BLOCKING: + return bms_copy(relation->rd_hotblockingattr); + case INDEX_ATTR_BITMAP_SUMMARIZED: + return bms_copy(relation->rd_summarizedattr); default: elog(ERROR, "unknown attrKind %u", attrKind); } @@ -5230,10 +5234,11 @@ restart: * CONCURRENTLY is far enough along that we should ignore the index, it * won't be returned at all by RelationGetIndexList. */ - indexattrs = NULL; uindexattrs = NULL; pkindexattrs = NULL; idindexattrs = NULL; + hotblockingattrs = NULL; + summarizedattrs = NULL; foreach(l, indexoidlist) { Oid indexOid = lfirst_oid(l); @@ -5246,6 +5251,7 @@ restart: bool isKey; /* candidate key */ bool isPK; /* primary key */ bool isIDKey; /* replica identity index */ + Bitmapset **attrs; indexDesc = index_open(indexOid, AccessShareLock); @@ -5283,6 +5289,16 @@ restart: /* Is this index the configured (or default) replica identity? */ isIDKey = (indexOid == relreplindex); + /* + * If the index is summarizing, it doesn't block HOT updates, but we + * may still need to update it (if the attributes were modified). So + * decide which bitmap we'll update in the following loop. + */ + if (indexDesc->rd_indam->amsummarizing) + attrs = &summarizedattrs; + else + attrs = &hotblockingattrs; + /* Collect simple attribute references */ for (i = 0; i < indexDesc->rd_index->indnatts; i++) { @@ -5291,15 +5307,21 @@ restart: /* * Since we have covering indexes with non-key columns, we must * handle them accurately here. non-key columns must be added into - * indexattrs, since they are in index, and HOT-update shouldn't - * miss them. Obviously, non-key columns couldn't be referenced by + * hotblockingattrs or summarizedattrs, since they are in index, + * and update shouldn't miss them. + * + * Summarizing indexes do not block HOT, but do need to be updated + * when the column value changes, thus require a separate + * attribute bitmapset. + * + * Obviously, non-key columns couldn't be referenced by * foreign key or identity key. Hence we do not include them into * uindexattrs, pkindexattrs and idindexattrs bitmaps. */ if (attrnum != 0) { - indexattrs = bms_add_member(indexattrs, - attrnum - FirstLowInvalidHeapAttributeNumber); + *attrs = bms_add_member(*attrs, + attrnum - FirstLowInvalidHeapAttributeNumber); if (isKey && i < indexDesc->rd_index->indnkeyatts) uindexattrs = bms_add_member(uindexattrs, @@ -5316,10 +5338,10 @@ restart: } /* Collect all attributes used in expressions, too */ - pull_varattnos(indexExpressions, 1, &indexattrs); + pull_varattnos(indexExpressions, 1, attrs); /* Collect all attributes in the index predicate, too */ - pull_varattnos(indexPredicate, 1, &indexattrs); + pull_varattnos(indexPredicate, 1, attrs); index_close(indexDesc, AccessShareLock); } @@ -5347,24 +5369,28 @@ restart: bms_free(uindexattrs); bms_free(pkindexattrs); bms_free(idindexattrs); - bms_free(indexattrs); + bms_free(hotblockingattrs); + bms_free(summarizedattrs); goto restart; } /* Don't leak the old values of these bitmaps, if any */ - bms_free(relation->rd_indexattr); - relation->rd_indexattr = NULL; + relation->rd_attrsvalid = false; bms_free(relation->rd_keyattr); relation->rd_keyattr = NULL; bms_free(relation->rd_pkattr); relation->rd_pkattr = NULL; bms_free(relation->rd_idattr); relation->rd_idattr = NULL; + bms_free(relation->rd_hotblockingattr); + relation->rd_hotblockingattr = NULL; + bms_free(relation->rd_summarizedattr); + relation->rd_summarizedattr = NULL; /* * Now save copies of the bitmaps in the relcache entry. We intentionally - * set rd_indexattr last, because that's the one that signals validity of + * set rd_attrsvalid last, because that's the one that signals validity of * the values; if we run out of memory before making that copy, we won't * leave the relcache entry looking like the other ones are valid but * empty. @@ -5373,20 +5399,24 @@ restart: relation->rd_keyattr = bms_copy(uindexattrs); relation->rd_pkattr = bms_copy(pkindexattrs); relation->rd_idattr = bms_copy(idindexattrs); - relation->rd_indexattr = bms_copy(indexattrs); + relation->rd_hotblockingattr = bms_copy(hotblockingattrs); + relation->rd_summarizedattr = bms_copy(summarizedattrs); + relation->rd_attrsvalid = true; MemoryContextSwitchTo(oldcxt); /* We return our original working copy for caller to play with */ switch (attrKind) { - case INDEX_ATTR_BITMAP_ALL: - return indexattrs; case INDEX_ATTR_BITMAP_KEY: return uindexattrs; case INDEX_ATTR_BITMAP_PRIMARY_KEY: return pkindexattrs; case INDEX_ATTR_BITMAP_IDENTITY_KEY: return idindexattrs; + case INDEX_ATTR_BITMAP_HOT_BLOCKING: + return hotblockingattrs; + case INDEX_ATTR_BITMAP_SUMMARIZED: + return summarizedattrs; default: elog(ERROR, "unknown attrKind %u", attrKind); return NULL; @@ -6307,7 +6337,7 @@ load_relcache_init_file(bool shared) rel->rd_indexlist = NIL; rel->rd_pkindex = InvalidOid; rel->rd_replidindex = InvalidOid; - rel->rd_indexattr = NULL; + rel->rd_attrsvalid = false; rel->rd_keyattr = NULL; rel->rd_pkattr = NULL; rel->rd_idattr = NULL; |