Thread: libpgtcl: pq_recvbuf: unexpected EOF on client connection
libpgtcl: pq_recvbuf: unexpected EOF on client connection
From
g.hintermayer@inode.at (Gerhard Hintermayer)
Date:
I constantly keep getting this message in the log files when disconnection with pg_disconnect (TCL-interface) I did an upgrade to 7.2.1 in combination with Tcl8.3.4, everything works, but that message is annoying. Using psql doesn't produce any log entrys. Even a simple script set conn [pg_connect ....] pg_disconnect $conn creates the log entry. Has anyone ever encountered that problem ? Gerhard -- Gerhard Hintermayer http://www.inode.at/g.hintermayer
g.hintermayer@inode.at (Gerhard Hintermayer) writes: > I constantly keep getting this message in the log files when > disconnection with pg_disconnect (TCL-interface) Yeah, I see it too --- though everything's fine if you just exit the client program without an explicit pg_disconnect. I think the problem is that pg_disconnect shouldn't be unregistering the notifier_channel; I bet TCL thinks it should close the socket when we do that. Then the later PQfinish call will be unable to send the normal termination message to the backend. Probably the best fix is to move the unregister call into PgDelConnectionId(), after we do PQfinish. regards, tom lane
Tom Lane wrote: > g.hintermayer@inode.at (Gerhard Hintermayer) writes: > >>I constantly keep getting this message in the log files when >>disconnection with pg_disconnect (TCL-interface) > > > Yeah, I see it too --- though everything's fine if you just exit the > client program without an explicit pg_disconnect. I think the problem > is that pg_disconnect shouldn't be unregistering the notifier_channel; > I bet TCL thinks it should close the socket when we do that. Then > the later PQfinish call will be unable to send the normal termination > message to the backend. Probably the best fix is to move the unregister > call into PgDelConnectionId(), after we do PQfinish. > > regards, tom lane Hope my posting works. I don't understand what you're thinking of, because the unregistering triggers the call to PgDelConnectionId, so who will close the connection if you remove the unregister call ? I wonder what has changed either in the Tcl or the PQ internals, since this worked in Tcl8.3.2 combined with PostgreSQL 7.0.2. Going to check that tomorrow at work. Btw, is the PQfinish syncroneous (?) or not ? Maybe the problem is we're sending the X and close the connection immediately instead of letting the server close it. Gerhard -- Gerhard Hintermayer http://www.inode.at/g.hintermayer
Gerhard Hintermayer <g.hintermayer@inode.at> writes: > I don't understand what you're thinking of, because the unregistering > triggers the call to PgDelConnectionId, so who will close the > connection if you remove the unregister call ? I meant the unregister of the notifier_channel, which is not Pg_disconnect's business anyway. Unfortunately, it seems this fixes your problem but creates a bigger one: Tcl dumps core if you shut down the interpreter without having done pg_disconnect. As a compromise I've applied the attached patch, which seems to suppress the "unexpected EOF" problem at the cost of leaking a small amount of memory for each disconnect. regards, tom lane *** src/interfaces/libpgtcl/pgtclCmds.c.orig Mon Sep 2 17:51:47 2002 --- src/interfaces/libpgtcl/pgtclCmds.c Mon Sep 2 18:03:35 2002 *************** *** 399,405 **** int Pg_disconnect(ClientData cData, Tcl_Interp *interp, int argc, char *argv[]) { - Pg_ConnectionId *connid; PGconn *conn; Tcl_Channel conn_chan; --- 399,404 ---- *************** *** 413,427 **** if (conn_chan == NULL) { Tcl_ResetResult(interp); ! Tcl_AppendResult(interp, argv[1], " is not a valid connection\n", 0); return TCL_ERROR; } ! #if TCL_MAJOR_VERSION >= 8 ! conn = PgGetConnectionId(interp, argv[1], &connid); ! if (connid->notifier_channel != NULL) ! Tcl_UnregisterChannel(interp, connid->notifier_channel); ! #endif return Tcl_UnregisterChannel(interp, conn_chan); } --- 412,425 ---- if (conn_chan == NULL) { Tcl_ResetResult(interp); ! Tcl_AppendResult(interp, argv[1], " is not a valid connection", 0); return TCL_ERROR; } ! /* Check that it is a PG connection and not something else */ ! conn = PgGetConnectionId(interp, argv[1], (Pg_ConnectionId **) NULL); ! if (conn == (PGconn *) NULL) ! return TCL_ERROR; return Tcl_UnregisterChannel(interp, conn_chan); } *** src/interfaces/libpgtcl/pgtclId.c.orig Mon Sep 2 17:51:47 2002 --- src/interfaces/libpgtcl/pgtclId.c Mon Sep 2 19:38:22 2002 *************** *** 193,199 **** #if TCL_MAJOR_VERSION >= 8 connid->notifier_channel = Tcl_MakeTcpClientChannel((ClientData) PQsocket(conn)); ! Tcl_RegisterChannel(interp, connid->notifier_channel); #else connid->notifier_socket = -1; #endif --- 194,200 ---- #if TCL_MAJOR_VERSION >= 8 connid->notifier_channel = Tcl_MakeTcpClientChannel((ClientData) PQsocket(conn)); ! Tcl_RegisterChannel(NULL, connid->notifier_channel); #else connid->notifier_socket = -1; #endif *************** *** 286,291 **** --- 289,313 ---- connid->conn = NULL; /* + * Kill the notifier channel, too. We must not do this until after + * we've closed the libpq connection, because Tcl will try to close + * the socket itself! + * + * XXX Unfortunately, while this works fine if we are closing due to + * explicit pg_disconnect, Tcl versions through 8.3.3 dump core if we + * try to do it during interpreter shutdown. Not clear why, or if + * there is a workaround. For now, accept leakage of the (fairly + * small) amount of memory taken for the channel state representation. + * Note we are not leaking a socket, since libpq closed that already. + */ + #ifdef NOT_USED + #if TCL_MAJOR_VERSION >= 8 + if (connid->notifier_channel != NULL) + Tcl_UnregisterChannel(NULL, connid->notifier_channel); + #endif + #endif + + /* * We must use Tcl_EventuallyFree because we don't want the connid * struct to vanish instantly if Pg_Notify_EventProcis active for it. * (Otherwise, closing the connection from inside a pg_listen callback