From 8a5b5f4212ee9089b8fbf500c6fc6c3feb717aa8 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Wed, 22 Jul 2015 15:07:29 +0900 Subject: [PATCH 1/3] Replace use of malloc by an internal memory context in pltcl This simplifies the code to not rely anymore on malloc() calls and removes an old tweak to cache function information in the top memory context of a backend. --- src/pl/tcl/pltcl.c | 82 +++++++++++------------------------------------------- 1 file changed, 17 insertions(+), 65 deletions(-) diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c index 48a3206..ef0e3fa 100644 --- a/src/pl/tcl/pltcl.c +++ b/src/pl/tcl/pltcl.c @@ -303,23 +303,6 @@ pltcl_WaitForEvent(CONST86 Tcl_Time *timePtr) /* - * This routine is a crock, and so is everyplace that calls it. The problem - * is that the cached form of pltcl functions/queries is allocated permanently - * (mostly via malloc()) and never released until backend exit. Subsidiary - * data structures such as fmgr info records therefore must live forever - * as well. A better implementation would store all this stuff in a per- - * function memory context that could be reclaimed at need. In the meantime, - * fmgr_info_cxt must be called specifying TopMemoryContext so that whatever - * it might allocate, and whatever the eventual function might allocate using - * fn_mcxt, will live forever too. - */ -static void -perm_fmgr_info(Oid functionId, FmgrInfo *finfo) -{ - fmgr_info_cxt(functionId, finfo, TopMemoryContext); -} - -/* * _PG_init() - library load-time initialization * * DO NOT make this static nor change its name! @@ -1222,12 +1205,14 @@ static pltcl_proc_desc * compile_pltcl_function(Oid fn_oid, Oid tgreloid, bool is_event_trigger, bool pltrusted) { + volatile MemoryContext plan_cxt = NULL; HeapTuple procTup; Form_pg_proc procStruct; pltcl_proc_key proc_key; pltcl_proc_ptr *proc_ptr; bool found; pltcl_proc_desc *prodesc; + MemoryContext oldcontext = CurrentMemoryContext; /* We'll need the pg_proc tuple in any case... */ procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(fn_oid)); @@ -1309,21 +1294,21 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, /************************************************************ * Allocate a new procedure description block + * + * struct prodesc and subsidiary data all live in plan_cxt. ************************************************************/ - prodesc = (pltcl_proc_desc *) malloc(sizeof(pltcl_proc_desc)); - if (prodesc == NULL) - ereport(ERROR, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); - MemSet(prodesc, 0, sizeof(pltcl_proc_desc)); - prodesc->user_proname = strdup(NameStr(procStruct->proname)); - prodesc->internal_proname = strdup(internal_proname); - if (prodesc->user_proname == NULL || prodesc->internal_proname == NULL) - ereport(ERROR, - (errcode(ERRCODE_OUT_OF_MEMORY), - errmsg("out of memory"))); + plan_cxt = AllocSetContextCreate(TopMemoryContext, + "PL/TCL compile", + ALLOCSET_SMALL_MINSIZE, + ALLOCSET_SMALL_INITSIZE, + ALLOCSET_SMALL_MAXSIZE); + MemoryContextSwitchTo(plan_cxt); + prodesc = (pltcl_proc_desc *) palloc0(sizeof(pltcl_proc_desc)); + prodesc->user_proname = pstrdup(NameStr(procStruct->proname)); + prodesc->internal_proname = pstrdup(internal_proname); prodesc->fn_xmin = HeapTupleHeaderGetRawXmin(procTup->t_data); prodesc->fn_tid = procTup->t_self; + MemoryContextSwitchTo(oldcontext); /* Remember if function is STABLE/IMMUTABLE */ prodesc->fn_readonly = @@ -1347,13 +1332,8 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, SearchSysCache1(TYPEOID, ObjectIdGetDatum(procStruct->prorettype)); if (!HeapTupleIsValid(typeTup)) - { - free(prodesc->user_proname); - free(prodesc->internal_proname); - free(prodesc); elog(ERROR, "cache lookup failed for type %u", procStruct->prorettype); - } typeStruct = (Form_pg_type) GETSTRUCT(typeTup); /* Disallow pseudotype result, except VOID */ @@ -1363,37 +1343,22 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, /* okay */ ; else if (procStruct->prorettype == TRIGGEROID || procStruct->prorettype == EVTTRIGGEROID) - { - free(prodesc->user_proname); - free(prodesc->internal_proname); - free(prodesc); ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("trigger functions can only be called as triggers"))); - } else - { - free(prodesc->user_proname); - free(prodesc->internal_proname); - free(prodesc); ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("PL/Tcl functions cannot return type %s", format_type_be(procStruct->prorettype)))); - } } if (typeStruct->typtype == TYPTYPE_COMPOSITE) - { - free(prodesc->user_proname); - free(prodesc->internal_proname); - free(prodesc); ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("PL/Tcl functions cannot return composite types"))); - } - perm_fmgr_info(typeStruct->typinput, &(prodesc->result_in_func)); + fmgr_info_cxt(typeStruct->typinput, &(prodesc->result_in_func), plan_cxt); prodesc->result_typioparam = getTypeIOParam(typeTup); ReleaseSysCache(typeTup); @@ -1412,26 +1377,16 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(procStruct->proargtypes.values[i])); if (!HeapTupleIsValid(typeTup)) - { - free(prodesc->user_proname); - free(prodesc->internal_proname); - free(prodesc); elog(ERROR, "cache lookup failed for type %u", procStruct->proargtypes.values[i]); - } typeStruct = (Form_pg_type) GETSTRUCT(typeTup); /* Disallow pseudotype argument */ if (typeStruct->typtype == TYPTYPE_PSEUDO) - { - free(prodesc->user_proname); - free(prodesc->internal_proname); - free(prodesc); ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("PL/Tcl functions cannot accept type %s", format_type_be(procStruct->proargtypes.values[i])))); - } if (typeStruct->typtype == TYPTYPE_COMPOSITE) { @@ -1441,8 +1396,8 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, else { prodesc->arg_is_rowtype[i] = false; - perm_fmgr_info(typeStruct->typoutput, - &(prodesc->arg_out_func[i])); + fmgr_info_cxt(typeStruct->typoutput, + &(prodesc->arg_out_func[i]), plan_cxt); snprintf(buf, sizeof(buf), "%d", i + 1); } @@ -1541,9 +1496,6 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid, Tcl_DStringFree(&proc_internal_def); if (tcl_rc != TCL_OK) { - free(prodesc->user_proname); - free(prodesc->internal_proname); - free(prodesc); UTF_BEGIN; elog(ERROR, "could not create internal procedure \"%s\": %s", internal_proname, UTF_U2E(Tcl_GetStringResult(interp))); -- 2.4.6