mirror of
https://github.com/postgres/postgres.git
synced 2025-04-20 00:42:27 +03:00
Split some storage out to separate subcontexts of fcontext.
Put the JunkFilter and its result slot (and thence also some subsidiary data such as the result tupledesc) into a separate subcontext "jfcontext". This doesn't accomplish a lot at this point, because we make a new JunkFilter each time through the SQL function. However, the plan is to make the fcontext long-lived, and that raises the possibility that we'll need a new JunkFilter because the plan for the result-generating query changes. A separate context makes it easy to free the obsoleted data when that happens. Also, instead of always running the sub-executor in fcontext, make a separate context for it if we're doing lazy eval of a SRF, and otherwise just run it inside CurrentMemoryContext.
This commit is contained in:
parent
595d1efeda
commit
f45a5444ee
@ -107,6 +107,8 @@ typedef struct execution_state
|
|||||||
* which we free at completion. In non-returnsSet mode, this is just a child
|
* which we free at completion. In non-returnsSet mode, this is just a child
|
||||||
* of the call-time context. In returnsSet mode, it is made a child of the
|
* of the call-time context. In returnsSet mode, it is made a child of the
|
||||||
* FmgrInfo's fn_mcxt so that it will survive between fmgr_sql calls.
|
* FmgrInfo's fn_mcxt so that it will survive between fmgr_sql calls.
|
||||||
|
* The fcontext may have subsidiary contexts jfcontext and/or subcontext,
|
||||||
|
* which have somewhat shorter lifespans.
|
||||||
*
|
*
|
||||||
* 3. SQLFunctionLink is a tiny struct that just holds pointers to
|
* 3. SQLFunctionLink is a tiny struct that just holds pointers to
|
||||||
* the SQLFunctionHashEntry and the current SQLFunctionCache (if any).
|
* the SQLFunctionHashEntry and the current SQLFunctionCache (if any).
|
||||||
@ -151,6 +153,7 @@ typedef struct SQLFunctionCache
|
|||||||
bool lazyEvalOK; /* true if lazyEval is safe */
|
bool lazyEvalOK; /* true if lazyEval is safe */
|
||||||
bool shutdown_reg; /* true if registered shutdown callback */
|
bool shutdown_reg; /* true if registered shutdown callback */
|
||||||
bool lazyEval; /* true if using lazyEval for result query */
|
bool lazyEval; /* true if using lazyEval for result query */
|
||||||
|
bool ownSubcontext; /* is subcontext really a separate context? */
|
||||||
|
|
||||||
ParamListInfo paramLI; /* Param list representing current args */
|
ParamListInfo paramLI; /* Param list representing current args */
|
||||||
|
|
||||||
@ -178,6 +181,9 @@ typedef struct SQLFunctionCache
|
|||||||
|
|
||||||
MemoryContext fcontext; /* memory context holding this struct and all
|
MemoryContext fcontext; /* memory context holding this struct and all
|
||||||
* subsidiary data */
|
* subsidiary data */
|
||||||
|
MemoryContext jfcontext; /* subsidiary memory context holding
|
||||||
|
* junkFilter, result slot, and related data */
|
||||||
|
MemoryContext subcontext; /* subsidiary memory context for sub-executor */
|
||||||
} SQLFunctionCache;
|
} SQLFunctionCache;
|
||||||
|
|
||||||
typedef SQLFunctionCache *SQLFunctionCachePtr;
|
typedef SQLFunctionCache *SQLFunctionCachePtr;
|
||||||
@ -617,8 +623,8 @@ init_sql_fcache(FunctionCallInfo fcinfo, bool lazyEvalOK)
|
|||||||
*/
|
*/
|
||||||
pcontext = func->returnsSet ? finfo->fn_mcxt : CurrentMemoryContext;
|
pcontext = func->returnsSet ? finfo->fn_mcxt : CurrentMemoryContext;
|
||||||
fcontext = AllocSetContextCreate(pcontext,
|
fcontext = AllocSetContextCreate(pcontext,
|
||||||
"SQL function execution",
|
"SQL function cache",
|
||||||
ALLOCSET_DEFAULT_SIZES);
|
ALLOCSET_SMALL_SIZES);
|
||||||
|
|
||||||
oldcontext = MemoryContextSwitchTo(fcontext);
|
oldcontext = MemoryContextSwitchTo(fcontext);
|
||||||
|
|
||||||
@ -791,6 +797,9 @@ init_execution_state(SQLFunctionCachePtr fcache)
|
|||||||
* nothing to coerce to. (XXX Frequently, the JunkFilter isn't doing
|
* nothing to coerce to. (XXX Frequently, the JunkFilter isn't doing
|
||||||
* anything very interesting, but much of this module expects it to be
|
* anything very interesting, but much of this module expects it to be
|
||||||
* there anyway.)
|
* there anyway.)
|
||||||
|
*
|
||||||
|
* The JunkFilter, its result slot, and its tupledesc are kept in a
|
||||||
|
* subsidiary memory context so that we can free them easily when needed.
|
||||||
*/
|
*/
|
||||||
if (fcache->func->rettype != VOIDOID)
|
if (fcache->func->rettype != VOIDOID)
|
||||||
{
|
{
|
||||||
@ -798,8 +807,14 @@ init_execution_state(SQLFunctionCachePtr fcache)
|
|||||||
List *resulttlist;
|
List *resulttlist;
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
/* The result slot and JunkFilter must be in the fcontext */
|
/* Create or reset the jfcontext */
|
||||||
oldcontext = MemoryContextSwitchTo(fcache->fcontext);
|
if (fcache->jfcontext == NULL)
|
||||||
|
fcache->jfcontext = AllocSetContextCreate(fcache->fcontext,
|
||||||
|
"SQL function junkfilter",
|
||||||
|
ALLOCSET_SMALL_SIZES);
|
||||||
|
else
|
||||||
|
MemoryContextReset(fcache->jfcontext);
|
||||||
|
oldcontext = MemoryContextSwitchTo(fcache->jfcontext);
|
||||||
|
|
||||||
slot = MakeSingleTupleTableSlot(NULL, &TTSOpsMinimalTuple);
|
slot = MakeSingleTupleTableSlot(NULL, &TTSOpsMinimalTuple);
|
||||||
|
|
||||||
@ -1265,14 +1280,46 @@ postquel_start(execution_state *es, SQLFunctionCachePtr fcache)
|
|||||||
Assert(ActiveSnapshotSet());
|
Assert(ActiveSnapshotSet());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Run the sub-executor in a child of fcontext. The sub-executor is
|
* In lazyEval mode for a SRF, we must run the sub-executor in a child of
|
||||||
* responsible for deleting per-tuple information. (XXX in the case of a
|
* fcontext, so that it can survive across multiple calls to fmgr_sql.
|
||||||
* long-lived FmgrInfo, this policy potentially causes memory leakage, but
|
* (XXX in the case of a long-lived FmgrInfo, this policy potentially
|
||||||
* it's not very clear where we could keep stuff instead. Fortunately,
|
* causes memory leakage, but it's not very clear where we could keep
|
||||||
* there are few if any cases where set-returning functions are invoked
|
* stuff instead. Fortunately, there are few if any cases where
|
||||||
* via FmgrInfos that would outlive the calling query.)
|
* set-returning functions are invoked via FmgrInfos that would outlive
|
||||||
|
* the calling query.) Otherwise, we're going to run it to completion
|
||||||
|
* before exiting fmgr_sql, so it can perfectly well run in the caller's
|
||||||
|
* context.
|
||||||
*/
|
*/
|
||||||
oldcontext = MemoryContextSwitchTo(fcache->fcontext);
|
if (es->lazyEval && fcache->func->returnsSet)
|
||||||
|
{
|
||||||
|
fcache->subcontext = AllocSetContextCreate(fcache->fcontext,
|
||||||
|
"SQL function execution",
|
||||||
|
ALLOCSET_DEFAULT_SIZES);
|
||||||
|
fcache->ownSubcontext = true;
|
||||||
|
}
|
||||||
|
else if (es->stmt->commandType == CMD_UTILITY)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The code path using a sub-executor is pretty good about cleaning up
|
||||||
|
* cruft, since the executor will make its own sub-context. We don't
|
||||||
|
* really need an additional layer of sub-context in that case.
|
||||||
|
* However, if this is a utility statement, it won't make its own
|
||||||
|
* sub-context, so it seems advisable to make one that we can free on
|
||||||
|
* completion.
|
||||||
|
*/
|
||||||
|
fcache->subcontext = AllocSetContextCreate(CurrentMemoryContext,
|
||||||
|
"SQL function execution",
|
||||||
|
ALLOCSET_DEFAULT_SIZES);
|
||||||
|
fcache->ownSubcontext = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fcache->subcontext = CurrentMemoryContext;
|
||||||
|
fcache->ownSubcontext = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Switch into the selected subcontext (might be a no-op) */
|
||||||
|
oldcontext = MemoryContextSwitchTo(fcache->subcontext);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this query produces the function result, send its output to the
|
* If this query produces the function result, send its output to the
|
||||||
@ -1335,8 +1382,8 @@ postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache)
|
|||||||
bool result;
|
bool result;
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
/* Run the sub-executor in a child of fcontext */
|
/* Run the sub-executor in subcontext */
|
||||||
oldcontext = MemoryContextSwitchTo(fcache->fcontext);
|
oldcontext = MemoryContextSwitchTo(fcache->subcontext);
|
||||||
|
|
||||||
if (es->qd->operation == CMD_UTILITY)
|
if (es->qd->operation == CMD_UTILITY)
|
||||||
{
|
{
|
||||||
@ -1375,8 +1422,8 @@ postquel_end(execution_state *es, SQLFunctionCachePtr fcache)
|
|||||||
{
|
{
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
/* Run the sub-executor in a child of fcontext */
|
/* Run the sub-executor in subcontext */
|
||||||
oldcontext = MemoryContextSwitchTo(fcache->fcontext);
|
oldcontext = MemoryContextSwitchTo(fcache->subcontext);
|
||||||
|
|
||||||
/* mark status done to ensure we don't do ExecutorEnd twice */
|
/* mark status done to ensure we don't do ExecutorEnd twice */
|
||||||
es->status = F_EXEC_DONE;
|
es->status = F_EXEC_DONE;
|
||||||
@ -1394,6 +1441,11 @@ postquel_end(execution_state *es, SQLFunctionCachePtr fcache)
|
|||||||
es->qd = NULL;
|
es->qd = NULL;
|
||||||
|
|
||||||
MemoryContextSwitchTo(oldcontext);
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
|
||||||
|
/* Delete the subcontext, if it's actually a separate context */
|
||||||
|
if (fcache->ownSubcontext)
|
||||||
|
MemoryContextDelete(fcache->subcontext);
|
||||||
|
fcache->subcontext = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user