From e519b5c78ce6c21df524a609eb9acf582f49cb79 Mon Sep 17 00:00:00 2001 From: amit Date: Thu, 19 Jul 2018 13:01:43 +0900 Subject: [PATCH v1 4/4] Revise executor range table relation opening/closing All requests to open range table relations in the executor now go through ExecRangeTableRelation(), which consults an array of Relation pointers indexed by RT index. To speed up retrieving range table entries at arbitrary points within the executor, this introduceds an array of RangeTblEntry pointers in EState. InitPlan builds it from the es_range_table list. This also revises PartitionedRelPruneInfo node to contain the partitioned table's RT index instead of OID. With that change, ExecCreatePartitionPruneState can use ExecRangeTableRelation described above. --- src/backend/executor/execExprInterp.c | 6 ++++-- src/backend/executor/execMain.c | 34 +++++++++++++++++++++++++--------- src/backend/executor/execPartition.c | 12 ++++++------ src/backend/executor/execUtils.c | 4 +--- src/backend/executor/nodeModifyTable.c | 9 +++------ src/backend/nodes/copyfuncs.c | 2 +- src/backend/nodes/outfuncs.c | 2 +- src/backend/nodes/readfuncs.c | 2 +- src/backend/optimizer/plan/setrefs.c | 30 ++++++++++++++++++++++++++++++ src/backend/partitioning/partprune.c | 5 +---- src/include/executor/executor.h | 30 ++++++++++++++++++++++++++++++ src/include/nodes/execnodes.h | 7 +++++++ src/include/nodes/plannodes.h | 2 +- 13 files changed, 111 insertions(+), 34 deletions(-) diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index 9d6e25aae5..af8c636d94 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -3963,8 +3963,10 @@ ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext) if (econtext->ecxt_estate && variable->varno <= list_length(econtext->ecxt_estate->es_range_table)) { - RangeTblEntry *rte = rt_fetch(variable->varno, - econtext->ecxt_estate->es_range_table); + RangeTblEntry *rte = econtext->ecxt_estate->es_rtable_array ? + econtext->ecxt_estate->es_rtable_array[variable->varno] : + rt_fetch(variable->varno, + econtext->ecxt_estate->es_range_table); if (rte->eref) ExecTypeSetColNames(output_tupdesc, rte->eref->colnames); diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 5e0c2b8e67..c3899d9068 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -109,9 +109,13 @@ static void EvalPlanQualStart(EPQState *epqstate, EState *parentestate, * to be changed, however. */ #define GetInsertedColumns(relinfo, estate) \ - (rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->insertedCols) + ((estate)->es_rtable_array != NULL ?\ + (estate)->es_rtable_array[(relinfo)->ri_RangeTableIndex]->insertedCols :\ + rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->insertedCols) #define GetUpdatedColumns(relinfo, estate) \ - (rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->updatedCols) + ((estate)->es_rtable_array != NULL ?\ + (estate)->es_rtable_array[(relinfo)->ri_RangeTableIndex]->updatedCols :\ + rt_fetch((relinfo)->ri_RangeTableIndex, (estate)->es_range_table)->updatedCols) /* end of local decls */ @@ -814,6 +818,7 @@ InitPlan(QueryDesc *queryDesc, int eflags) TupleDesc tupType; ListCell *l; int i; + int rti; /* * Do permissions checks @@ -844,6 +849,17 @@ InitPlan(QueryDesc *queryDesc, int eflags) * initialize the node's execution state */ estate->es_range_table = rangeTable; + + /* allocate space for Relation pointer and initialize with 0s. */ + estate->es_relations = (Relation *) + palloc0((list_length(rangeTable) + 1) * sizeof(Relation)); + estate->es_rtable_array = (RangeTblEntry **) + palloc((list_length(rangeTable) + 1) * + sizeof(RangeTblEntry *)); + rti = 1; + foreach(l, rangeTable) + estate->es_rtable_array[rti++] = lfirst(l); + estate->es_plannedstmt = plannedstmt; /* @@ -2278,14 +2294,10 @@ ExecRowMark * ExecBuildRowMark(EState *estate, PlanRowMark *rc) { ExecRowMark *erm; - Oid relid; Relation relation; Assert(!rc->isParent); - /* get relation's OID (will produce InvalidOid if subquery) */ - relid = getrelid(rc->rti, estate->es_range_table); - /* * If you change the conditions under which rel locks are acquired * here, be sure to adjust ExecOpenScanRelation to match. @@ -2296,10 +2308,10 @@ ExecBuildRowMark(EState *estate, PlanRowMark *rc) case ROW_MARK_NOKEYEXCLUSIVE: case ROW_MARK_SHARE: case ROW_MARK_KEYSHARE: - relation = heap_open(relid, NoLock); + relation = ExecRangeTableRelation(estate, rc->rti); break; case ROW_MARK_REFERENCE: - relation = heap_open(relid, NoLock); + relation = ExecRangeTableRelation(estate, rc->rti); break; case ROW_MARK_COPY: /* no physical table access is required */ @@ -2317,7 +2329,7 @@ ExecBuildRowMark(EState *estate, PlanRowMark *rc) erm = (ExecRowMark *) palloc(sizeof(ExecRowMark)); erm->relation = relation; - erm->relid = relid; + erm->relid = estate->es_rtable_array[rc->rti]->relid; erm->rti = rc->rti; erm->prti = rc->prti; erm->rowmarkId = rc->rowmarkId; @@ -3114,6 +3126,10 @@ EvalPlanQualStart(EPQState *epqstate, EState *parentestate, Plan *planTree) */ estate->es_tupleTable = NIL; + /* OK to use these as is from the parent. */ + estate->es_rtable_array = parentestate->es_rtable_array; + estate->es_relations = parentestate->es_relations; + /* * Initialize private state information for each SubPlan. We must do this * before running ExecInitNode on the main query tree, since diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index 3db0b99aa6..cf4b569d5c 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -831,11 +831,10 @@ ExecCleanupTupleRouting(ModifyTableState *mtstate, int subplan_index = 0; /* - * Remember, proute->partition_dispatch_info[0] corresponds to the root - * partitioned table, which we must not try to close, because it is the - * main target table of the query that will be closed by callers such as - * ExecEndPlan() or DoCopy(). Also, tupslot is NULL for the root - * partitioned table. + * proute->partition_dispatch_info[0] corresponds to the root partitioned + * table, which is the main target table of the query, so it is closed by + * ExecEndModifyTable() or DoCopy(). Also, tupslot is NULL for the root + * partitioned table, so nothing to do here for the root table. */ for (i = 1; i < proute->num_dispatch; i++) { @@ -1432,6 +1431,7 @@ PartitionPruneState * ExecCreatePartitionPruneState(PlanState *planstate, PartitionPruneInfo *partitionpruneinfo) { + EState *estate = planstate->state; PartitionPruneState *prunestate; int n_part_hierarchies; ListCell *lc; @@ -1512,7 +1512,7 @@ ExecCreatePartitionPruneState(PlanState *planstate, * so that we can rely on its copies of the table's partition key * and partition descriptor. */ - context->partrel = relation_open(pinfo->reloid, NoLock); + context->partrel = ExecRangeTableRelation(estate, pinfo->rtindex); partkey = RelationGetPartitionKey(context->partrel); partdesc = RelationGetPartitionDesc(context->partrel); diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index d32796aac3..94acea245a 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -653,11 +653,9 @@ Relation ExecOpenScanRelation(EState *estate, Index scanrelid, int eflags) { Relation rel; - Oid reloid; /* Open the relation. */ - reloid = getrelid(scanrelid, estate->es_range_table); - rel = heap_open(reloid, NoLock); + rel = ExecRangeTableRelation(estate, scanrelid); /* * Complain if we're attempting a scan of an unscannable relation, except diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index fd3966d489..8c6c26d7d6 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -2243,10 +2243,9 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) foreach(l, node->resultRelations) { Index resultRelationIndex = lfirst_int(l); - RangeTblEntry *rte = rt_fetch(resultRelationIndex, - estate->es_range_table); - Relation rel = heap_open(rte->relid, NoLock); + Relation rel; + rel = ExecRangeTableRelation(estate, resultRelationIndex); InitResultRelInfo(resultRelInfo, rel, resultRelationIndex, NULL, estate->es_instrument); resultRelInfo++; @@ -2255,15 +2254,13 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) /* If modifying a partitioned table, initialize the root table info */ if (node->rootResultRelIndex >= 0) { - RangeTblEntry *rte; Relation rel; mtstate->rootResultRelInfo = estate->es_root_result_relations + node->rootResultRelIndex; Assert(node->rootRelation > 0); - rte = rt_fetch(node->rootRelation, estate->es_range_table); - rel = heap_open(rte->relid, NoLock); + rel = ExecRangeTableRelation(estate, node->rootRelation); InitResultRelInfo(mtstate->rootResultRelInfo, rel, node->rootRelation, NULL, estate->es_instrument); } diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 29abe56b70..478cd711cf 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -1190,7 +1190,7 @@ _copyPartitionedRelPruneInfo(const PartitionedRelPruneInfo *from) { PartitionedRelPruneInfo *newnode = makeNode(PartitionedRelPruneInfo); - COPY_SCALAR_FIELD(reloid); + COPY_SCALAR_FIELD(rtindex); COPY_NODE_FIELD(pruning_steps); COPY_BITMAPSET_FIELD(present_parts); COPY_SCALAR_FIELD(nparts); diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index f5fd9e6345..dd53ef3115 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -1025,7 +1025,7 @@ _outPartitionedRelPruneInfo(StringInfo str, const PartitionedRelPruneInfo *node) WRITE_NODE_TYPE("PARTITIONEDRELPRUNEINFO"); - WRITE_OID_FIELD(reloid); + WRITE_UINT_FIELD(rtindex); WRITE_NODE_FIELD(pruning_steps); WRITE_BITMAPSET_FIELD(present_parts); WRITE_INT_FIELD(nparts); diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 780d261edf..df80a31cc1 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -2338,7 +2338,7 @@ _readPartitionedRelPruneInfo(void) { READ_LOCALS(PartitionedRelPruneInfo); - READ_OID_FIELD(reloid); + READ_UINT_FIELD(rtindex); READ_NODE_FIELD(pruning_steps); READ_BITMAPSET_FIELD(present_parts); READ_INT_FIELD(nparts); diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 7db9d0f1d4..0e53981834 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -896,6 +896,21 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) (Plan *) lfirst(l), rtoffset); } + if (splan->part_prune_info) + { + foreach(l, splan->part_prune_info->prune_infos) + { + List *prune_infos = lfirst(l); + ListCell *l2; + + foreach(l2, prune_infos) + { + PartitionedRelPruneInfo *pinfo = lfirst(l2); + + pinfo->rtindex += rtoffset; + } + } + } } break; case T_MergeAppend: @@ -914,6 +929,21 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) (Plan *) lfirst(l), rtoffset); } + if (splan->part_prune_info) + { + foreach(l, splan->part_prune_info->prune_infos) + { + List *prune_infos = lfirst(l); + ListCell *l2; + + foreach(l2, prune_infos) + { + PartitionedRelPruneInfo *pinfo = lfirst(l2); + + pinfo->rtindex += rtoffset; + } + } + } } break; case T_RecursiveUnion: diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index 0dd55ac1ba..58d8ad6f24 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -357,7 +357,6 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, Index rti = lfirst_int(lc); RelOptInfo *subpart = find_base_rel(root, rti); PartitionedRelPruneInfo *pinfo; - RangeTblEntry *rte; Bitmapset *present_parts; int nparts = subpart->nparts; int partnatts = subpart->part_scheme->partnatts; @@ -459,10 +458,8 @@ make_partitionedrel_pruneinfo(PlannerInfo *root, RelOptInfo *parentrel, present_parts = bms_add_member(present_parts, i); } - rte = root->simple_rte_array[subpart->relid]; - pinfo = makeNode(PartitionedRelPruneInfo); - pinfo->reloid = rte->relid; + pinfo->rtindex = rti; pinfo->pruning_steps = pruning_steps; pinfo->present_parts = present_parts; pinfo->nparts = nparts; diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 1d2b48fe09..97d86788ba 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -17,6 +17,7 @@ #include "executor/execdesc.h" #include "nodes/parsenodes.h" #include "utils/memutils.h" +#include "utils/rel.h" /* @@ -568,4 +569,33 @@ extern void CheckCmdReplicaIdentity(Relation rel, CmdType cmd); extern void CheckSubscriptionRelkind(char relkind, const char *nspname, const char *relname); +#ifndef FRONTEND +static inline Relation +ExecRangeTableRelation(EState *estate, Index rti) +{ + RangeTblEntry *rte; + Relation rel; + + if (estate->es_relations[rti] != NULL) + { + RelationIncrementReferenceCount(estate->es_relations[rti]); + rel = estate->es_relations[rti]; + } + else + { + Assert(estate->es_rtable_array != NULL && + estate->es_rtable_array[rti] != NULL); + rte = estate->es_rtable_array[rti]; + + /* + * No need to lock the relation lock, because upstream code + * must hold the lock already. + */ + rel = estate->es_relations[rti] = heap_open(rte->relid, NoLock); + } + + return rel; +} +#endif + #endif /* EXECUTOR_H */ diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 41fa2052a2..127153b3be 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -20,6 +20,7 @@ #include "executor/instrument.h" #include "lib/pairingheap.h" #include "nodes/params.h" +#include "nodes/parsenodes.h" #include "nodes/plannodes.h" #include "utils/hsearch.h" #include "utils/queryenvironment.h" @@ -486,6 +487,12 @@ typedef struct EState /* If query can insert/delete tuples, the command ID to mark them with */ CommandId es_output_cid; + /* Array of RT entries indexed by their RT indexes. */ + RangeTblEntry **es_rtable_array; + + /* Relation pointers for all relations in es_range_table. */ + Relation *es_relations; + /* Info about target table(s) for insert/update/delete queries: */ ResultRelInfo *es_result_relations; /* array of ResultRelInfos */ int es_num_result_relations; /* length of array */ diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index a342edf49c..34f7de1f9d 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -1091,7 +1091,7 @@ typedef struct PartitionPruneInfo typedef struct PartitionedRelPruneInfo { NodeTag type; - Oid reloid; /* OID of partition rel for this level */ + Index rtindex; /* Table's RT index */ List *pruning_steps; /* List of PartitionPruneStep, see below */ Bitmapset *present_parts; /* Indexes of all partitions which subplans or * subparts are present for. */ -- 2.11.0