Patch to cure O(N^2) behavior in libpq when reading a long
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 13 Sep 1999 03:00:19 +0000 (03:00 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 13 Sep 1999 03:00:19 +0000 (03:00 +0000)
message under a kernel that only returns one packet per recv() call.  This
didn't use to matter much, but it starts to get annoying with multi-megabyte
EXPLAIN VERBOSE responses...

src/interfaces/libpq/fe-misc.c

index 84149d12773f34569bd22cb7042b499c5502f581..85879847e6e64ee9216457760124b8408fac49d6 100644 (file)
@@ -24,7 +24,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.29 1999/08/31 01:37:36 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.30 1999/09/13 03:00:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -307,6 +307,7 @@ pqReadReady(PGconn *conn)
 int
 pqReadData(PGconn *conn)
 {
+   int         someread = 0;
    int         nread;
 
    if (conn->sock < 0)
@@ -359,11 +360,11 @@ tryAgain:
        /* Some systems return EAGAIN/EWOULDBLOCK for no data */
 #ifdef EAGAIN
        if (errno == EAGAIN)
-           return 0;
+           return someread;
 #endif
 #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
        if (errno == EWOULDBLOCK)
-           return 0;
+           return someread;
 #endif
        /* We might get ECONNRESET here if using TCP and backend died */
 #ifdef ECONNRESET
@@ -378,9 +379,30 @@ tryAgain:
    if (nread > 0)
    {
        conn->inEnd += nread;
+       /*
+        * Hack to deal with the fact that some kernels will only give us
+        * back 1 packet per recv() call, even if we asked for more and there
+        * is more available.  If it looks like we are reading a long message,
+        * loop back to recv() again immediately, until we run out of data
+        * or buffer space.  Without this, the block-and-restart behavior of
+        * libpq's higher levels leads to O(N^2) performance on long messages.
+        *
+        * Since we left-justified the data above, conn->inEnd gives the
+        * amount of data already read in the current message.  We consider
+        * the message "long" once we have acquired 32k ...
+        */
+       if (conn->inEnd > 32768 &&
+           (conn->inBufSize - conn->inEnd) >= 8192)
+       {
+           someread = 1;
+           goto tryAgain;
+       }
        return 1;
    }
 
+   if (someread)
+       return 1;               /* got a zero read after successful tries */
+
    /*
     * A return value of 0 could mean just that no data is now available,
     * or it could mean EOF --- that is, the server has closed the