Loading the PL/pgSQL debugger (and other plugins)

Lists: pgsql-hackers
From: korry <korryd(at)enterprisedb(dot)com>
To: pgsql-hackers(at)postgresql(dot)org
Subject: Loading the PL/pgSQL debugger (and other plugins)
Date: 2006-07-19 15:59:35
Message-ID: BAY101-DAV2A04597B2B11BEED0FF97D6600@phx.gbl
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

I'm working on a patch that implements the PL/pgSQL instrumentation
stuff (i.e. the PL/pgSQL debugger) that I discussed at the Anniversary
Summit and I need some opinions (this seems like a good place to look
for opinions :-)

A quick review: the PL/pgSQL debugger is designed as an optional
"plugin" that loads into the PL/pgSQL interpreter on-demand. You can
use the plugin idea to implement other kinds of instrumentation (I
demo'ed a tracer and a profiler at the conference, along with a
debugger). A plugin architecture greatly reduces the (source code)
footprint that would normally be required to implement a full-featured
debugger.

A plugin is basically a structure that contains a few function
pointers. If those function pointers are NULL, the PL/pgSQL interpreter
works exactly the way it does today. If any of those function pointers
are non-NULL, the PL/pgSQL interpreter calls the target function (which
points to a chunk of code inside of the plugin) and the plugin does
whatever it needs to do.

Right now, the plugin structure looks like this:

typedef struct
{
void (*init)( estate, func, error_callback, assign_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;

I've truncated the argument list (in this e-mail) for the (*init)()
function since it's rather long (error_callback and assign_expr are both
function pointers).

When the PL/pgSQL intrepreter loads the plugin, it calls the
plugin->init() function.
When the PL/pgSQL intrepreter starts running a new function, it calls
the plugin->func_beg() function.
When the PL/pgSQL intrepreter completes a function, it calls the
plugin->func_end() function.
When the PL/pgSQL interpreter is about to execute a line of PL/pgSQL
code, it calls plugin->stmt_beg()
When the PL/pgSQL interpreter has finished executing a line of PL/pgSQL
code, it calls plugin->stmt_end()

So here is where I need a few opinions:

1) I think the most straightforward way to load an instrumentation
plugin is to define a new custom GUC variable (using the
custom_variable_classes mechanism). When the PL/pgSQL call-handler
loads, it can check that config. variable (something like plpgsql.plugin
= '$libdir/plugin_profiler' or plpgsql.plugin =
'$libdir/plugin_debugger') and load the plugin if non-NULL. That seems
a little obtuse to me since custom variables don't appear in the
prototype postgresql.conf file. Would it be better to add a real GUC
variable instead of a custom variable?

2) Given that plpgsql.plugin points to the name of a shared-object file
(or DLL or whatever you prefer to call it), we need to find *something*
inside of the file. The most obvious choice would be to look for a
variable (a structure or structure pointer) with a fixed name. That
would mean, for example, that a plugin would define an externally
visible PLpgSQL_plugin structure named "plugin_hooks" and the PL/pgSQL
interpreter would look for that symbol inside of the plugin.
Alternatively, we could look for a function inside of the plugin
(something like 'plugin_loader') and then call that function with a
pointer to a PLpgSQL_plugin structure. I prefer the function-pointer
approach since we already have a reliable mechanism in place for finding
a function inside of a shared-object (the same mechanism works for
finding a variable instead of a function pointer, but I doubt that that
has been tested in all platforms).

3) Any comments on the PLpgSQL_plugin structure? Should it include (as
it's first member) a structure version number so we can add to/change
the structure as needed?

4) Do we need to support multiple active plugins? Would you ever need
to load the debugger at the same time you've loaded the profiler (no)?
Would you ever need to load the tracer at the same time you need the
debugger (probably not)? If we need to support multiple plugins, should
be just introduce a meta-plugin that knows how to handle a list of other
plugins? (Messy, but certainly gets the job done without worrying about
it right now).

5) I'll also be adding a void pointer to the PLpgSQL_execstate structure
(think of a PLpgSQL_execstate as a stack frame). The new pointer is
reserved for use by the plugin. It may be handy to add a void pointer
to each PLpgSQL_stmt as well - is that acceptable? (That would mean an
extra 4-bytes per-line of compiled PL/pgSQL code, even if you don't have
a plugin loaded).

