Attached is a patch that fixes the SRF memory leaks I recently reported
on -hackers[1]. The patch creates a distinct memory context for the
SRF's "multi_call_memory_ctx", and then deletes that context when the
SRF finishes. This ensures that any user allocations made in this
context are reclaimed. The patch also frees a TupleDesc that was leaked
in the per-query context when nodeFunctionscan was rescanned. Along the
way, it also fixes a leak in shutdown_MultiFuncCall() ("attinmeta" was
freed, but its palloc'd fields were not.)
It would be possible to allocate the TupleDesc in the multi-call memory
context, but it doesn't seem worth bothering about to me (since it would
require passing the context from the RSI down to the FuncCallContext). I
also didn't try to have multiple SRFs in the same subquery block use the
same context -- that seems like a lot of pain for little gain.
Comments welcome -- I think this fix should be applied to back branches.
-Neil
[1] http://markmail.org/message/45hekjinzl3e5i6q
Index: source/src/backend/executor/nodeFunctionscan.c
===================================================================
RCS file: /home/neilc/postgres/cvs_root/pgsql/src/backend/executor/nodeFunctionscan.c,v
retrieving revision 1.45
diff -p -c -r1.45 nodeFunctionscan.c
*** source/src/backend/executor/nodeFunctionscan.c 1 Jan 2008 19:45:49 -0000 1.45
--- source/src/backend/executor/nodeFunctionscan.c 25 Feb 2008 19:45:40 -0000
*************** FunctionNext(FunctionScanState *node)
*** 77,83 ****
--- 77,86 ----
* do it always.
*/
if (funcTupdesc)
+ {
tupledesc_match(node->tupdesc, funcTupdesc);
+ FreeTupleDesc(funcTupdesc);
+ }
}
/*
Index: source/src/backend/utils/fmgr/funcapi.c
===================================================================
RCS file: /home/neilc/postgres/cvs_root/pgsql/src/backend/utils/fmgr/funcapi.c,v
retrieving revision 1.37
diff -p -c -r1.37 funcapi.c
*** source/src/backend/utils/fmgr/funcapi.c 1 Jan 2008 19:45:53 -0000 1.37
--- source/src/backend/utils/fmgr/funcapi.c 25 Feb 2008 20:09:34 -0000
***************
*** 23,28 ****
--- 23,29 ----
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
+ #include "utils/memutils.h"
#include "utils/syscache.h"
#include "utils/typcache.h"
*************** init_MultiFuncCall(PG_FUNCTION_ARGS)
*** 63,75 ****
/*
* First call
*/
! ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
/*
* Allocate suitably long-lived space and zero it
*/
retval = (FuncCallContext *)
! MemoryContextAllocZero(fcinfo->flinfo->fn_mcxt,
sizeof(FuncCallContext));
/*
--- 64,86 ----
/*
* First call
*/
! ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
! MemoryContext multi_call_ctx;
!
! /*
! * Create a suitably long-lived context to hold cross-call data
! */
! multi_call_ctx = AllocSetContextCreate(fcinfo->flinfo->fn_mcxt,
! "SRF multi-call context",
! ALLOCSET_SMALL_MINSIZE,
! ALLOCSET_SMALL_INITSIZE,
! ALLOCSET_SMALL_MAXSIZE);
/*
* Allocate suitably long-lived space and zero it
*/
retval = (FuncCallContext *)
! MemoryContextAllocZero(multi_call_ctx,
sizeof(FuncCallContext));
/*
*************** init_MultiFuncCall(PG_FUNCTION_ARGS)
*** 81,87 ****
retval->user_fctx = NULL;
retval->attinmeta = NULL;
retval->tuple_desc = NULL;
! retval->multi_call_memory_ctx = fcinfo->flinfo->fn_mcxt;
/*
* save the pointer for cross-call use
--- 92,98 ----
retval->user_fctx = NULL;
retval->attinmeta = NULL;
retval->tuple_desc = NULL;
! retval->multi_call_memory_ctx = multi_call_ctx;
/*
* save the pointer for cross-call use
*************** shutdown_MultiFuncCall(Datum arg)
*** 168,180 ****
flinfo->fn_extra = NULL;
/*
! * Caller is responsible to free up memory for individual struct elements
! * other than att_in_funcinfo and elements.
*/
! if (funcctx->attinmeta != NULL)
! pfree(funcctx->attinmeta);
!
! pfree(funcctx);
}
--- 179,188 ----
flinfo->fn_extra = NULL;
/*
! * Delete context that holds all multi-call data, including the
! * FuncCallContext itself
*/
! MemoryContextDelete(funcctx->multi_call_memory_ctx);
}
---------------------------(end of broadcast)---------------------------
TIP 4: Have you searched our list archives?
http://archives.postgresql.org