Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit84ad4b0

Browse files
committed
Reduce memory usage of targetlist SRFs.
Previously nodeProjectSet only released memory once per input tuple,rather than once per returned tuple. If the computation of anindividual returned tuple requires a lot of memory, that can lead toproblems.Instead change things so that the expression context can be reset onceper output tuple, which requires a new memory context to store SRFarguments in.This is a longstanding issue, but was hard to fix before 9.6, due tothe way tSRFs where evaluated. But it's fairly easy to fix now. Wecould backpatch this into 10, but given there've been fewc omplaintsthat doesn't seem worth the risk so far.Reported-By: Lucas FairchildAuthor: Andres Freund, per discussion with Tom LaneDiscussion:https://postgr.es/m/4514.1507318623@sss.pgh.pa.us
1 parent643c27e commit84ad4b0

File tree

4 files changed

+57
-8
lines changed

4 files changed

+57
-8
lines changed

‎src/backend/executor/execSRF.c

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -467,13 +467,16 @@ ExecInitFunctionResultSet(Expr *expr,
467467
* function itself. The argument expressions may not contain set-returning
468468
* functions (the planner is supposed to have separated evaluation for those).
469469
*
470-
* This should be called in a short-lived (per-tuple) context.
470+
* This should be called in a short-lived (per-tuple) context, argContext
471+
* needs to live until all rows have been returned (i.e. *isDone set to
472+
* ExprEndResult or ExprSingleResult).
471473
*
472474
* This is used by nodeProjectSet.c.
473475
*/
474476
Datum
475477
ExecMakeFunctionResultSet(SetExprState*fcache,
476478
ExprContext*econtext,
479+
MemoryContextargContext,
477480
bool*isNull,
478481
ExprDoneCond*isDone)
479482
{
@@ -497,8 +500,21 @@ ExecMakeFunctionResultSet(SetExprState *fcache,
497500
*/
498501
if (fcache->funcResultStore)
499502
{
500-
if (tuplestore_gettupleslot(fcache->funcResultStore, true, false,
501-
fcache->funcResultSlot))
503+
TupleTableSlot*slot=fcache->funcResultSlot;
504+
MemoryContextoldContext;
505+
boolfoundTup;
506+
507+
/*
508+
* Have to make sure tuple in slot lives long enough, otherwise
509+
* clearing the slot could end up trying to free something already
510+
* freed.
511+
*/
512+
oldContext=MemoryContextSwitchTo(slot->tts_mcxt);
513+
foundTup=tuplestore_gettupleslot(fcache->funcResultStore, true, false,
514+
fcache->funcResultSlot);
515+
MemoryContextSwitchTo(oldContext);
516+
517+
if (foundTup)
502518
{
503519
*isDone=ExprMultipleResult;
504520
if (fcache->funcReturnsTuple)
@@ -526,11 +542,20 @@ ExecMakeFunctionResultSet(SetExprState *fcache,
526542
* function manager. We skip the evaluation if it was already done in the
527543
* previous call (ie, we are continuing the evaluation of a set-valued
528544
* function). Otherwise, collect the current argument values into fcinfo.
545+
*
546+
* The arguments have to live in a context that lives at least until all
547+
* rows from this SRF have been returned, otherwise ValuePerCall SRFs
548+
* would reference freed memory after the first returned row.
529549
*/
530550
fcinfo=&fcache->fcinfo_data;
531551
arguments=fcache->args;
532552
if (!fcache->setArgsValid)
553+
{
554+
MemoryContextoldContext=MemoryContextSwitchTo(argContext);
555+
533556
ExecEvalFuncArgs(fcinfo,arguments,econtext);
557+
MemoryContextSwitchTo(oldContext);
558+
}
534559
else
535560
{
536561
/* Reset flag (we may set it again below) */

‎src/backend/executor/nodeProjectSet.c

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,13 @@ ExecProjectSet(PlanState *pstate)
5252

5353
econtext=node->ps.ps_ExprContext;
5454

55+
/*
56+
* Reset per-tuple context to free expression-evaluation storage allocated
57+
* for a potentially previously returned tuple. Note that the SRF argument
58+
* context has a different lifetime and is reset below.
59+
*/
60+
ResetExprContext(econtext);
61+
5562
/*
5663
* Check to see if we're still projecting out tuples from a previous scan
5764
* tuple (because there is a function-returning-set in the projection
@@ -66,11 +73,13 @@ ExecProjectSet(PlanState *pstate)
6673
}
6774

6875
/*
69-
* Reset per-tuple memory context to free any expression evaluation
70-
* storage allocated in the previous tuple cycle. Note this can't happen
71-
* until we're done projecting out tuples from a scan tuple.
76+
* Reset argument context to free any expression evaluation storage
77+
* allocated in the previous tuple cycle. Note this can't happen until
78+
* we're done projecting out tuples from a scan tuple, as ValuePerCall
79+
* functions are allowed to reference the arguments for each returned
80+
* tuple.
7281
*/
73-
ResetExprContext(econtext);
82+
MemoryContextReset(node->argcontext);
7483

7584
/*
7685
* Get another input tuple and project SRFs from it.
@@ -164,7 +173,8 @@ ExecProjectSRF(ProjectSetState *node, bool continuing)
164173
* Evaluate SRF - possibly continuing previously started output.
165174
*/
166175
*result=ExecMakeFunctionResultSet((SetExprState*)elem,
167-
econtext,isnull,isdone);
176+
econtext,node->argcontext,
177+
isnull,isdone);
168178

169179
if (*isdone!=ExprEndResult)
170180
hasresult= true;
@@ -291,6 +301,18 @@ ExecInitProjectSet(ProjectSet *node, EState *estate, int eflags)
291301
off++;
292302
}
293303

304+
305+
/*
306+
* Create a memory context that ExecMakeFunctionResult can use to evaluate
307+
* function arguments in. We can't use the per-tuple context for this
308+
* because it gets reset too often; but we don't want to leak evaluation
309+
* results into the query-lifespan context either. We use one context for
310+
* the arguments of all tSRFs, as they have roughly equivalent lifetimes.
311+
*/
312+
state->argcontext=AllocSetContextCreate(CurrentMemoryContext,
313+
"tSRF function arguments",
314+
ALLOCSET_DEFAULT_SIZES);
315+
294316
returnstate;
295317
}
296318

‎src/include/executor/executor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ extern SetExprState *ExecInitFunctionResultSet(Expr *expr,
400400
ExprContext*econtext,PlanState*parent);
401401
externDatumExecMakeFunctionResultSet(SetExprState*fcache,
402402
ExprContext*econtext,
403+
MemoryContextargContext,
403404
bool*isNull,
404405
ExprDoneCond*isDone);
405406

‎src/include/nodes/execnodes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,7 @@ typedef struct ProjectSetState
946946
ExprDoneCond*elemdone;/* array of per-SRF is-done states */
947947
intnelems;/* length of elemdone[] array */
948948
boolpending_srf_tuples;/* still evaluating srfs in tlist? */
949+
MemoryContextargcontext;/* context for SRF arguments */
949950
}ProjectSetState;
950951

951952
/* ----------------

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp