From 9252ae65eee9b9718bd62e5804a7783b4b6b9000 Mon Sep 17 00:00:00 2001 From: amit Date: Tue, 30 Oct 2018 17:53:07 +0900 Subject: [PATCH v1 2/2] Add a MemoryContext arg to check_exclusion_or_unique_constraint check_exclusion_or_unique_constraint performs an index scan and some index AMs may use huge amounts of memory that might end up getting allocated in a possibly long-lived context. A given caller may call check_exclusion_or_unique_constraint repeatedly as it's scanning a heap, for example, where it's desirable to free the memory for each new tuple. With that in place, teach IndexCheckExclusion and ExecIndexInsertTuples to pass a per-tuple context down to check_exclusion_or_unique_constraint. --- src/backend/catalog/index.c | 12 +++++++++++- src/backend/commands/constraint.c | 2 +- src/backend/executor/execIndexing.c | 21 ++++++++++++++------- src/include/executor/executor.h | 3 ++- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 5885899c9b..ccafceb73a 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -2983,6 +2983,7 @@ IndexCheckExclusion(Relation heapRelation, EState *estate; ExprContext *econtext; Snapshot snapshot; + MemoryContext index_scan_cxt; /* * If we are reindexing the target index, mark it as no longer being @@ -3017,11 +3018,20 @@ IndexCheckExclusion(Relation heapRelation, true, /* buffer access strategy OK */ true); /* syncscan OK */ + /* + * This context contains the allocations needed to scan the index + * for a given heap tuple, reset for every tuple. + */ + index_scan_cxt = AllocSetContextCreate(CurrentMemoryContext, + "IndexCheckExclusion_cxt", + ALLOCSET_DEFAULT_SIZES); + while ((heapTuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { CHECK_FOR_INTERRUPTS(); MemoryContextReset(econtext->ecxt_per_tuple_memory); + MemoryContextReset(index_scan_cxt); /* Set up for predicate or expression evaluation */ ExecStoreHeapTuple(heapTuple, slot, false); @@ -3050,7 +3060,7 @@ IndexCheckExclusion(Relation heapRelation, check_exclusion_constraint(heapRelation, indexRelation, indexInfo, &(heapTuple->t_self), values, isnull, - estate, true); + estate, true, index_scan_cxt); } heap_endscan(scan); diff --git a/src/backend/commands/constraint.c b/src/backend/commands/constraint.c index f472355b48..a4b1e4c112 100644 --- a/src/backend/commands/constraint.c +++ b/src/backend/commands/constraint.c @@ -178,7 +178,7 @@ unique_key_recheck(PG_FUNCTION_ARGS) */ check_exclusion_constraint(trigdata->tg_relation, indexRel, indexInfo, &tmptid, values, isnull, - estate, false); + estate, false, CurrentMemoryContext); } /* diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c index 74d15e6b43..cc1f5ffc39 100644 --- a/src/backend/executor/execIndexing.c +++ b/src/backend/executor/execIndexing.c @@ -129,7 +129,8 @@ static bool check_exclusion_or_unique_constraint(Relation heap, Relation index, EState *estate, bool newIndex, CEOUC_WAIT_MODE waitMode, bool errorOK, - ItemPointer conflictTid); + ItemPointer conflictTid, + MemoryContext index_scan_cxt); static bool index_recheck_constraint(Relation index, Oid *constr_procs, Datum *existing_values, bool *existing_isnull, @@ -410,6 +411,7 @@ ExecInsertIndexTuples(TupleTableSlot *slot, { bool violationOK; CEOUC_WAIT_MODE waitMode; + ExprContext *econtext = GetPerTupleExprContext(estate); if (applyNoDupErr) { @@ -432,7 +434,8 @@ ExecInsertIndexTuples(TupleTableSlot *slot, indexRelation, indexInfo, tupleid, values, isnull, estate, false, - waitMode, violationOK, NULL); + waitMode, violationOK, NULL, + econtext->ecxt_per_tuple_memory); } if ((checkUnique == UNIQUE_CHECK_PARTIAL || @@ -582,7 +585,8 @@ ExecCheckIndexConstraints(TupleTableSlot *slot, indexInfo, &invalidItemPtr, values, isnull, estate, false, CEOUC_WAIT, true, - conflictTid); + conflictTid, + CurrentMemoryContext); if (!satisfiesConstraint) return false; } @@ -643,7 +647,8 @@ check_exclusion_or_unique_constraint(Relation heap, Relation index, EState *estate, bool newIndex, CEOUC_WAIT_MODE waitMode, bool violationOK, - ItemPointer conflictTid) + ItemPointer conflictTid, + MemoryContext index_scan_cxt) { Oid *constr_procs; uint16 *constr_strats; @@ -720,7 +725,7 @@ retry: conflict = false; found_self = false; index_scan = index_beginscan(heap, index, &DirtySnapshot, indnkeyatts, 0, - CurrentMemoryContext); + index_scan_cxt); index_rescan(index_scan, scankeys, indnkeyatts, NULL, 0); while ((tup = index_getnext(index_scan, @@ -865,12 +870,14 @@ check_exclusion_constraint(Relation heap, Relation index, IndexInfo *indexInfo, ItemPointer tupleid, Datum *values, bool *isnull, - EState *estate, bool newIndex) + EState *estate, bool newIndex, + MemoryContext index_scan_cxt) { (void) check_exclusion_or_unique_constraint(heap, index, indexInfo, tupleid, values, isnull, estate, newIndex, - CEOUC_WAIT, false, NULL); + CEOUC_WAIT, false, NULL, + index_scan_cxt); } /* diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index edf538365b..c5998d9885 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -556,7 +556,8 @@ extern void check_exclusion_constraint(Relation heap, Relation index, IndexInfo *indexInfo, ItemPointer tupleid, Datum *values, bool *isnull, - EState *estate, bool newIndex); + EState *estate, bool newIndex, + MemoryContext index_scan_cxt); /* * prototypes from functions in execReplication.c -- 2.11.0