This is an updated version of the PL instrumentation plugin patch that I submitted on July-28.  The new version re-implements the plugin loader code to use "rendezvous variables" as suggested by Tom Lane (thanks Tom, very elegant design).

I have not implemented any support for unloading shared libraries.  Once we've finalized the design for rendezvous variables, I'll submit a separate documentation patch.

            -- Korry


--
  Korry Douglas    [EMAIL PROTECTED]
  EnterpriseDB      http://www.enterprisedb.com
Index: src/backend/tcop/postgres.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/tcop/postgres.c,v
retrieving revision 1.497
diff -w -c -r1.497 postgres.c
*** src/backend/tcop/postgres.c	10 Aug 2006 00:44:01 -0000	1.497
--- src/backend/tcop/postgres.c	11 Aug 2006 15:53:24 -0000
***************
*** 2976,2981 ****
--- 2976,2987 ----
  	BeginReportingGUCOptions();
  
  	/*
+ 	 * Load any shared-libraries indicated by the backend_load_libraries
+ 	 * GUC variable.
+ 	 */
+ 	process_backend_libraries();
+ 
+ 	/*
  	 * Also set up handler to log session end; we have to wait till now to be
  	 * sure Log_disconnections has its final value.
  	 */
Index: src/backend/utils/fmgr/dfmgr.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v
retrieving revision 1.87
diff -w -c -r1.87 dfmgr.c
*** src/backend/utils/fmgr/dfmgr.c	8 Aug 2006 19:15:08 -0000	1.87
--- src/backend/utils/fmgr/dfmgr.c	11 Aug 2006 15:53:26 -0000
***************
*** 23,34 ****
  #endif
  #include "miscadmin.h"
  #include "utils/dynamic_loader.h"
! 
  
  /* signatures for PostgreSQL-specific library init/fini functions */
  typedef void (*PG_init_t)(void);
  typedef void (*PG_fini_t)(void);
  
  /*
   * List of dynamically loaded files (kept in malloc'd memory).
   */
--- 23,40 ----
  #endif
  #include "miscadmin.h"
  #include "utils/dynamic_loader.h"
! #include "utils/hsearch.h"
  
  /* signatures for PostgreSQL-specific library init/fini functions */
  typedef void (*PG_init_t)(void);
  typedef void (*PG_fini_t)(void);
  
+ typedef struct
+ { 
+ 	char	varName[NAMEDATALEN];
+ 	void   *varValue;
+ } rendezvousHashEntry;
+ 
  /*
   * List of dynamically loaded files (kept in malloc'd memory).
   */
***************
*** 324,329 ****
--- 330,380 ----
  	return pg_dlsym(filehandle, funcname);
  }
  
+ /*
+  * Find (or create) a rendezvous variable that one dynamically 
+  * loaded library can use to meet up with another.
+  *
+  * When you first call this function, a simple variable is 
+  * created with the given name. The value of the variable is
+  * void pointer (initially set to NULL). The next time you 
+  * call find_rendezvous_variable() with the same name, you 
+  * get the address of the void pointer created by the first
+  * call.
+  *
+  * Dynamically loaded libraries can use rendezvous variables
+  * to find each other and share information (through the 
+  * void pointer).
+  */
+ void **
+ find_rendezvous_variable(const char *varName)
+ {
+ 	static HTAB         *rendezvousHash  = NULL;
+ 	char			     key[NAMEDATALEN] = {0};
+ 	rendezvousHashEntry *hentry;
+ 	bool				 found;
+ 
+ 	/* Create a variable hash if we haven't already done so */
+ 	if (rendezvousHash == NULL)
+ 	{
+ 		HASHCTL ctl;
+ 
+ 		ctl.keysize    = NAMEDATALEN;
+ 		ctl.entrysize  = sizeof(rendezvousHashEntry);
+ 		rendezvousHash = hash_create("Rendezvous variable hash", 5, &ctl, HASH_ELEM);
+ 
+ 		Assert(rendezvousHash != NULL);
+ 	}
+ 
+ 	/* Turn the varName into a fixed-size string */
+ 	snprintf(key, NAMEDATALEN, "%s", varName);
+ 
+ 	hentry = (rendezvousHashEntry *) hash_search(rendezvousHash, key, HASH_ENTER, &found);
+ 
+ 	if (!found)
+ 		hentry->varValue = NULL;
+ 
+ 	return &hentry->varValue;
+ }
  
  static bool
  file_exists(const char *name)
Index: src/backend/utils/init/miscinit.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/init/miscinit.c,v
retrieving revision 1.156
diff -w -c -r1.156 miscinit.c
*** src/backend/utils/init/miscinit.c	8 Aug 2006 19:15:08 -0000	1.156
--- src/backend/utils/init/miscinit.c	11 Aug 2006 15:53:30 -0000
***************
*** 1097,1120 ****
   *-------------------------------------------------------------------------
   */
  
