Thread: Cheapest way to poll for notifications?

Cheapest way to poll for notifications?

From
Craig Ringer
Date:
Hi

As Pg doesn't presently support client push for notifications arising
from LISTEN/NOTIFY, I'm wondering if anybody here has done any research
into the cheapest statement to issue to check for such notifications.

First: is it worth caring? Or is a `SELECT 1;' every few seconds from a
small (50-ish) number of clients unlikely to have a detectable effect on
load?

Does it have any significant costs (considering that each statement
starts its own transaction) ? Is it worth issuing:

BEGIN ISOLATION LEVEL READ COMMITTED, READ ONLY; SELECT 1; ROLLBACK;

rather than just `SELECT 1' ?

I'll be doing some testing on all of this, of course, but I thought I'd
ask in case others have looked into this already. I didn't see anything
much in the archives.



One thing I've noticed is that an invalid statement that fails to parse
still produces the notifications, though it avoids planning and query
execution. However, it'll also fill the error log with garbage, so it's
not exactly desirable. The error paths are probably more expensive than
just running the SELECT anyway.

I wonder if it'd be useful to have a utility statement (perhaps 'LISTEN'
without arguments?) that was essentially a no-op that _only_ checked
notifications. It'd make it easier to see why clients were issuing
apparently random statements, and could possibly be also excluded from
statement logging even when other things were logged. Would there be any
support for the idea of something like that? It might be project #2 for
me once I get around to posting the array_reverse function, if so.

Also: Is there any practical way Pg can ever support server-to-client
push for notifications? I assume the reasons why it doesn't at present
are to do with the protocol and with deadlock/concurrency issues at the
wire level ... is that so?

--
Craig Ringer

Re: Cheapest way to poll for notifications?

From
Tom Lane
Date:
Craig Ringer <craig@postnewspapers.com.au> writes:
> As Pg doesn't presently support client push for notifications arising
> from LISTEN/NOTIFY, I'm wondering if anybody here has done any research
> into the cheapest statement to issue to check for such notifications.

The backend certainly will push the notification.  Maybe you just have
a client-side-software issue?

            regards, tom lane

Re: Cheapest way to poll for notifications?

From
Merlin Moncure
Date:
On Thu, Dec 10, 2009 at 8:23 AM, Craig Ringer
<craig@postnewspapers.com.au> wrote:
> Hi
>
> As Pg doesn't presently support client push for notifications arising from
> LISTEN/NOTIFY, I'm wondering if anybody here has done any research into the
> cheapest statement to issue to check for such notifications.

notifications are sent to the client as soon as they are generated and
the socket is not otherwise being used.  psql just prints the
notifcation message following a query because that happens to be a
convenient place to do it.  The only polling that has to be done (if
any) is 100% client side.  There is an excellent example (in C) in the
documentation showing a method of waiting on the connection socket for
notification events when the connection is not in use by the client.

merlin

Re: Cheapest way to poll for notifications?

From
Craig Ringer
Date:
Tom Lane wrote:
> Craig Ringer <craig@postnewspapers.com.au> writes:
>> As Pg doesn't presently support client push for notifications arising
>> from LISTEN/NOTIFY, I'm wondering if anybody here has done any research
>> into the cheapest statement to issue to check for such notifications.
>
> The backend certainly will push the notification.  Maybe you just have
> a client-side-software issue?

Testing with two plain old psql sessions to an 8.4.1 DB on linux (Ubuntu
9.10) here, I don't see the asynchronous notification until I send some
other command to the database from the client. It's the same over a
local UNIX socket or a loopback TCP/IP connection (with SSL).

Neither listener nor notifier are in a transaction, though it doesn't
seem to make any difference if I "BEGIN; NOTIFY test; COMMIT;" instead.

I only waited a few minutes after sending NOTIFY to see if psql would
notice, but if it's server-pushed it should be immediate, right?

Is this a psql limitation rather than a backend one? I know the JDBC
driver has such a limitation, and in fact the psql man page suggests
that it does too:

"
 Whenever  a command is executed, psql also polls for asynchronous noti‐
 fication events generated by LISTEN [listen(7)] and NOTIFY [notify(7)].
"

... but if that is the case, is there any client software that _does_
support truly asynchronous receipt of notifications?




=====(SESSION 1, psql 8.4.1, local socket)====

test=> LISTEN x;
LISTEN
test=> SELECT current_timestamp;
              now
-------------------------------
 2009-12-10 23:54:16.988355+08
(1 row)

test=> SELECT current_timestamp;
              now
-------------------------------
 2009-12-10 23:55:04.872358+08
(1 row)

Asynchronous notification "x" received from server process with PID 14623.
test=>


=====(SESSION 2, psql 8.4.1, local socket)====
test=> SELECT current_timestamp;
              now
-------------------------------
 2009-12-10 23:54:34.252394+08
(1 row)

test=> NOTIFY x;
NOTIFY
test=>




*Self* notifications ( where listener == notifier ) are issued
immediately, but a NOTIFY to another backend doesn't seem to get pushed.

--
Craig Ringer

Re: Cheapest way to poll for notifications?

