1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-12 05:01:15 +03:00

Rearrange fmgr.c and relcache so that it's possible to keep FmgrInfo

lookup info in the relcache for index access method support functions.
This makes a huge difference for dynamically loaded support functions,
and should save a few cycles even for built-in ones.  Also tweak dfmgr.c
so that load_external_function is called only once, not twice, when
doing fmgr_info for a dynamically loaded function.  All per performance
gripe from Teodor Sigaev, 5-Oct-01.
This commit is contained in:
Tom Lane
2001-10-06 23:21:45 +00:00
parent a965750abf
commit 85801a4dbd
31 changed files with 424 additions and 390 deletions

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.52 2001/10/04 19:13:55 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.53 2001/10/06 23:21:44 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -55,14 +55,20 @@ static char * substitute_libpath_macro(const char * name);
/*
* Load the specified dynamic-link library file, and look for a function
* named funcname in it. If the function is not found, we raise an error
* if signalNotFound is true, else return (PGFunction) NULL. Note that
* errors in loading the library will provoke elog regardless of
* signalNotFound.
*/
* named funcname in it. (funcname can be NULL to just load the file.)
*
* If the function is not found, we raise an error if signalNotFound is true,
* else return (PGFunction) NULL. Note that errors in loading the library
* will provoke elog regardless of signalNotFound.
*
* If filehandle is not NULL, then *filehandle will be set to a handle
* identifying the library file. The filehandle can be used with
* lookup_external_function to lookup additional functions in the same file
* at less cost than repeating load_external_function.
*/
PGFunction
load_external_function(char *filename, char *funcname,
bool signalNotFound)
bool signalNotFound, void **filehandle)
{
DynamicFileList *file_scanner;
PGFunction retval;
@@ -130,6 +136,10 @@ load_external_function(char *filename, char *funcname,
file_tail = file_scanner;
}
/* Return handle if caller wants it. */
if (filehandle)
*filehandle = file_scanner->handle;
/*
* If funcname is NULL, we only wanted to load the file.
*/
@@ -201,11 +211,20 @@ load_file(char *filename)
}
}
load_external_function(fullname, (char *) NULL, false);
load_external_function(fullname, (char *) NULL, false, (void *) NULL);
pfree(fullname);
}
/*
* Lookup a function whose library file is already loaded.
* Return (PGFunction) NULL if not found.
*/
PGFunction
lookup_external_function(void *filehandle, char *funcname)
{
return pg_dlsym(filehandle, funcname);
}
static bool
@@ -305,7 +324,7 @@ substitute_libpath_macro(const char * name)
AssertArg(name != NULL);
if (strlen(name) == 0 || name[0] != '$')
if (name[0] != '$')
return pstrdup(name);
macroname_len = strcspn(name + 1, "/") + 1;

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.54 2001/08/14 22:21:58 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/fmgr/fmgr.c,v 1.55 2001/10/06 23:21:44 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -121,11 +121,21 @@ fmgr_lookupByName(const char *name)
* will be allocated in that context. The caller must ensure that this
* context is at least as long-lived as the info struct itself. This is
* not a problem in typical cases where the info struct is on the stack or
* in freshly-palloc'd space, but one must take extra care when the info
* struct is in a long-lived table.
* in freshly-palloc'd space. However, if one intends to store an info
* struct in a long-lived table, it's better to use fmgr_info_cxt.
*/
void
fmgr_info(Oid functionId, FmgrInfo *finfo)
{
fmgr_info_cxt(functionId, finfo, CurrentMemoryContext);
}
/*
* Fill a FmgrInfo struct, specifying a memory context in which its
* subsidiary data should go.
*/
void
fmgr_info_cxt(Oid functionId, FmgrInfo *finfo, MemoryContext mcxt)
{
const FmgrBuiltin *fbp;
HeapTuple procedureTuple;
@@ -139,7 +149,7 @@ fmgr_info(Oid functionId, FmgrInfo *finfo)
*/
finfo->fn_oid = InvalidOid;
finfo->fn_extra = NULL;
finfo->fn_mcxt = CurrentMemoryContext;
finfo->fn_mcxt = mcxt;
if ((fbp = fmgr_isbuiltin(functionId)) != NULL)
{
@@ -228,6 +238,7 @@ fmgr_info_C_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple)
probinattr;
char *prosrcstring,
*probinstring;
void *libraryhandle;
PGFunction user_fn;
Pg_finfo_record *inforec;
Oldstyle_fnextra *fnextra;
@@ -250,22 +261,19 @@ fmgr_info_C_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple)
probinstring = DatumGetCString(DirectFunctionCall1(textout, probinattr));
/* Look up the function itself */
user_fn = load_external_function(probinstring, prosrcstring, true);
user_fn = load_external_function(probinstring, prosrcstring, true,
&libraryhandle);
/* Get the function information record (real or default) */
inforec = fetch_finfo_record(probinstring, prosrcstring);
inforec = fetch_finfo_record(libraryhandle, prosrcstring);
switch (inforec->api_version)
{
case 0:
/* Old style: need to use a handler */
finfo->fn_addr = fmgr_oldstyle;
/*
* OK to use palloc here because fn_mcxt is
* CurrentMemoryContext
*/
fnextra = (Oldstyle_fnextra *) palloc(sizeof(Oldstyle_fnextra));
fnextra = (Oldstyle_fnextra *)
MemoryContextAlloc(finfo->fn_mcxt, sizeof(Oldstyle_fnextra));
finfo->fn_extra = (void *) fnextra;
MemSet(fnextra, 0, sizeof(Oldstyle_fnextra));
fnextra->func = (func_ptr) user_fn;
@@ -335,6 +343,8 @@ fmgr_info_other_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple)
/*
* Fetch and validate the information record for the given external function.
* The function is specified by a handle for the containing library
* (obtained from load_external_function) as well as the function name.
*
* If no info function exists for the given name, it is not an error.
* Instead we return a default info record for a version-0 function.
@@ -346,7 +356,7 @@ fmgr_info_other_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple)
* pg_proc.
*/
Pg_finfo_record *
fetch_finfo_record(char *filename, char *funcname)
fetch_finfo_record(void *filehandle, char *funcname)
{
char *infofuncname;
PGFInfoFunction infofunc;
@@ -355,12 +365,12 @@ fetch_finfo_record(char *filename, char *funcname)
/* Compute name of info func */
infofuncname = (char *) palloc(strlen(funcname) + 10);
sprintf(infofuncname, "pg_finfo_%s", funcname);
strcpy(infofuncname, "pg_finfo_");
strcat(infofuncname, funcname);
/* Try to look up the info function */
infofunc = (PGFInfoFunction) load_external_function(filename,
infofuncname,
false);
infofunc = (PGFInfoFunction) lookup_external_function(filehandle,
infofuncname);
if (infofunc == (PGFInfoFunction) NULL)
{
/* Not found --- assume version 0 */
@@ -391,6 +401,34 @@ fetch_finfo_record(char *filename, char *funcname)
}
/*
* Copy an FmgrInfo struct
*
* This is inherently somewhat bogus since we can't reliably duplicate
* language-dependent subsidiary info. We cheat by zeroing fn_extra,
* instead, meaning that subsidiary info will have to be recomputed.
*/
void
fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo,
MemoryContext destcxt)
{
memcpy(dstinfo, srcinfo, sizeof(FmgrInfo));
dstinfo->fn_mcxt = destcxt;
if (dstinfo->fn_addr == fmgr_oldstyle)
{
/* For oldstyle functions we must copy fn_extra */
Oldstyle_fnextra *fnextra;
fnextra = (Oldstyle_fnextra *)
MemoryContextAlloc(destcxt, sizeof(Oldstyle_fnextra));
memcpy(fnextra, srcinfo->fn_extra, sizeof(Oldstyle_fnextra));
dstinfo->fn_extra = (void *) fnextra;
}
else
dstinfo->fn_extra = NULL;
}
/*
* Specialized lookup routine for ProcedureCreate(): given the alleged name
* of an internal function, return the OID of the function.