What I have done for libpgtcl:
authorBruce Momjian
Sat, 17 Aug 2002 12:19:31 +0000 (12:19 +0000)
committerBruce Momjian
Sat, 17 Aug 2002 12:19:31 +0000 (12:19 +0000)
Everytime if I do PQconsumeInput (when the backend channel gets
readable) I check for the return value. (0 == error) and generate a
notification manually, e.g. fixed string connection_closed) and pass it to the
TCL event queue. The only other thing I had to do is to comment out removing
all pending events in PgStopNotifyEventSource whenever the connection was
unexpectedly closed (so the manually generated event will not be deleted).

A broken backend connection triggers a notify event to the client (fixed
notification string "connection_closed") so proper action can be taken to switch
to another database server etc. Remember that this is event driven. If you have
applications, that have idle database connections most of the time, you'll get
immediate feedback of a dying server. Upon connection to the server issue a
pg_notify for notify event "connection_closed" and whenever the backend crashes
(which it does do in very very rare cases) you get an event driven recovery. (of
course the Tcl-Event loop has to be processed). Issuing a notification
"connection_closed" on a still working database could be used for switching to
another db-server (which I've actually impelemented right now).

Gerhard Hintermayer

src/interfaces/libpgtcl/pgtclCmds.c
src/interfaces/libpgtcl/pgtclId.c
src/interfaces/libpgtcl/pgtclId.h

index 24f045670785aaf9f1ec9cc8304816b6a87c0f98..4b047b1b6e5af6034677c917f28515c0149503b8 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.62 2002/06/20 20:29:53 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclCmds.c,v 1.63 2002/08/17 12:19:31 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -419,8 +419,11 @@ Pg_disconnect(ClientData cData, Tcl_Interp *interp, int argc, char *argv[])
 
 #if TCL_MAJOR_VERSION >= 8
    conn = PgGetConnectionId(interp, argv[1], &connid);
-   if (connid->notifier_channel != NULL)
+   if (connid->notifier_channel != NULL) {
+       /* stop listening for NOTIFY events on that channel */
+       PgStopNotifyEventSource(connid,1);
        Tcl_UnregisterChannel(interp, connid->notifier_channel);
+   }
 #endif
 
    return Tcl_UnregisterChannel(interp, conn_chan);
index cb6250cdb49ad6d84e33c9357061f54feb269b94..d5474ce61c9cdee89bcff1c33a8aa5e7be5952df 100644 (file)
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclId.c,v 1.30 2002/06/20 20:29:53 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/interfaces/libpgtcl/Attic/pgtclId.c,v 1.31 2002/08/17 12:19:31 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -277,7 +277,7 @@ PgDelConnectionId(DRIVER_DEL_PROTO)
     * Turn off the Tcl event source for this connection, and delete any
     * pending notify events.
     */
-   PgStopNotifyEventSource(connid);
+   PgStopNotifyEventSource(connid,1);
 
    /* Close the libpq connection too */
    PQfinish(connid->conn);
@@ -441,7 +441,7 @@ PgGetConnByResultId(Tcl_Interp *interp, char *resid_c)
    *mark = '.';
    if (conn_chan && Tcl_GetChannelType(conn_chan) == &Pg_ConnType)
    {
-       Tcl_SetResult(interp, Tcl_GetChannelName(conn_chan), TCL_VOLATILE);
+       Tcl_SetResult(interp, (char *)Tcl_GetChannelName(conn_chan), TCL_VOLATILE);
        return TCL_OK;
    }
 
@@ -611,7 +611,9 @@ PgNotifyTransferEvents(Pg_ConnectionId * connid)
     * closed socket descriptor.
     */
    if (PQsocket(connid->conn) < 0)
-       PgStopNotifyEventSource(connid);
+       /* do not remove any pending events, so that the virtual notification
+         connection_closed will be processed */
+       PgStopNotifyEventSource(connid,0);
 }
 
 /*
@@ -675,7 +677,17 @@ Pg_Notify_FileHandler(ClientData clientData, int mask)
     * it internally to libpq; but it will clear the read-ready
     * condition).
     */
-   PQconsumeInput(connid->conn);
+   if (!PQconsumeInput(connid->conn)) {
+       NotifyEvent *event = (NotifyEvent *) ckalloc(sizeof(NotifyEvent));
+       
+       PGnotify *closed = (PGnotify *) ckalloc(sizeof(PGnotify));
+       strcpy(closed->relname,"connection_closed");
+       event->header.proc = Pg_Notify_EventProc;
+       event->info= *closed;
+       event->connid = connid;
+       Tcl_QueueEvent((Tcl_Event *) event, TCL_QUEUE_TAIL);
+       ckfree((void *)closed);
+   }
 
    /* Transfer notify events from libpq to Tcl event queue. */
    PgNotifyTransferEvents(connid);
@@ -724,7 +736,7 @@ PgStartNotifyEventSource(Pg_ConnectionId * connid)
 }
 
 void
-PgStopNotifyEventSource(Pg_ConnectionId * connid)
+PgStopNotifyEventSource(Pg_ConnectionId * connid, int remove_pending)
 {
    /* Remove the event source */
    if (connid->notifier_running)
@@ -743,5 +755,5 @@ PgStopNotifyEventSource(Pg_ConnectionId * connid)
    }
 
    /* Kill any queued Tcl events that reference this channel */
-   Tcl_DeleteEvents(NotifyEventDeleteProc, (ClientData) connid);
+   if (remove_pending) Tcl_DeleteEvents(NotifyEventDeleteProc, (ClientData) connid);
 }
index 55b572bb78cac87dbad383c2c3d2371a3d96cf88..6a918e41f8c2f3593a53f87063cc887ad934fc08 100644 (file)
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pgtclId.h,v 1.18 2002/06/20 20:29:53 momjian Exp $
+ * $Id: pgtclId.h,v 1.19 2002/08/17 12:19:31 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -44,7 +44,7 @@ extern PGresult *PgGetResultId(Tcl_Interp *interp, char *id);
 extern void PgDelResultId(Tcl_Interp *interp, char *id);
 extern int PgGetConnByResultId(Tcl_Interp *interp, char *resid);
 extern void PgStartNotifyEventSource(Pg_ConnectionId * connid);
-extern void PgStopNotifyEventSource(Pg_ConnectionId * connid);
+extern void PgStopNotifyEventSource(Pg_ConnectionId * connid, int remove_pend);
 extern void PgNotifyTransferEvents(Pg_ConnectionId * connid);
 extern void PgNotifyInterpDelete(ClientData clientData, Tcl_Interp *interp);