Adjust libpq to avoid deadlock when both client and server want to send
authorTom Lane
Sun, 19 Oct 2003 21:36:41 +0000 (21:36 +0000)
committerTom Lane
Sun, 19 Oct 2003 21:36:41 +0000 (21:36 +0000)
data, and both have filled the transmission buffers.  One scenario where
this can happen was illustrated here:
http://archives.postgresql.org/pgsql-hackers/2003-04/msg00979.php

src/interfaces/libpq/fe-exec.c
src/interfaces/libpq/fe-misc.c

index 810a753ed3c7565e1dd7194daf7b60a5922708be..1967d7429b44d96ecf2abf05af21ea7c75620f75 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.151 2003/10/04 21:05:21 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-exec.c,v 1.152 2003/10/19 21:36:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1336,6 +1336,17 @@ PQputCopyData(PGconn *conn, const char *buffer, int nbytes)
                          libpq_gettext("no COPY in progress\n"));
        return -1;
    }
+
+   /*
+    * Check for NOTICE messages coming back from the server.  Since the
+    * server might generate multiple notices during the COPY, we have to
+    * consume those in a reasonably prompt fashion to prevent the comm
+    * buffers from filling up and possibly blocking the server.
+    */
+   if (!PQconsumeInput(conn))
+       return -1;              /* I/O failure */
+   parseInput(conn);
+
    if (nbytes > 0)
    {
        /*
index d71473d514ae591145c3eacebff64981cb3382ea..4349a4e05aa5bdf35bf87910a685fcb8f6fcff57 100644 (file)
@@ -23,7 +23,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.102 2003/08/08 21:42:55 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.103 2003/10/19 21:36:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -828,7 +828,24 @@ pqSendSome(PGconn *conn, int len)
                break;
            }
 
-           if (pqWait(FALSE, TRUE, conn))
+           /*
+            * There are scenarios in which we can't send data because the
+            * communications channel is full, but we cannot expect the server
+            * to clear the channel eventually because it's blocked trying to
+            * send data to us.  (This can happen when we are sending a large
+            * amount of COPY data, and the server has generated lots of
+            * NOTICE responses.)  To avoid a deadlock situation, we must be
+            * prepared to accept and buffer incoming data before we try
+            * again.  Furthermore, it is possible that such incoming data
+            * might not arrive until after we've gone to sleep.  Therefore,
+            * we wait for either read ready or write ready.
+            */
+           if (pqReadData(conn) < 0)
+           {
+               result = -1;    /* error message already set up */
+               break;
+           }
+           if (pqWait(TRUE, TRUE, conn))
            {
                result = -1;
                break;