! /* GUC variable: list of library names to be preloaded */
  char	   *preload_libraries_string = NULL;
  
  /*
!  * process any libraries that should be preloaded at postmaster start
   */
! void
! process_preload_libraries(void)
  {
  	char	   *rawstring;
  	List	   *elemlist;
  	ListCell   *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))
--- 1097,1126 ----
   *-------------------------------------------------------------------------
   */
  
! /* 
!  * GUC variables: list of library names to be preloaded, list of 
!  * library names to load into each backend
!  */
  char	   *preload_libraries_string = NULL;
+ char	   *backend_libraries_string = NULL;
  
  /*
!  * load the shared libraries listed in 'libraries', if something
!  * goes wrong, throw an error that indicates a problem loading 
!  * the libraries specified by 'gucname'
   */
! static void
! load_libraries(const char *libraries, const char *gucname)
  {
  	char	   *rawstring;
  	List	   *elemlist;
  	ListCell   *l;
  
! 	if (libraries == NULL)
  		return;
  
  	/* Need a modifiable copy of string */
! 	rawstring = pstrdup(libraries);
  
  	/* Parse string into list of identifiers */
  	if (!SplitIdentifierString(rawstring, ',', &elemlist))
***************
*** 1124,1130 ****
  		list_free(elemlist);
  		ereport(LOG,
  				(errcode(ERRCODE_SYNTAX_ERROR),
! 		 errmsg("invalid list syntax for parameter \"preload_libraries\"")));
  		return;
  	}
  
--- 1130,1136 ----
  		list_free(elemlist);
  		ereport(LOG,
  				(errcode(ERRCODE_SYNTAX_ERROR),
! 		 errmsg("invalid list syntax for parameter \"%s\"", gucname)));
  		return;
  	}
  
***************
*** 1137,1146 ****
  		canonicalize_path(filename);
  		(void) load_external_function(filename, NULL, true, NULL);
  		ereport(LOG,
! 				(errmsg("preloaded library \"%s\"", filename)));
  		pfree(filename);
  	}
  
  	pfree(rawstring);
  	list_free(elemlist);
  }
--- 1143,1170 ----
  		canonicalize_path(filename);
  		(void) load_external_function(filename, NULL, true, NULL);
  		ereport(LOG,
! 				(errmsg("%s \"%s\"", gucname, filename)));
  		pfree(filename);
  	}
  
  	pfree(rawstring);
  	list_free(elemlist);
  }
+ 
+ /*
+  * process any libraries that should be preloaded at postmaster start
+  */
+ void
+ process_preload_libraries(void)
+ {
+ 	load_libraries(preload_libraries_string, "preload_libraries");
+ }
+ 
+ /*
+  * process any libraries that should be preloaded at backend start
+  */
+ void
+ process_backend_libraries(void)
+ {
+ 	load_libraries(backend_libraries_string, "backend_load_libraries");
+ }
Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/misc/guc.c,v
retrieving revision 1.333
diff -w -c -r1.333 guc.c
*** src/backend/utils/misc/guc.c	29 Jul 2006 03:02:56 -0000	1.333
--- src/backend/utils/misc/guc.c	11 Aug 2006 15:53:41 -0000
***************
*** 1973,1978 ****
--- 1973,1989 ----
  		"", NULL, NULL
  	},
  