Any other comments? Obviously, you'll have a chance to critique the
patch when I get it sent in.

Thanks for your help.

-- Korry


From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: korry <korryd(at)enterprisedb(dot)com>
Cc: pgsql-hackers(at)postgresql(dot)org
Subject: Re: Loading the PL/pgSQL debugger (and other plugins)
Date: 2006-07-19 17:35:16
Message-ID: 14284.1153330516@sss.pgh.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

korry <korryd(at)enterprisedb(dot)com> writes:
> I'm working on a patch that implements the PL/pgSQL instrumentation
> stuff (i.e. the PL/pgSQL debugger) that I discussed at the Anniversary
> Summit and I need some opinions (this seems like a good place to look
> for opinions :-)

Opinions R US ;-)

> 1) I think the most straightforward way to load an instrumentation
> plugin is to define a new custom GUC variable (using the
> custom_variable_classes mechanism).

This seems a bit messy and special-purpose. I see no good reason to tie
it to plpgsql; we'll just need another one for every other language.
IMHO what we want is something with similar properties to preload_libraries,
but processed on a per-backend basis instead of once at postmaster start.
(You could almost just tell people to select the plugin they want by
LOADing it, but that is hard to use if you're trying to debug a
non-interactive application. A GUC variable can be set for an app
without much cooperation from the app.)

When the plugin's shared library gets loaded, one way or the other,
it should construct the function-pointer struct and then pass it to a
function defined by plpgsql (this lets us hide/postpone the decision
about whether there can be more than one active plugin).

One issue that needs to be thought about with either this proposal or
your original is what permissions are needed to set the GUC variable.
I don't think we dare allow non-superusers to specify LOADing of
arbitrary shared libraries, so there has to be some filter function.

Perhaps a better way is that the GUC variable specifies a (list of)
initialization functions to call at backend start, and then the
superuserness is involved with installing the init functions into
pg_proc, and the GUC variable itself needs no special permissions.
Again, a plugin's init function would just register its function-pointer
struct with plpgsql.

We should also think about a deregistration function. This would allow
you to turn debugging on and off within an interactive session. The
GUC variable is really only for coercing non-interactive applications
into being debuggable --- I don't see it as being important for
interactive debugging, as compared to just "select plugin_init();" ...

> 3) Any comments on the PLpgSQL_plugin structure? Should it include (as
> it's first member) a structure version number so we can add to/change
> the structure as needed?

Given our current plans for enforcing recompiles at major version
changes (via magic-block checking), I'm not sure I see a need for this.

> 4) Do we need to support multiple active plugins?

Probably, but let's fix the API to hide this, so we don't have to commit
now.

regards, tom lane


From: korry <korryd(at)enterprisedb(dot)com>
To: pgsql-hackers(at)postgresql(dot)org
Subject: Re: Loading the PL/pgSQL debugger (and other plugins)
Date: 2006-07-19 18:44:30
Message-ID: BAY101-DAV11D7ED420DAB1D575A8C1CD6600@phx.gbl
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

Thanks for the quick feedback.
>> 1) I think the most straightforward way to load an instrumentation
>> plugin is to define a new custom GUC variable (using the
>> custom_variable_classes mechanism).
>>
>
> This seems a bit messy and special-purpose.
Agreed, I'm not crazy about using a custom_variable_class variable either.
> I see no good reason to tie
> it to plpgsql; we'll just need another one for every other language.
>
Hmmm... but the plugins themselves would be language-specific. I can't
imagine that a plugin (say a profiler) for PL/python would work for
PL/pgSQL. It seems to me that, even if we come up with a common
mechanism, we'll still need a separate GUC variable *name* for each PL.
Or am I not understanding something? Can you post an example of what
you are thinking (what would such a GUC variable look like)?