From
Craig Ringer
Date:
Merlin Moncure wrote:
> On Thu, Dec 10, 2009 at 8:23 AM, Craig Ringer
> <craig@postnewspapers.com.au> wrote:
>> Hi
>>
>> As Pg doesn't presently support client push for notifications arising from
>> LISTEN/NOTIFY, I'm wondering if anybody here has done any research into the
>> cheapest statement to issue to check for such notifications.
>
> notifications are sent to the client as soon as they are generated and
> the socket is not otherwise being used.  psql just prints the
> notifcation message following a query because that happens to be a
> convenient place to do it.  The only polling that has to be done (if
> any) is 100% client side.  There is an excellent example (in C) in the
> documentation showing a method of waiting on the connection socket for
> notification events when the connection is not in use by the client.

Aah, that makes sense. So psql is being sent (and buffering) the
notification immediately, and could choose to report it promptly - say
by calling recv(...) on its socket periodically using an alarm signal.
Since it's not important for psql to report notifications immediately
though, it only checks after statements.

Right?

Anyway, thanks for the explanation, it's appreciated.

--
Craig Ringer

Re: Cheapest way to poll for notifications?

From
Tom Lane
Date:
Craig Ringer <craig@postnewspapers.com.au> writes:
> Tom Lane wrote:
>> The backend certainly will push the notification.  Maybe you just have
>> a client-side-software issue?

> Testing with two plain old psql sessions to an 8.4.1 DB on linux (Ubuntu
> 9.10) here, I don't see the asynchronous notification until I send some
> other command to the database from the client. It's the same over a
> local UNIX socket or a loopback TCP/IP connection (with SSL).

psql is not too bright about that; when it's waiting for user input it
just waits.  But I don't think it matters because nobody is going to
write an application that depends on this in psql anyway.  If you are
writing something that uses libpq directly, it's certainly possible to
watch for incoming notifies along with whatever else your event loop is
watching for.  (I had an application that did so a dozen years ago...)

            regards, tom lane

Re: Cheapest way to poll for notifications?

From
Scott Ribe
Date:
> Right?

Right. The way I do it, very roughly:


 Pqconnectdb(...)
 PQexec( mDbConn, "listen notify" );
 int dbsock = PQsocket( mDbConn );
 mKq = kqueue();
 struct kevent kev[1], kevs[1];
 EV_SET( &kev[0], dbsock, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0 );
 kevent( mKq, kev, 1, NULL, 0, NULL );
 while( true ) {
   bool needsnotify = false;
   int evtcnt = kevent( mKq, NULL, 0, kevs, 1, NULL );
   if( evtcnt == 1 && kevs[i].filter == EVFILT_READ && kevs[i].ident ==
dbsock ) {
     while( true ) {
       PQconsumeInput( mDbConn );
       PGnotify * notify = PQnotifies( mDbConn );
       if( notify )  {
         free( notify );
         needsnotify = true;
       }
       else
         break;
     }
   }

  if( needsnotify )
    // go off & query the db & handle updates here
 }


Of course you could also use select to wait on the socket.

--
Scott Ribe
scott_ribe@killerbytes.com
http://www.killerbytes.com/
(303) 722-0567 voice



Re: Cheapest way to poll for notifications?

From
Craig Ringer
Date:
Scott, Tom, Merlin:

Thanks for the comments and help. It's all sorted now - the origin of
the confusion was some outdated information in the JDBC driver
documentation.

The question arose because I was originally looking at polling from JDBC
(which I know I forgot to mention), where the docs state that:

"A key limitation of the JDBC driver is that it cannot receive
asynchronous notifications and must poll the backend to check if any
notifications were issued."

  http://jdbc.postgresql.org/documentation/84/listennotify.html

.... and show a `SELECT 1' being issued to push any notifications.

I'd assumed that was a JDBC limitation until I tested with psql and
found that it, too, required some kind of client-initiated communication
to see NOTIFY events, at which point I began wondering if the backend
pushed them at all rather than waiting for client interaction. Hence my
question.


Anyway, as pointed out, psql just doesn't bother polling for
notifications because it's not important for psql, but it could if it
needed to - the notifications are waiting in its recieve buffer for it
to notice and care.

As for the JDBC driver - it turns out that the documentation is
out-of-date and/or misleading. The JDBC driver *does* support reading
notifications the backend has pushed to its receive buffer, and does
*not* have to poll the backend or issue a statement to receive
notifications. Some searching suggests that this changed in 8.0 or 8.1 .
The documentation needs adjusting, so I've sent a patch to it off to the
JDBC folks.

--
Craig Ringer

Re: Cheapest way to poll for notifications?

From
Craig Ringer
Date:
On 11/12/2009 11:39 PM, Craig Ringer wrote:

> As for the JDBC driver - it turns out that the documentation is
> out-of-date and/or misleading. The JDBC driver *does* support reading
> notifications the backend has pushed to its receive buffer, and does
> *not* have to poll the backend or issue a statement to receive
> notifications.

Update: The above is true only for non-SSL connections. For SSL
connections you still have to send dummy statements.

--
Craig Ringer