OSDN Git Service

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 84149d1..8587984 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