> IMHO what we want is something with similar properties to preload_libraries,
> but processed on a per-backend basis instead of once at postmaster start.
> (You could almost just tell people to select the plugin they want by
> LOADing it, but that is hard to use if you're trying to debug a
> non-interactive application. A GUC variable can be set for an app
> without much cooperation from the app.)
>
Agreed.
> When the plugin's shared library gets loaded, one way or the other,
> it should construct the function-pointer struct and then pass it to a
> function defined by plpgsql (this lets us hide/postpone the decision
> about whether there can be more than one active plugin).
>
But there's a timing issue there. If you ask the plugin to call a
call-handler function, then you can't load the plugin at backend startup
because the PL/pgSQL call-handler isn't loaded until it's required.
Since both the plugin and the call-handler are dynamically loaded, I
think one of them has to load the other. We already have a mechanism
for loading call-handlers on demand - it seems kind of messy to
introduce another mechanism for loading plugins (that in turn load the
call-handlers).

The PL/pgSQL call-handler has a convenient initialization function that
could read the GUC variable and load the referenced plugin (that's what
I'm doing right now).

What I'm thinking is that the plpgsql_init() function would look
something like this (my changes in red);

PLpgSQL_plugin pluginHooks;
typedef void (*plugin_loader_func)(PLpgSQL_plugin *hooks);

void
plpgsql_init(void)
{
static char * pluginName;
plugin_load_func plugin_loader();

/* Do initialization only once */
if (!plpgsql_firstcall)
return;

plpgsql_HashTableInit();
RegisterXactCallback(plpgsql_xact_cb, NULL);
plpgsql_firstcall = false;

/* Load any instrumentation plugins */
DefineCustomStringVariable( "plpgsql.plugin",
"Name of instrumentation plugin to use
when PL/pgSQL function is invoked",
NULL,
&pluginName,
PGC_USERSET,
NULL,
NULL );

EmitWarningsOnPlaceholders("plpgsql");

if (pluginName )
{
plugin_loader = (plugin_loader_func
*)load_external_function(pluginName, "plugin_loader", false, NULL );

if (plugin_loader)
(*plugin_loader)(&pluginHooks);
}
}

(Ignore the custom variable stuff for now)

Each plugin would export a plugin_loader() function - that function,
given a pointer to a PLpgSQL_plugin structure, would fill in that
structure with the required function pointers.
> One issue that needs to be thought about with either this proposal or
> your original is what permissions are needed to set the GUC variable.
> I don't think we dare allow non-superusers to specify LOADing of
> arbitrary shared libraries, so there has to be some filter function.
>
> Perhaps a better way is that the GUC variable specifies a (list of)
> initialization functions to call at backend start, and then the
> superuserness is involved with installing the init functions into
> pg_proc, and the GUC variable itself needs no special permissions.
> Again, a plugin's init function would just register its function-pointer
> struct with plpgsql.
>
You're right, privileges are an issue. Is it safe enough if we force
all plugins to reside in $libdir? Each plugin could enforce additional
security as needed that way, but you'd have to hold enough privileges to
get your plugin into $libdir to begin with so you can't write your own
nasty plugin to gain more privileges than you ought to have.
> We should also think about a deregistration function. This would allow
> you to turn debugging on and off within an interactive session. The
> GUC variable is really only for coercing non-interactive applications
> into being debuggable --- I don't see it as being important for
> interactive debugging, as compared to just "select plugin_init();" ...
>
Ok.
>> 3) Any comments on the PLpgSQL_plugin structure? Should it include (as
>> it's first member) a structure version number so we can add to/change
>> the structure as needed?
>>
>
> Given our current plans for enforcing recompiles at major version
> changes (via magic-block checking), I'm not sure I see a need for this.
>
That makes a lot more sense - I don't like the idea of each plugin
managing its own version information. We can always add more function
pointers to the end of the plugin structure - if the pointers are
non-NULL, you gain more functionality.
>> 4) Do we need to support multiple active plugins?
>>
>
> Probably, but let's fix the API to hide this, so we don't have to commit
> now.
>
Cool.

-- Korry


From: korry <korryd(at)enterprisedb(dot)com>
To: pgsql-hackers(at)postgresql(dot)org
Cc: tgl(at)sss(dot)pgh(dot)pa(dot)us
Subject: Re: Loading the PL/pgSQL debugger (and other plugins)
Date: 2006-07-21 16:51:55
Message-ID: BAY101-DAV7D3951D570453B94F1F5CD6660@phx.gbl
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

Sorry to poke - but I'd like to get a patch submitted next week. Any
more comments? Thanks.

-- Korry

