The ultimate extension hook. - Mailing list pgsql-hackers

From Daniel Wood
Subject The ultimate extension hook.
Date
Msg-id 628272472.67614.1600920890350@connect.xfinity.com
Whole thread Raw
Responses Re: The ultimate extension hook.  (Tom Lane <tgl@sss.pgh.pa.us>)
List pgsql-hackers
Hooks exist all over PG for extensions to cover various specific usages.

The hook I'd like to see would be in the PostgresMain() loop
for the API "firstchar" messages.

While I started just wanting the hook for the absolute minimum overhead to execute a function, even faster than fastpath, and in brainstorming with David Rowley other use cases became apparent.

API tracing within the engine.  I've heard of client tools for this.
API filtering.  Block/ignore manual checkpoints for instance.
API message altering.
Anything you want to hook into at the highest level well above ExecutorRun.

Originally I just wanted a lightweight mechanism to capture some system counters like /proc/stat without going through the SQL execution machinery.  I'm picky about implementing stuff in the absolute fastest way.  :-)  But I think there are other practical things that I haven't even thought of yet.

There are a few implementation mechanisms which achieve slightly different possibilities:

1) The generic mechanism would let one or more API filters be installed to directly call functions in an extension.  There would be no SQL arg processing overhead based on the specific function.   You'd just pass it the StringInfoData 'msg' itself. Multiple extensions might use the hook so you'd need to rewind the StringInfo buffer.  Maybe I return a boolean to indicate no further processing of this message or fall through to the normal "switch (firstchar)" processing.

2) switch (firstchar) { case 'A': // New trivial API message for extensions
which would call a single extension installed function to do whatever I wanted based on the message payload.  And, yes, I know this can be done just using SQL.  It is simply a variation.  But this would require client support and I prefer the below.

3) case 'Q':  /* simple query */
if (pq_peekbyte() == '!' && APIHook != NULL) {
   (*APIHook)(msg);
  <return something>
  ...
  continue;
}

I've use this last technique to do things like:
if (!strncmp(query_string, "DIEDIEDIE", 9) {
    char *np = NULL;
    *np = 1;
} else if (!strncmp(query_string, "PING", 4) {
    static const char *pong = "PONG";
    pq_putmessage('C', pong, strlen(pong) + 1);
    send_ready_for_query = true;
    continue;
} else if (...)

Then I can simple type PING into psql and get back a PONG.
Or during a stress test on a remote box I can execute the simple query "DIEDIEDIE" and crash the server.  I did this inline for experimentation before but it would be nice if I had the mechanism to use a "statement" to invoke a hook function in an extension.  A single check for "!" in the 'Q' processing would allow user defined commands in extensions.  The dispatcher would be in the extension.  I just need the "!" check.

Another example where ultimate performance might be a goal, if  you are familiar with why redis/memcached/etc. exists then imagine loading SQL results into a cache in an extension and executing as a 'simple' query something like:  !LOOKUP <KEY>
and getting the value faster than SQL could do.

Before I prototype I want to get some feedback.  Why not have a hook at the API level?

pgsql-hackers by date:

Previous
From: Michael Paquier
Date:
Subject: Re: Get memory contexts of an arbitrary backend process
Next
From: Michael Paquier
Date:
Subject: Re: PATCH: Attempt to make dbsize a bit more consistent