+ 
+ 	{
+ 		{"backend_load_libraries", PGC_POSTMASTER, RESOURCES_KERNEL,
+ 			gettext_noop("Lists shared libraries to load into each backend."),
+ 			NULL,
+ 			GUC_LIST_INPUT | GUC_LIST_QUOTE | GUC_SUPERUSER_ONLY
+ 		},
+ 		&backend_libraries_string,
+ 		"", NULL, NULL
+ 	},
+ 
  	{
  		{"regex_flavor", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
  			gettext_noop("Sets the regular expression \"flavor\"."),
Index: src/include/fmgr.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/fmgr.h,v
retrieving revision 1.45
diff -w -c -r1.45 fmgr.h
*** src/include/fmgr.h	31 May 2006 20:58:09 -0000	1.45
--- src/include/fmgr.h	11 Aug 2006 15:53:43 -0000
***************
*** 489,495 ****
  					   bool signalNotFound, void **filehandle);
  extern PGFunction lookup_external_function(void *filehandle, char *funcname);
  extern void load_file(char *filename);
! 
  
  /*
   * !!! OLD INTERFACE !!!
--- 489,495 ----
  					   bool signalNotFound, void **filehandle);
  extern PGFunction lookup_external_function(void *filehandle, char *funcname);
  extern void load_file(char *filename);
! extern void **find_rendezvous_variable(const char *varName);
  
  /*
   * !!! OLD INTERFACE !!!
Index: src/include/miscadmin.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/miscadmin.h,v
retrieving revision 1.187
diff -w -c -r1.187 miscadmin.h
*** src/include/miscadmin.h	8 Aug 2006 19:15:08 -0000	1.187
--- src/include/miscadmin.h	11 Aug 2006 15:53:45 -0000
***************
*** 308,314 ****
  /* in utils/init/miscinit.c */
  extern bool IgnoreSystemIndexes;
  extern char *preload_libraries_string;
! 
  extern void SetReindexProcessing(Oid heapOid, Oid indexOid);
  extern void ResetReindexProcessing(void);
  extern bool ReindexIsProcessingHeap(Oid heapOid);
--- 308,314 ----
  /* in utils/init/miscinit.c */
  extern bool IgnoreSystemIndexes;
  extern char *preload_libraries_string;
! extern char *backend_libraries_string;
  extern void SetReindexProcessing(Oid heapOid, Oid indexOid);
  extern void ResetReindexProcessing(void);
  extern bool ReindexIsProcessingHeap(Oid heapOid);
***************
*** 320,324 ****
--- 320,325 ----
  							 unsigned long id2);
  extern void ValidatePgVersion(const char *path);
  extern void process_preload_libraries(void);
+ extern void process_backend_libraries(void);
  
  #endif   /* MISCADMIN_H */
Index: src/pl/plpgsql/src/pl_exec.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v
retrieving revision 1.174
diff -w -c -r1.174 pl_exec.c
*** src/pl/plpgsql/src/pl_exec.c	13 Jul 2006 16:49:20 -0000	1.174
--- src/pl/plpgsql/src/pl_exec.c	11 Aug 2006 15:53:53 -0000
***************
*** 255,260 ****
--- 255,266 ----
  	exec_set_found(&estate, false);
  
  	/*
+ 	 * Let the instrumentation plugin peek at this function
+ 	 */
+ 	if (*plugin_ptr && (*plugin_ptr)->func_beg)
+ 		((*plugin_ptr)->func_beg)(&estate, func);
+ 
+ 	/*
  	 * Now call the toplevel block of statements
  	 */
  	estate.err_text = NULL;
***************
*** 389,394 ****
--- 395,407 ----
  		}
  	}
  
+ 	/*
+ 	 * Tell the (optional) plugin that we've finished executing this 
+ 	 * function
+ 	 */
+ 	if (*plugin_ptr && (*plugin_ptr)->func_end)
+ 		((*plugin_ptr)->func_end)(&estate, func);
+ 
  	/* Clean up any leftover temporary memory */
  	FreeExprContext(estate.eval_econtext);
  	estate.eval_econtext = NULL;
***************
*** 583,588 ****
--- 596,607 ----
  	exec_set_found(&estate, false);
  
  	/*
+ 	 * Let the instrumentation plugin peek at this function
+ 	 */
+ 	if (*plugin_ptr && (*plugin_ptr)->func_beg)
+ 		((*plugin_ptr)->func_beg)(&estate, func);
+ 
+ 	/*
  	 * Now call the toplevel block of statements
  	 */
  	estate.err_text = NULL;
***************
*** 635,640 ****
--- 654,666 ----
  		rettup = SPI_copytuple((HeapTuple) (estate.retval));
  	}
  
+ 	/*
+ 	 * Tell the (optional) plugin that we've finished executing this 
+ 	 * function
+ 	 */
+ 	if (*plugin_ptr && (*plugin_ptr)->func_end)
+ 		((*plugin_ptr)->func_end)(&estate, func);
+ 
  	/* Clean up any leftover temporary memory */
  	FreeExprContext(estate.eval_econtext);
  	estate.eval_econtext = NULL;
***************
*** 1039,1044 ****
--- 1065,1074 ----
  	save_estmt = estate->err_stmt;
  	estate->err_stmt = stmt;
  
+ 	/* Let the plugin know that we are about to execute this statement */
+ 	if (*plugin_ptr && (*plugin_ptr)->stmt_beg)
+ 		((*plugin_ptr)->stmt_beg)(estate, stmt);
+ 
  	CHECK_FOR_INTERRUPTS();
  
  	switch (stmt->cmd_type)
***************
*** 1130,1135 ****
--- 1160,1169 ----
  
  	estate->err_stmt = save_estmt;
  
+ 	/* Let the plugin know that we have finished executing this statement */
+ 	if (*plugin_ptr && (*plugin_ptr)->stmt_end)
+ 		((*plugin_ptr)->stmt_end)(estate, stmt);
+ 
  	return rc;
  }
  