> Thanks for the quick feedback.
>>> 1) I think the most straightforward way to load an instrumentation
>>> plugin is to define a new custom GUC variable (using the
>>> custom_variable_classes mechanism).
>>>
>>
>> This seems a bit messy and special-purpose.
> Agreed, I'm not crazy about using a custom_variable_class variable either.
>> I see no good reason to tie
>> it to plpgsql; we'll just need another one for every other language.
>>
> Hmmm... but the plugins themselves would be language-specific. I
> can't imagine that a plugin (say a profiler) for PL/python would work
> for PL/pgSQL. It seems to me that, even if we come up with a common
> mechanism, we'll still need a separate GUC variable *name* for each
> PL. Or am I not understanding something? Can you post an example of
> what you are thinking (what would such a GUC variable look like)?
>
>> IMHO what we want is something with similar properties to preload_libraries,
>> but processed on a per-backend basis instead of once at postmaster start.
>> (You could almost just tell people to select the plugin they want by
>> LOADing it, but that is hard to use if you're trying to debug a
>> non-interactive application. A GUC variable can be set for an app
>> without much cooperation from the app.)
>>
> Agreed.
>> When the plugin's shared library gets loaded, one way or the other,
>> it should construct the function-pointer struct and then pass it to a
>> function defined by plpgsql (this lets us hide/postpone the decision
>> about whether there can be more than one active plugin).
>>
> But there's a timing issue there. If you ask the plugin to call a
> call-handler function, then you can't load the plugin at backend
> startup because the PL/pgSQL call-handler isn't loaded until it's
> required. Since both the plugin and the call-handler are dynamically
> loaded, I think one of them has to load the other. We already have a
> mechanism for loading call-handlers on demand - it seems kind of messy
> to introduce another mechanism for loading plugins (that in turn load
> the call-handlers).
>
> The PL/pgSQL call-handler has a convenient initialization function
> that could read the GUC variable and load the referenced plugin
> (that's what I'm doing right now).
>
> What I'm thinking is that the plpgsql_init() function would look
> something like this (my changes in red);
>
> PLpgSQL_plugin pluginHooks;
> typedef void (*plugin_loader_func)(PLpgSQL_plugin *hooks);
>
> void
> plpgsql_init(void)
> {
> static char * pluginName;
> plugin_load_func plugin_loader();
>
> /* Do initialization only once */
> if (!plpgsql_firstcall)
> return;
>
> plpgsql_HashTableInit();
> RegisterXactCallback(plpgsql_xact_cb, NULL);
> plpgsql_firstcall = false;
>
> /* Load any instrumentation plugins */
> DefineCustomStringVariable( "plpgsql.plugin",
> "Name of instrumentation plugin to use
> when PL/pgSQL function is invoked",
> NULL,
> &pluginName,
> PGC_USERSET,
> NULL,
> NULL );
>
> EmitWarningsOnPlaceholders("plpgsql");
>
> if (pluginName )
> {
> plugin_loader = (plugin_loader_func
> *)load_external_function(pluginName, "plugin_loader", false, NULL );
>
> if (plugin_loader)
> (*plugin_loader)(&pluginHooks);
> }
> }
>
> (Ignore the custom variable stuff for now)
>
> Each plugin would export a plugin_loader() function - that function,
> given a pointer to a PLpgSQL_plugin structure, would fill in that
> structure with the required function pointers.
>> One issue that needs to be thought about with either this proposal or
>> your original is what permissions are needed to set the GUC variable.
>> I don't think we dare allow non-superusers to specify LOADing of
>> arbitrary shared libraries, so there has to be some filter function.
>>
>> Perhaps a better way is that the GUC variable specifies a (list of)
>> initialization functions to call at backend start, and then the
>> superuserness is involved with installing the init functions into
>> pg_proc, and the GUC variable itself needs no special permissions.
>> Again, a plugin's init function would just register its function-pointer
>> struct with plpgsql.
>>
> You're right, privileges are an issue. Is it safe enough if we force
> all plugins to reside in $libdir? Each plugin could enforce
> additional security as needed that way, but you'd have to hold enough
> privileges to get your plugin into $libdir to begin with so you can't
> write your own nasty plugin to gain more privileges than you ought to
> have.
>> We should also think about a deregistration function. This would allow
>> you to turn debugging on and off within an interactive session. The
>> GUC variable is really only for coercing non-interactive applications
>> into being debuggable --- I don't see it as being important for
>> interactive debugging, as compared to just "select plugin_init();" ...
>>
> Ok.
>>> 3) Any comments on the PLpgSQL_plugin structure? Should it include (as
>>> it's first member) a structure version number so we can add to/change
>>> the structure as needed?
>>>
>>
>> Given our current plans for enforcing recompiles at major version
>> changes (via magic-block checking), I'm not sure I see a need for this.
>>
> That makes a lot more sense - I don't like the idea of each plugin
> managing its own version information. We can always add more function
> pointers to the end of the plugin structure - if the pointers are
> non-NULL, you gain more functionality.
>>> 4) Do we need to support multiple active plugins?
>>>
>>
>> Probably, but let's fix the API to hide this, so we don't have to commit
>> now.
>>
> Cool.
>
> -- Korry
>


