From 15ce2d2e4a3e9ae70801a5caa07579200a66b510 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Thu, 20 Mar 2003 04:51:44 +0000 Subject: [PATCH] > I can see a couple possible downsides: (a) the library might have some > weird behavior across fork boundaries; (b) the additional memory space > that has to be duplicated into child processes will cost something per > child launch, even if the child never uses it. But these are only > arguments that it might not *always* be a prudent thing to do, not that > we shouldn't give the DBA the tool to do it if he wants. So fire away. Here is a patch for the above, including a documentation update. It creates a new GUC variable "preload_libraries", that accepts a list in the form: preload_libraries = '$libdir/mylib1:initfunc,$libdir/mylib2' If ":initfunc" is omitted or not found, no initialization function is executed, but the library is still preloaded. If "$libdir/mylib" isn't found, the postmaster refuses to start. In my testing with PL/R, it reduces the first call to a PL/R function (after connecting) from almost 2 seconds, down to about 8 ms. Joe Conway --- doc/src/sgml/runtime.sgml | 31 ++++++- src/backend/postmaster/postmaster.c | 11 ++- src/backend/utils/init/miscinit.c | 91 ++++++++++++++++++- src/backend/utils/misc/guc.c | 9 +- src/backend/utils/misc/postgresql.conf.sample | 1 + src/include/miscadmin.h | 3 +- 6 files changed, 141 insertions(+), 5 deletions(-) diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml index 408c81e2ee5..0f53895fdcd 100644 --- a/doc/src/sgml/runtime.sgml +++ b/doc/src/sgml/runtime.sgml @@ -1,5 +1,5 @@ @@ -1799,6 +1799,35 @@ dynamic_library_path = '/usr/local/lib/postgresql:/home/my_project/lib:$libdir' + + PRELOAD_LIBRARIES (string) + preload_libraries + + + This variable specifies one or more shared libraries that are to be + preloaded at Postmaster start. An initialization function can also be + optionally specified by adding a colon followed by the name of the + initialization function after the library name. For example + '$libdir/mylib:init_mylib' would cause mylib + to be preloaded and init_mylib to be executed. If more than + one library is to be loaded, they must be delimited with a comma. + + + + If mylib is not found, the postmaster will fail to start. + However, if init_mylib is not found, mylib will + still be preloaded without executing the initialization function. + + + + By preloading a shared library (and initializing it if applicable), + the library startup time is avoided when the library is used later in a + specific backend. However there is a cost in terms of memory duplication + as every backend is forked, whether or not the library is used. + + + + REGEX_FLAVOR (string) regular expressions diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 3ce63e05d63..13cc86e98c7 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -37,7 +37,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.307 2003/02/23 04:48:19 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/postmaster/postmaster.c,v 1.308 2003/03/20 04:51:44 momjian Exp $ * * NOTES * @@ -205,6 +205,8 @@ bool LogSourcePort; bool Log_connections = false; bool Db_user_namespace = false; +/* list of library:init-function to be preloaded */ +char *preload_libraries_string = NULL; /* Startup/shutdown state */ static pid_t StartupPID = 0, @@ -645,6 +647,13 @@ PostmasterMain(int argc, char *argv[]) secure_initialize(); #endif + /* + * process any libraries that should be preloaded and + * optionally pre-initialized + */ + if (preload_libraries_string) + process_preload_libraries(preload_libraries_string); + /* * Fork away from controlling terminal, if -S specified. * diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c index 12154396193..8b49ca2e584 100644 --- a/src/backend/utils/init/miscinit.c +++ b/src/backend/utils/init/miscinit.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.100 2003/01/27 00:51:06 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.101 2003/03/20 04:51:44 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -1044,3 +1044,92 @@ ValidatePgVersion(const char *path) "which is not compatible with this version %s.", file_major, file_minor, version_string); } + +/*------------------------------------------------------------------------- + * Library preload support + *------------------------------------------------------------------------- + */ + +#if defined(__mc68000__) && defined(__ELF__) +typedef int32 ((*func_ptr) ()); +#else +typedef char *((*func_ptr) ()); +#endif + +/* + * process any libraries that should be preloaded and + * optionally pre-initialized + */ +void +process_preload_libraries(char *preload_libraries_string) +{ + char *rawstring; + List *elemlist; + List *l; + + if (preload_libraries_string == NULL) + return; + + /* Need a modifiable copy of string */ + rawstring = pstrdup(preload_libraries_string); + + /* Parse string into list of identifiers */ + if (!SplitIdentifierString(rawstring, ',', &elemlist)) + { + /* syntax error in list */ + pfree(rawstring); + freeList(elemlist); + elog(LOG, "invalid list syntax for preload_libraries configuration option"); + } + + foreach(l, elemlist) + { + char *tok = (char *) lfirst(l); + char *sep = strstr(tok, ":"); + char *filename = NULL; + char *funcname = NULL; + func_ptr initfunc; + + if (sep) + { + /* + * a colon separator implies there is an initialization function + * that we need to run in addition to loading the library + */ + size_t filename_len = sep - tok; + size_t funcname_len = strlen(tok) - filename_len - 1; + + filename = (char *) palloc(filename_len + 1); + memset(filename, '\0', filename_len + 1); + snprintf(filename, filename_len + 1, "%s", tok); + + funcname = (char *) palloc(funcname_len + 1); + memset(funcname, '\0', funcname_len + 1); + snprintf(funcname, funcname_len + 1, "%s", sep + 1); + } + else + { + /* + * no separator -- just load the library + */ + filename = pstrdup(tok); + funcname = NULL; + } + + initfunc = (func_ptr) load_external_function(filename, funcname, false, NULL); + if (initfunc) + (*initfunc)(); + + elog(LOG, "preloaded library %s with initialization function %s", filename, funcname); + + if (filename != NULL) + pfree(filename); + + if (funcname != NULL) + pfree(funcname); + } + + pfree(rawstring); + freeList(elemlist); +} + diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 37e1192b6d0..7c5d6d18849 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -5,7 +5,7 @@ * command, configuration file, and command line options. * See src/backend/utils/misc/README for more information. * - * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.116 2003/03/04 21:51:21 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.117 2003/03/20 04:51:44 momjian Exp $ * * Copyright 2000 by PostgreSQL Global Development Group * Written by Peter Eisentraut . @@ -60,6 +60,7 @@ extern int CheckPointTimeout; extern bool autocommit; extern int CommitDelay; extern int CommitSiblings; +extern char *preload_libraries_string; #ifdef HAVE_SYSLOG extern char *Syslog_facility; @@ -814,6 +815,12 @@ static struct config_string "C", locale_time_assign, NULL }, + { + {"preload_libraries", PGC_POSTMASTER, GUC_LIST_INPUT | GUC_LIST_QUOTE}, + &preload_libraries_string, + "", NULL, NULL + }, + { {"regex_flavor", PGC_USERSET}, ®ex_flavor_string, "advanced", assign_regex_flavor, NULL diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 40b143c7cab..c290df19d99 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -214,4 +214,5 @@ #transform_null_equals = false #statement_timeout = 0 # 0 is disabled, in milliseconds #db_user_namespace = false +#preload_libraries = '' diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index f8321325f6c..e44d0fbad30 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -12,7 +12,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: miscadmin.h,v 1.116 2003/02/22 05:57:45 tgl Exp $ + * $Id: miscadmin.h,v 1.117 2003/03/20 04:51:44 momjian Exp $ * * NOTES * some of the information in this file should be moved to @@ -288,6 +288,7 @@ extern void RecordSharedMemoryInLockFile(unsigned long id1, unsigned long id2); extern void ValidatePgVersion(const char *path); +extern void process_preload_libraries(char *preload_libraries_string); /* these externs do not belong here... */ extern void IgnoreSystemIndexes(bool mode);