v2-0001-estimate-selectivities-in-temp-context.patch
text/x-diff
Filename: v2-0001-estimate-selectivities-in-temp-context.patch
Type: text/x-diff
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v2-0001
| File | + | − |
|---|---|---|
| src/backend/optimizer/path/clausesel.c | 31 | 0 |
| src/backend/optimizer/plan/planner.c | 34 | 3 |
| src/backend/optimizer/prep/prepjointree.c | 1 | 1 |
| src/include/nodes/pathnodes.h | 13 | 1 |
diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c
index c949dc1866..4678c778b0 100644
--- a/src/backend/optimizer/path/clausesel.c
+++ b/src/backend/optimizer/path/clausesel.c
@@ -24,6 +24,7 @@
#include "statistics/statistics.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
+#include "utils/memutils.h"
#include "utils/selfuncs.h"
/*
@@ -693,6 +694,7 @@ clause_selectivity_ext(PlannerInfo *root,
Selectivity s1 = 0.5; /* default for any unhandled clause type */
RestrictInfo *rinfo = NULL;
bool cacheable = false;
+ MemoryContext saved_cxt;
if (clause == NULL) /* can this still happen? */
return s1;
@@ -756,6 +758,21 @@ clause_selectivity_ext(PlannerInfo *root,
clause = (Node *) rinfo->clause;
}
+ /*
+ * Run all the remaining work in the short-lived planner_tmp_cxt, which
+ * we'll reset at the bottom. This allows selectivity-related code to not
+ * be too concerned about leaking memory.
+ */
+ saved_cxt = MemoryContextSwitchTo(root->glob->planner_tmp_cxt);
+
+ /*
+ * This function can be called recursively, in which case we'd better not
+ * reset planner_tmp_cxt until we exit the topmost level. Use of
+ * planner_tmp_cxt_depth also makes it safe for other places to use and
+ * reset planner_tmp_cxt in the same fashion.
+ */
+ root->glob->planner_tmp_cxt_depth++;
+
if (IsA(clause, Var))
{
Var *var = (Var *) clause;
@@ -967,6 +984,20 @@ clause_selectivity_ext(PlannerInfo *root,
rinfo->outer_selec = s1;
}
+ /* Exit and optionally clean up the planner_tmp_cxt */
+ MemoryContextSwitchTo(saved_cxt);
+ root->glob->planner_tmp_cxt_usage++;
+ Assert(root->glob->planner_tmp_cxt_depth > 0);
+ if (--root->glob->planner_tmp_cxt_depth == 0)
+ {
+ /* It's safe to reset the tmp context, but do we want to? */
+ if (root->glob->planner_tmp_cxt_usage >= PLANNER_TMP_CXT_USAGE_RESET)
+ {
+ MemoryContextReset(root->glob->planner_tmp_cxt);
+ root->glob->planner_tmp_cxt_usage = 0;
+ }
+ }
+
#ifdef SELECTIVITY_DEBUG
elog(DEBUG4, "clause_selectivity: s1 %f", s1);
#endif /* SELECTIVITY_DEBUG */
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index be4e182869..df6a1fd330 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -307,6 +307,12 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
glob = makeNode(PlannerGlobal);
glob->boundParams = boundParams;
+ glob->planner_cxt = CurrentMemoryContext;
+ glob->planner_tmp_cxt = AllocSetContextCreate(glob->planner_cxt,
+ "Planner temp context",
+ ALLOCSET_DEFAULT_SIZES);
+ glob->planner_tmp_cxt_depth = 0;
+ glob->planner_tmp_cxt_usage = 0;
glob->subplans = NIL;
glob->subroots = NIL;
glob->rewindPlanIDs = NULL;
@@ -586,6 +592,9 @@ standard_planner(Query *parse, const char *query_string, int cursorOptions,
result->jitFlags |= PGJIT_DEFORM;
}
+ /* Clean up. We aren't very thorough here. */
+ MemoryContextDelete(glob->planner_tmp_cxt);
+
if (glob->partition_directory != NULL)
DestroyPartitionDirectory(glob->partition_directory);
@@ -642,7 +651,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
root->parent_root = parent_root;
root->plan_params = NIL;
root->outer_params = NULL;
- root->planner_cxt = CurrentMemoryContext;
+ root->planner_cxt = glob->planner_cxt;
root->init_plans = NIL;
root->cte_plan_ids = NIL;
root->multiexpr_params = NIL;
@@ -6509,11 +6518,18 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
glob = makeNode(PlannerGlobal);
+ glob->planner_cxt = CurrentMemoryContext;
+ glob->planner_tmp_cxt = AllocSetContextCreate(glob->planner_cxt,
+ "Planner temp context",
+ ALLOCSET_DEFAULT_SIZES);
+ glob->planner_tmp_cxt_depth = 0;
+ glob->planner_tmp_cxt_usage = 0;
+
root = makeNode(PlannerInfo);
root->parse = query;
root->glob = glob;
root->query_level = 1;
- root->planner_cxt = CurrentMemoryContext;
+ root->planner_cxt = glob->planner_cxt;
root->wt_param_id = -1;
root->join_domains = list_make1(makeNode(JoinDomain));
@@ -6552,7 +6568,10 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
* trust the index contents but use seqscan-and-sort.
*/
if (lc == NULL) /* not in the list? */
+ {
+ MemoryContextDelete(glob->planner_tmp_cxt);
return true; /* use sort */
+ }
/*
* Rather than doing all the pushups that would be needed to use
@@ -6584,6 +6603,9 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
ForwardScanDirection, false,
NULL, 1.0, false);
+ /* We assume this won't free *indexScanPath */
+ MemoryContextDelete(glob->planner_tmp_cxt);
+
return (seqScanAndSortPath.total_cost < indexScanPath->path.total_cost);
}
@@ -6631,11 +6653,18 @@ plan_create_index_workers(Oid tableOid, Oid indexOid)
glob = makeNode(PlannerGlobal);
+ glob->planner_cxt = CurrentMemoryContext;
+ glob->planner_tmp_cxt = AllocSetContextCreate(glob->planner_cxt,
+ "Planner temp context",
+ ALLOCSET_DEFAULT_SIZES);
+ glob->planner_tmp_cxt_depth = 0;
+ glob->planner_tmp_cxt_usage = 0;
+
root = makeNode(PlannerInfo);
root->parse = query;
root->glob = glob;
root->query_level = 1;
- root->planner_cxt = CurrentMemoryContext;
+ root->planner_cxt = glob->planner_cxt;
root->wt_param_id = -1;
root->join_domains = list_make1(makeNode(JoinDomain));
@@ -6725,6 +6754,8 @@ plan_create_index_workers(Oid tableOid, Oid indexOid)
parallel_workers--;
done:
+ MemoryContextDelete(glob->planner_tmp_cxt);
+
index_close(index, NoLock);
table_close(heap, NoLock);
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index aa83dd3636..6a36110df2 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -987,7 +987,7 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
subroot->parent_root = root->parent_root;
subroot->plan_params = NIL;
subroot->outer_params = NULL;
- subroot->planner_cxt = CurrentMemoryContext;
+ subroot->planner_cxt = root->planner_cxt;
subroot->init_plans = NIL;
subroot->cte_plan_ids = NIL;
subroot->multiexpr_params = NIL;
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 534692bee1..92f465c55e 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -101,6 +101,18 @@ typedef struct PlannerGlobal
/* Param values provided to planner() */
ParamListInfo boundParams pg_node_attr(read_write_ignore);
+ /* context holding PlannerGlobal */
+ MemoryContext planner_cxt pg_node_attr(read_write_ignore);
+
+ /* short-lived context for purposes such as calling selectivity functions */
+ MemoryContext planner_tmp_cxt pg_node_attr(read_write_ignore);
+ /* nesting depth of uses of planner_tmp_cxt; reset it only at level 0 */
+ int planner_tmp_cxt_depth;
+ /* how many times we've used planner_tmp_cxt since last reset */
+ int planner_tmp_cxt_usage;
+ /* how often we want to reset it */
+#define PLANNER_TMP_CXT_USAGE_RESET 10
+
/* Plans for SubPlan nodes */
List *subplans;
@@ -468,7 +480,7 @@ struct PlannerInfo
/* List of MinMaxAggInfos */
List *minmax_aggs;
- /* context holding PlannerInfo */
+ /* context holding PlannerInfo (copied from PlannerGlobal) */
MemoryContext planner_cxt pg_node_attr(read_write_ignore);
/* # of pages in all non-dummy tables of query */