From: John DeSoi <desoi(at)pgedit(dot)com>
To: korry <korryd(at)enterprisedb(dot)com>
Cc: PostgreSQL-development Hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: Loading the PL/pgSQL debugger (and other plugins)
Date: 2006-07-21 17:35:11
Message-ID: AC97FF80-536E-455D-8E99-3CCF7032AB09@pgedit.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

Hi Korry,

On Jul 21, 2006, at 12:51 PM, korry wrote:

> Sorry to poke - but I'd like to get a patch submitted next week.
> Any more comments? Thanks.

I'm unqualified to comment on the server side design, but I was
wondering if there was consensus on how the client interface to the
debugger would work. From previous threads I saw DBGP mentioned
(http://xdebug.org/docs-dbgp.php), but I don't recall seeing any
final commitment to it.

Thanks,

John

John DeSoi, Ph.D.
http://pgedit.com/
Power Tools for PostgreSQL


From: korry <korryd(at)enterprisedb(dot)com>
To: John DeSoi <desoi(at)pgedit(dot)com>
Cc: PostgreSQL-development Hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: Loading the PL/pgSQL debugger (and other plugins)
Date: 2006-07-21 18:21:11
Message-ID: BAY101-DAV1047F8E91D05750B49385FD6660@phx.gbl
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers


> I'm unqualified to comment on the server side design, but I was
> wondering if there was consensus on how the client interface to the
> debugger would work. From previous threads I saw DBGP mentioned
> (http://xdebug.org/docs-dbgp.php), but I don't recall seeing any final
> commitment to it.
The patch that I'll be submitting for 8.2 will implement a way to
instrument PL/pgSQL (and that idea can be extended to other PL
languages). 'Instrumentation' can mean different things - it may be a
debugger, a profiler, a coverage analyzer, a tracer, ...

EnterpriseDB has developed a few plugins that we'll be contributing soon
(a debugger, a profiler, and a tracer). The debugger is by far the
largest plugin that we've developed and we implemented it before we had
the idea to use a modular architecture (we're still in the process of
converting the debugger to modular form, at the moment it's pretty
heavily integrated into the PL/pgSQL interpreter). As soon as we get a
patch in for the plugin architecture, we'll open-source at least one or
two of the plugins so others can use them and/or write more (the
debugger will take a little longer).

That means that we (i.e. the community) haven't made a firm commitment
to the debugger client protocol. I can tell you a little about the
protocol that we are currently using, but it may change by the time
we're ready to open-source the debugger. I gave a presentation at the
anniversary summit that described the overall architecture and also
showed the client/server protocol - the slides and audio should be
available at the conference web site "real soon now".

The most important part, from your perspective (assuming that you might
want to add a debugger to pgEdit), is the method that a debugger client
application uses to interact with the debugger server. That's done
through a collection of server-side functions that you can call from any
libpq application. For example, to set a breakpoint, you would:

SELECT * FROM pldbg_set_breakpoint( sessionHandle, functionOID,
lineNumber, processID );

to step/over:

SELECT * FROM pldbg_step_over( sessionHandle );

to step/into:

SELECT * FROM pldbg_step_into( sessionHandle );

to get a copy of all local variables:

SELECT * FROM pldbg_get_variables( sessionHandle, stackFrame );

and so on. There are a few functions that you can call to attach your
debugger client to a target server and to set global breakpoints.

I'll be posting more information as we get closer to releasing this stuff.

-- Korry


From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: korry <korryd(at)enterprisedb(dot)com>
Cc: pgsql-hackers(at)postgresql(dot)org
Subject: Re: Loading the PL/pgSQL debugger (and other plugins)
Date: 2006-07-21 18:28:49
Message-ID: 700.1153506529@sss.pgh.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

korry <korryd(at)enterprisedb(dot)com> writes:
>> I see no good reason to tie
>> it to plpgsql; we'll just need another one for every other language.
>>
> Hmmm... but the plugins themselves would be language-specific.

You miss my point. The plugins will be language-specific but the
mechanism for selecting/loading them shouldn't be.

>> When the plugin's shared library gets loaded, one way or the other,
>> it should construct the function-pointer struct and then pass it to a
>> function defined by plpgsql (this lets us hide/postpone the decision
>> about whether there can be more than one active plugin).
>>
> But there's a timing issue there. If you ask the plugin to call a
> call-handler function, then you can't load the plugin at backend startup
> because the PL/pgSQL call-handler isn't loaded until it's required.
> Since both the plugin and the call-handler are dynamically loaded, I
> think one of them has to load the other.

Right, but if you set up the mechanism such that each individual PL is
responsible for loading plugins, then we'll have to duplicate all that
code each time we instrument another PL. I want to do as much as
possible of the work in the core code so that we don't end up with
duplicate code to maintain.

That being the case, I don't see anything wrong with having the
selection mechanism pull in the selected plugin(s) and then those
force loading of the language handlers so that they can call the plugin
installation function. Sure, sometimes this would result in loading
a plugin and handler that don't get used in the current session, but
given that people would only load plugins they intend to use, I don't
see that as a significant objection.

I'm thinking that the cleanest way to handle this would be to add
another column to pg_language containing the OID of the plugin receptor
function for each PL. Then the plugin just calls that function passing
its constructed function-pointer struct. This eliminates the need for
hard-wired assumptions about function names and so forth, and also lets
you use the existing fmgr functionality to pull in the PL's handler
library. OTOH this requires extending the syntax of CREATE LANGUAGE
and so on. That is all doable (it's basically the same kind of work
that got done when we added validator functions for PLs) but it might
be more work than we think the plugin idea is worth.

To do it without a pg_language column, we'd need code in each plugin to
identify the language shared library (by looking in pg_language), force
loading of same (using existing fmgr code), and look up and call a
plugin receptor function given an expected C-code name for it (again,
most of this already exists in fmgr). It's not a huge amount of code,
probably, but again duplicating it in each plugin seems unappealing.
I suppose we could make fmgr export a general function to find a plugin
receptor function given the PL name and the expected C symbol.

Comments anyone?

regards, tom lane


From: korry <korryd(at)enterprisedb(dot)com>
To: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Cc: pgsql-hackers(at)postgresql(dot)org
Subject: Re: Loading the PL/pgSQL debugger (and other plugins)
Date: 2006-07-21 19:38:16
Message-ID: BAY101-DAV84495D04E0C77B6FDE75ED6660@phx.gbl
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers


>>> When the plugin's shared library gets loaded, one way or the other,
>>> it should construct the function-pointer struct and then pass it to a
>>> function defined by plpgsql (this lets us hide/postpone the decision
>>> about whether there can be more than one active plugin).
>>>
>>>
>> But there's a timing issue there. If you ask the plugin to call a
>> call-handler function, then you can't load the plugin at backend startup
>> because the PL/pgSQL call-handler isn't loaded until it's required.
>> Since both the plugin and the call-handler are dynamically loaded, I
>> think one of them has to load the other.
>>
>
> Right, but if you set up the mechanism such that each individual PL is
> responsible for loading plugins, then we'll have to duplicate all that
> code each time we instrument another PL. I want to do as much as
> possible of the work in the core code so that we don't end up with
> duplicate code to maintain.
>
I think I'm missing something important here.

At minimum, you need a way to identify a plugin (or a list of plugins),
and, if we generalize the mechanism, a way to identify the language that
that plugin is associated with (like, this profiler works with PL/tcl,
this debugger works with PL/Java, ...).

Once you have that, you've got two choices:

1) The plugin loads the language
or
2) The language loads the plugin