***************
*** 2204,2209 ****
--- 2238,2252 ----
  	 * child of simple_eval_estate.
  	 */
  	estate->eval_econtext = CreateExprContext(simple_eval_estate);
+ 
+ 	/*
+ 	 * Let the plugin see this function before we initialize any
+ 	 * local PL/pgSQL variables - note that we also give the plugin
+ 	 * a few function pointers so it can call back into the executor
+ 	 * for doing things like variable assignments and stack traces
+ 	 */
+ 	if (*plugin_ptr && (*plugin_ptr)->func_setup)
+ 		((*plugin_ptr)->func_setup)(estate, func, plpgsql_exec_error_callback, exec_assign_expr);
  }
  
  /* ----------
Index: src/pl/plpgsql/src/pl_handler.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/pl/plpgsql/src/pl_handler.c,v
retrieving revision 1.30
diff -w -c -r1.30 pl_handler.c
*** src/pl/plpgsql/src/pl_handler.c	8 Aug 2006 19:15:09 -0000	1.30
--- src/pl/plpgsql/src/pl_handler.c	11 Aug 2006 15:53:53 -0000
***************
*** 28,33 ****
--- 28,34 ----
  
  PG_MODULE_MAGIC;
  
+ PLpgSQL_plugin **plugin_ptr = NULL;
  
  /*
   * _PG_init()			- library load-time initialization
***************
*** 46,51 ****
--- 47,57 ----
  	plpgsql_HashTableInit();
  	RegisterXactCallback(plpgsql_xact_cb, NULL);
  
+ 	/*
+ 	 * Try to rendezvous with any plugin that we may have loaded.
+ 	 */
+ 	plugin_ptr = (PLpgSQL_plugin **) find_rendezvous_variable("PLpgSQL_plugin");
+ 
  	inited = true;
  }
  
Index: src/pl/plpgsql/src/plpgsql.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v
retrieving revision 1.78
diff -w -c -r1.78 plpgsql.h
*** src/pl/plpgsql/src/plpgsql.h	8 Aug 2006 19:15:09 -0000	1.78
--- src/pl/plpgsql/src/plpgsql.h	11 Aug 2006 15:53:55 -0000
***************
*** 621,629 ****
--- 621,661 ----
  	PLpgSQL_function *err_func; /* current func */
  	PLpgSQL_stmt *err_stmt;		/* current stmt */
  	const char *err_text;		/* additional state info */
+ 	void       *plugin_info;	/* reserved for use by optional plugin */
  } PLpgSQL_execstate;
  
  
+ /*
+  * A PLpgSQL_plugin structure represents an instrumentation plugin.
+  * We keep one of these structures (in pl_handler) and initialize 
+  * it by loading a plugin (if desired). This structure is basically
+  * a collection of function pointers - at various points in pl_exec.c,
+  * we call those functions (if they are non-NULL) to give the plugin
+  * a chance to watch what we are doing.
+  *
+  *	func_setup is called when we start a function, before we've initialized
+  *  the local variables (that is, the PL/pgSQL variables defined by the 
+  *  function).
+  *
+  *  func_beg is called when we start a function, after we've initialized
+  *  the local variables
+  *
+  *  func_end is called at the end of a function
+  *
+  *  stmt_beg and stmt_end are called before and after (respectively) each
+  *  statement
+  */
+ 
+ typedef struct
+ {
+ 	void (*func_setup)(PLpgSQL_execstate * estate, PLpgSQL_function * func, void (*error_callback)(void *arg), void (*assign_expr)( PLpgSQL_execstate *estate, PLpgSQL_datum *target, PLpgSQL_expr *expr));
+ 	void (*func_beg)(PLpgSQL_execstate * estate, PLpgSQL_function * func);
+ 	void (*func_end)(PLpgSQL_execstate * estate, PLpgSQL_function * func);
+ 	void (*stmt_beg)(PLpgSQL_execstate * estate, PLpgSQL_stmt * stmt);
+ 	void (*stmt_end)(PLpgSQL_execstate * estate, PLpgSQL_stmt * stmt);
+ } PLpgSQL_plugin;
+ 
+ 
  /**********************************************************************
   * Global variable declarations
   **********************************************************************/
***************
*** 645,650 ****
--- 677,684 ----
  extern bool plpgsql_check_syntax;
  extern MemoryContext compile_tmp_cxt;
  
+ extern PLpgSQL_plugin ** plugin_ptr;
+ 
  /**********************************************************************
   * Function declarations
   **********************************************************************/
---------------------------(end of broadcast)---------------------------
TIP 4: Have you searched our list archives?

               http://archives.postgresql.org

Reply via email to