You are suggesting option 1. That means that we must:

a) come up with a way to identify the set of plugins desired
(probably some GUC variables?)
b) Extend the pg_language structure
c) Extend the CREATE LANGUAGE statement
d) come up with a way for the backend to load the plugins (the
backend already knows how to load a language-handler)
e) add loader code to each plugin (there should be more plugins than
languages eventually)
f) add loader code to each language (at least each language that
wants to support a plugin)

On the other hand, if the language loads the plugin, we must:

a) come up with a way to identify the set of plugins desired
(probably some GUC variables?)
b) add loader code to each plugin
c) add loader code to each language (that wants to support a plugin)

In either case, the loader code in the language-handlers and the loader
code in the plugins could be simple calls to common functions that are
defined in the core, avoiding a lot of duplicate code. For example, each
language handler (in it's initialization code) could include a call such as:

pl_load_plugins( "pl/pgsql", &functionPointers );

or

pl_load_plugins( "pl/java", &functionPointers );

pl_load_plugins() would reside in the core, it would find the list of
plugins, load each one, find the plugin's initialization function, and
call that function with &functionPointers (the initializer would fill in
the functionPointers structure).

So what am I missing? What's the advantage to having the plugin load
the language?

> To do it without a pg_language column, we'd need code in each plugin to
> identify the language shared library (by looking in pg_language), force
> loading of same (using existing fmgr code), and look up and call a
> plugin receptor function given an expected C-code name for it (again,
> most of this already exists in fmgr). It's not a huge amount of code,
> probably, but again duplicating it in each plugin seems unappealing.
> I suppose we could make fmgr export a general function to find a plugin
> receptor function given the PL name and the expected C symbol.
>
That's what I was thinking too. But we could avoid hard-coded names
using a syntax similar to preload_libraries (each entry in
preload_libraries can contain the name of an optional initialization
function). If you specify libraryName:functionName, we would assume
that functionName was the loader function, if you just specify
libraryName, we could look for a hard-coded default.

(Oh, and any more comments on security? Is it enough to require that
all plugins live in $libdir?)

-- Korry


From: "Hiroshi Saito" <z-saito(at)guitar(dot)ocn(dot)ne(dot)jp>
To: "korry" <korryd(at)enterprisedb(dot)com>, "John DeSoi" <desoi(at)pgedit(dot)com>
Cc: "PostgreSQL-development Hackers" <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: Loading the PL/pgSQL debugger (and other plugins)
Date: 2006-07-21 23:28:48
Message-ID: 038701c6ad1d$6b1ac090$01324d80@hiroshi5jz7dqj
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

Hi korry-san.

From: "korry"

>
> > I'm unqualified to comment on the server side design, but I was
> > wondering if there was consensus on how the client interface to the
> > debugger would work. From previous threads I saw DBGP mentioned
> > (http://xdebug.org/docs-dbgp.php), but I don't recall seeing any final
> > commitment to it.
> The patch that I'll be submitting for 8.2 will implement a way to
> instrument PL/pgSQL (and that idea can be extended to other PL
> languages). 'Instrumentation' can mean different things - it may be a
> debugger, a profiler, a coverage analyzer, a tracer, ...

I can regard it as very great. probably, It is expected that workstation
(edb-debugger) is realizable with an addition of some language parser.:-)

>
> EnterpriseDB has developed a few plugins that we'll be contributing soon
> (a debugger, a profiler, and a tracer). The debugger is by far the
> largest plugin that we've developed and we implemented it before we had
> the idea to use a modular architecture (we're still in the process of
> converting the debugger to modular form, at the moment it's pretty
> heavily integrated into the PL/pgSQL interpreter). As soon as we get a
> patch in for the plugin architecture, we'll open-source at least one or
> two of the plugins so others can use them and/or write more (the
> debugger will take a little longer).
>
> That means that we (i.e. the community) haven't made a firm commitment
> to the debugger client protocol. I can tell you a little about the
> protocol that we are currently using, but it may change by the time
> we're ready to open-source the debugger. I gave a presentation at the
> anniversary summit that described the overall architecture and also
> showed the client/server protocol - the slides and audio should be
> available at the conference web site "real soon now".

Great.!
Your session was very wonderful. People who were not able to hear it will be seen.

>
> The most important part, from your perspective (assuming that you might
> want to add a debugger to pgEdit), is the method that a debugger client
> application uses to interact with the debugger server. That's done
> through a collection of server-side functions that you can call from any
> libpq application. For example, to set a breakpoint, you would:
>
> SELECT * FROM pldbg_set_breakpoint( sessionHandle, functionOID,
> lineNumber, processID );
>
> to step/over:
>
> SELECT * FROM pldbg_step_over( sessionHandle );
>
> to step/into:
>
> SELECT * FROM pldbg_step_into( sessionHandle );
>
> to get a copy of all local variables:
>
> SELECT * FROM pldbg_get_variables( sessionHandle, stackFrame );
>
> and so on. There are a few functions that you can call to attach your
> debugger client to a target server and to set global breakpoints.
>
> I'll be posting more information as we get closer to releasing this stuff.

This regards me as a very great contribution.!
As for me, the feeling of workstation (edb-debugger) was pleased very much.
I consider it so that often to pgAdmin. Then, I am looking forward to the evolution.:-)

Thanks!!

Regards,
Hiroshi Saito


From: "Jim C(dot) Nasby" <jnasby(at)pervasive(dot)com>
To: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Cc: korry <korryd(at)enterprisedb(dot)com>, pgsql-hackers(at)postgresql(dot)org
Subject: Re: Loading the PL/pgSQL debugger (and other plugins)
Date: 2006-07-25 16:38:08
Message-ID: 20060725163808.GY83250@pervasive.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

On Wed, Jul 19, 2006 at 01:35:16PM -0400, Tom Lane wrote:
> > 1) I think the most straightforward way to load an instrumentation
> > plugin is to define a new custom GUC variable (using the
> > custom_variable_classes mechanism).
>
> This seems a bit messy and special-purpose. I see no good reason to tie
> it to plpgsql; we'll just need another one for every other language.
> IMHO what we want is something with similar properties to preload_libraries,
> but processed on a per-backend basis instead of once at postmaster start.
> (You could almost just tell people to select the plugin they want by
> LOADing it, but that is hard to use if you're trying to debug a
> non-interactive application. A GUC variable can be set for an app
> without much cooperation from the app.)
<snip>
> We should also think about a deregistration function. This would allow
> you to turn debugging on and off within an interactive session. The
> GUC variable is really only for coercing non-interactive applications
> into being debuggable --- I don't see it as being important for
> interactive debugging, as compared to just "select plugin_init();" ...

This isn't the only example of where it would be handy to be able to
tell a certain backend or group of backends to do something, so you
could gain more insight into what some application is doing. Turning on
query logging is another example that comes to mind.

Is there some way we could allow one backend to tell another backend to
change certain aspects of its behavior? One idea is to have a function
that can send commands to another backend via some form of IPC. That
backend would then execute the commands the next time it would normally
accept commands from it's client connection. Of course this creates a
pretty big foot-gun, so we might want to greatly restrict what kind of
commands could be executed this way.

Another possibility would be allowing users to specify certain GUC
settings for backends that match certain criteria when they're spawned,
such as what IP the client is connecting from, or what user it's
authenticating as.
--
Jim C. Nasby, Sr. Engineering Consultant jnasby(at)pervasive(dot)com
Pervasive Software http://pervasive.com work: 512-231-6117
vcard: http://jim.nasby.net/pervasive.vcf cell: 512-569-9461


From: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
To: "Jim C(dot) Nasby" <jnasby(at)pervasive(dot)com>
Cc: korry <korryd(at)enterprisedb(dot)com>, pgsql-hackers(at)postgresql(dot)org
Subject: Re: Loading the PL/pgSQL debugger (and other plugins)
Date: 2006-07-25 16:42:06
Message-ID: 17766.1153845726@sss.pgh.pa.us
Views: Raw Message | Whole Thread | Download mbox | Resend email
Lists: pgsql-hackers

"Jim C. Nasby" <jnasby(at)pervasive(dot)com> writes:
> Another possibility would be allowing users to specify certain GUC
> settings for backends that match certain criteria when they're spawned,
> such as what IP the client is connecting from, or what user it's
> authenticating as.

ALTER USER SET ...

regards, tom lane