Re: [HACKERS] LIBPQ patches ...

Поиск
Список
Период
Сортировка
От The Hermit Hacker
Тема Re: [HACKERS] LIBPQ patches ...
Дата
Msg-id Pine.BSF.4.21.0001081752460.18498-100000@thelab.hub.org
обсуждение исходный текст
Ответ на Re: [HACKERS] LIBPQ patches ...  (Bruce Momjian <pgman@candle.pha.pa.us>)
Список pgsql-hackers
On Sat, 8 Jan 2000, Bruce Momjian wrote:

> Looks fine.  I have talked to someone about doing no-blocking
> connections in the past.  Maybe this the same person.
> 
> I will let someone else comment on whether the protocol changes are
> correct.

Okay, if I haven't heard anything major by Sunday, I'm going to include
these, whic still gives us a month before beta (well, not quite, but
close) and then the beta period in order to clean it up...
> 
> 
> > 
> > Does anyone have anything against me applying this to the current source
> > tree?  
> > 
> > 
> > Marc G. Fournier                   ICQ#7615664               IRC Nick: Scrappy
> > Systems Administrator @ hub.org 
> > primary: scrappy@hub.org           secondary: scrappy@{freebsd|postgresql}.org 
> > 
> > ---------- Forwarded message ----------
> > Date: Fri, 17 Dec 1999 13:51:50 -0800 (PST)
> > From: Alfred Perlstein <bright@wintelcom.net>
> > To: The Hermit Hacker <scrappy@hub.org>
> > Subject: Re: pctrackd updates and such
> > 
> > On Fri, 17 Dec 1999, The Hermit Hacker wrote:
> > 
> > > 
> > > Okay, first thing...can you redo these as context diffs?  We generally
> > > refuse *any* patches that aren't context...
> > 
> > sure.
> > 
> > > 
> > > Second, are these against a reasonably current snapshot of PostgreSQL
> > > (aka. the upcoming v7), or v6.5.3 release?  If v6.5.3, we're gonna need to
> > > get these v7.x ready before we can commit them...
> > 
> > they are against a checked out cvs copy as of a couple days ago,
> > and should apply cleanly to what's in the current repo.
> > 
> > > Once both of the above conditions are in place, and after I get back from
> > > BC, I'll work on  getting these into the v7.0 release...or, at least,
> > > talked/commented about if there are any objections...
> > > 
> > > I'm outta here for 10 days...Happy Holidays and talk with ya when I get
> > > back...
> > 
> > ok, cool see you soon. :)
> > 
> > -Alfred
> > 
> > don't forget the problem with sending queries that may occur:
> > 
> > i'm not sure if handlesendfailure() can cope with only sending
> > a 'Q' to the backend, we may have to work out reservations or
> > something for space, another idea would be to implement a 
> > pqWritev() of some sort that would take an array of pointers
> > and lengths to send to the backend and only allow any data to
> > go into the backend if the entire string can fit.
> > 
> > then again, handlesendfailure may work, but doing reservations
> > for the send buffer seems cleaner...
> > 
> > diff's contexted against pgsql-'current':
> > 
> > 
> > Index: fe-connect.c
> > ===================================================================
> > RCS file: /home/pgcvs/pgsql/src/interfaces/libpq/fe-connect.c,v
> > retrieving revision 1.108
> > diff -u -c -r1.108 fe-connect.c
> > cvs diff: conflicting specifications of output style
> > *** fe-connect.c    1999/12/02 00:26:15    1.108
> > --- fe-connect.c    1999/12/14 09:42:24
> > ***************
> > *** 595,625 ****
> >       return 0;
> >   }
> >   
> > - 
> > - /* ----------
> > -  * connectMakeNonblocking -
> > -  * Make a connection non-blocking.
> > -  * Returns 1 if successful, 0 if not.
> > -  * ----------
> > -  */
> > - static int
> > - connectMakeNonblocking(PGconn *conn)
> > - {
> > - #ifndef WIN32
> > -     if (fcntl(conn->sock, F_SETFL, O_NONBLOCK) < 0)
> > - #else
> > -     if (ioctlsocket(conn->sock, FIONBIO, &on) != 0)
> > - #endif
> > -     {
> > -         printfPQExpBuffer(&conn->errorMessage,
> > -                           "connectMakeNonblocking -- fcntl() failed: errno=%d\n%s\n",
> > -                           errno, strerror(errno));
> > -         return 0;
> > -     }
> > - 
> > -     return 1;
> > - }
> > - 
> >   /* ----------
> >    * connectNoDelay -
> >    * Sets the TCP_NODELAY socket option.
> > --- 595,600 ----
> > ***************
> > *** 792,798 ****
> >        *   Ewan Mellor <eem21@cam.ac.uk>.
> >        * ---------- */
> >   #if (!defined(WIN32) || defined(WIN32_NON_BLOCKING_CONNECTIONS)) && !defined(USE_SSL)
> > !     if (!connectMakeNonblocking(conn))
> >           goto connect_errReturn;
> >   #endif    
> >   
> > --- 767,773 ----
> >        *   Ewan Mellor <eem21@cam.ac.uk>.
> >        * ---------- */
> >   #if (!defined(WIN32) || defined(WIN32_NON_BLOCKING_CONNECTIONS)) && !defined(USE_SSL)
> > !     if (PQsetnonblocking(conn, TRUE) != 0)
> >           goto connect_errReturn;
> >   #endif    
> >   
> > ***************
> > *** 904,910 ****
> >       /* This makes the connection non-blocking, for all those cases which forced us
> >          not to do it above. */
> >   #if (defined(WIN32) && !defined(WIN32_NON_BLOCKING_CONNECTIONS)) || defined(USE_SSL)
> > !     if (!connectMakeNonblocking(conn))
> >           goto connect_errReturn;
> >   #endif    
> >   
> > --- 879,885 ----
> >       /* This makes the connection non-blocking, for all those cases which forced us
> >          not to do it above. */
> >   #if (defined(WIN32) && !defined(WIN32_NON_BLOCKING_CONNECTIONS)) || defined(USE_SSL)
> > !     if (PQsetnonblocking(conn, TRUE) != 0)
> >           goto connect_errReturn;
> >   #endif    
> >   
> > ***************
> > *** 1702,1707 ****
> > --- 1677,1683 ----
> >       conn->inBuffer = (char *) malloc(conn->inBufSize);
> >       conn->outBufSize = 8 * 1024;
> >       conn->outBuffer = (char *) malloc(conn->outBufSize);
> > +     conn->nonblocking = FALSE;
> >       initPQExpBuffer(&conn->errorMessage);
> >       initPQExpBuffer(&conn->workBuffer);
> >       if (conn->inBuffer == NULL ||
> > ***************
> > *** 1811,1816 ****
> > --- 1787,1793 ----
> >       conn->lobjfuncs = NULL;
> >       conn->inStart = conn->inCursor = conn->inEnd = 0;
> >       conn->outCount = 0;
> > +     conn->nonblocking = FALSE;
> >   
> >   }
> >   
> > Index: fe-exec.c
> > ===================================================================
> > RCS file: /home/pgcvs/pgsql/src/interfaces/libpq/fe-exec.c,v
> > retrieving revision 1.86
> > diff -u -c -r1.86 fe-exec.c
> > cvs diff: conflicting specifications of output style
> > *** fe-exec.c    1999/11/11 00:10:14    1.86
> > --- fe-exec.c    1999/12/14 05:55:11
> > ***************
> > *** 13,18 ****
> > --- 13,19 ----
> >    */
> >   #include <errno.h>
> >   #include <ctype.h>
> > + #include <fcntl.h>
> >   
> >   #include "postgres.h"
> >   #include "libpq-fe.h"
> > ***************
> > *** 24,30 ****
> >   #include <unistd.h>
> >   #endif
> >   
> > - 
> >   /* keep this in same order as ExecStatusType in libpq-fe.h */
> >   const char *const pgresStatus[] = {
> >       "PGRES_EMPTY_QUERY",
> > --- 25,30 ----
> > ***************
> > *** 574,580 ****
> > --- 574,588 ----
> >        * we will NOT block waiting for more input.
> >        */
> >       if (pqReadData(conn) < 0)
> > +     {
> > +         /*
> > +          * try to flush the send-queue otherwise we may never get a 
> > +          * resonce for something that may not have already been sent
> > +          * because it's in our write buffer!
> > +          */
> > +         pqFlush(conn);
> >           return 0;
> > +     }
> >       /* Parsing of the data waits till later. */
> >       return 1;
> >   }
> > ***************
> > *** 1088,1095 ****
> > --- 1096,1112 ----
> >   {
> >       PGresult   *result;
> >       PGresult   *lastResult;
> > +     bool    savedblocking;
> >   
> >       /*
> > +      * we assume anyone calling PQexec wants blocking behaviour,
> > +      * we force the blocking status of the connection to blocking
> > +      * for the duration of this function and restore it on return
> > +      */
> > +     savedblocking = PQisnonblocking(conn);
> > +     PQsetnonblocking(conn, FALSE);
> > + 
> > +     /*
> >        * Silently discard any prior query result that application didn't
> >        * eat. This is probably poor design, but it's here for backward
> >        * compatibility.
> > ***************
> > *** 1102,1115 ****
> >               PQclear(result);
> >               printfPQExpBuffer(&conn->errorMessage,
> >                   "PQexec: you gotta get out of a COPY state yourself.\n");
> > !             return NULL;
> >           }
> >           PQclear(result);
> >       }
> >   
> >       /* OK to send the message */
> >       if (!PQsendQuery(conn, query))
> > !         return NULL;
> >   
> >       /*
> >        * For backwards compatibility, return the last result if there are
> > --- 1119,1133 ----
> >               PQclear(result);
> >               printfPQExpBuffer(&conn->errorMessage,
> >                   "PQexec: you gotta get out of a COPY state yourself.\n");
> > !             /* restore blocking status */
> > !             goto errout;
> >           }
> >           PQclear(result);
> >       }
> >   
> >       /* OK to send the message */
> >       if (!PQsendQuery(conn, query))
> > !         goto errout;
> >   
> >       /*
> >        * For backwards compatibility, return the last result if there are
> > ***************
> > *** 1142,1148 ****
> > --- 1160,1172 ----
> >               result->resultStatus == PGRES_COPY_OUT)
> >               break;
> >       }
> > + 
> > +     PQsetnonblocking(conn, savedblocking);
> >       return lastResult;
> > + 
> > + errout:
> > +     PQsetnonblocking(conn, savedblocking);
> > +     return NULL;
> >   }
> >   
> >   
> > ***************
> > *** 1431,1438 ****
> >                "PQendcopy() -- I don't think there's a copy in progress.\n");
> >           return 1;
> >       }
> >   
> > !     (void) pqFlush(conn);        /* make sure no data is waiting to be sent */
> >   
> >       /* Return to active duty */
> >       conn->asyncStatus = PGASYNC_BUSY;
> > --- 1455,1468 ----
> >                "PQendcopy() -- I don't think there's a copy in progress.\n");
> >           return 1;
> >       }
> > + 
> > +     /* make sure no data is waiting to be sent */
> > +     if (pqFlush(conn))
> > +         return (1);
> >   
> > !     /* non blocking connections may have to abort at this point. */
> > !     if (PQisnonblocking(conn) && PQisBusy(conn))
> > !         return (1);
> >   
> >       /* Return to active duty */
> >       conn->asyncStatus = PGASYNC_BUSY;
> > ***************
> > *** 2025,2028 ****
> > --- 2055,2126 ----
> >           return 1;
> >       else
> >           return 0;
> > + }
> > + 
> > + /* PQsetnonblocking:
> > +      sets the PGconn's database connection non-blocking if the arg is TRUE
> > +      or makes it non-blocking if the arg is FALSE, this will not protect
> > +      you from PQexec(), you'll only be safe when using the non-blocking
> > +      API
> > +      Needs to be called only on a connected database connection.
> > + */
> > + 
> > + int
> > + PQsetnonblocking(PGconn *conn, int arg)
> > + {
> > +     int    fcntlarg;
> > + 
> > +     arg = (arg == TRUE) ? 1 : 0;
> > +     if (arg == conn->nonblocking)
> > +         return (0);
> > + 
> > + #ifdef USE_SSL
> > +     if (conn->ssl)
> > +     {
> > +         printfPQExpBuffer(&conn->errorMessage,
> > +             "PQsetnonblocking() -- not supported when using SSL\n");
> > +         return (-1);
> > +     }
> > + #endif /* USE_SSL */
> > + 
> > + #ifndef WIN32
> > +     fcntlarg = fcntl(conn->sock, F_GETFL, 0);
> > +     if (fcntlarg == -1)
> > +         return (-1);
> > + 
> > +     if ((arg == TRUE && 
> > +         fcntl(conn->sock, F_SETFL, fcntlarg | O_NONBLOCK) == -1) ||
> > +         (arg == FALSE &&
> > +         fcntl(conn->sock, F_SETFL, fcntlarg & ~O_NONBLOCK) == -1)) 
> > + #else
> > +     fcntlarg = arg;
> > +     if (ioctlsocket(conn->sock, FIONBIO, &fcntlarg) != 0)
> > + #endif
> > +     {
> > +         printfPQExpBuffer(&conn->errorMessage,
> > +             "PQsetblocking() -- unable to set nonblocking status to %s\n",
> > +             arg == TRUE ? "TRUE" : "FALSE");
> > +         return (-1);
> > +     }
> > + 
> > +     conn->nonblocking = arg;
> > +     return (0);
> > + }
> > + 
> > + /* return the blocking status of the database connection, TRUE == nonblocking,
> > +      FALSE == blocking
> > + */
> > + int
> > + PQisnonblocking(PGconn *conn)
> > + {
> > + 
> > +     return (conn->nonblocking);
> > + }
> > + 
> > + /* try to force data out, really only useful for non-blocking users */
> > + int
> > + PQflush(PGconn *conn)
> > + {
> > + 
> > +     return (pqFlush(conn));
> >   }
> > Index: fe-misc.c
> > ===================================================================
> > RCS file: /home/pgcvs/pgsql/src/interfaces/libpq/fe-misc.c,v
> > retrieving revision 1.33
> > diff -u -c -r1.33 fe-misc.c
> > cvs diff: conflicting specifications of output style
> > *** fe-misc.c    1999/11/30 03:08:19    1.33
> > --- fe-misc.c    1999/12/14 08:21:09
> > ***************
> > *** 86,91 ****
> > --- 86,119 ----
> >   {
> >       size_t avail = Max(conn->outBufSize - conn->outCount, 0);
> >   
> > +     /*
> > +      * if we are non-blocking and the send queue is too full to buffer this
> > +      * request then try to flush some and return an error 
> > +      */
> > +     if (PQisnonblocking(conn) && nbytes > avail && pqFlush(conn))
> > +     {
> > +         /* 
> > +          * even if the flush failed we may still have written some
> > +          * data, recalculate the size of the send-queue relative
> > +          * to the amount we have to send, we may be able to queue it
> > +          * afterall even though it's not sent to the database it's
> > +          * ok, any routines that check the data coming from the
> > +          * database better call pqFlush() anyway.
> > +          */
> > +         if (nbytes > Max(conn->outBufSize - conn->outCount, 0))
> > +         {
> > +             printfPQExpBuffer(&conn->errorMessage,
> > +                 "pqPutBytes --  pqFlush couldn't flush enough"
> > +                 " data: space available: %d, space needed %d\n",
> > +                 Max(conn->outBufSize - conn->outCount, 0), nbytes);
> > +             return EOF;
> > +         }
> > +     }
> > + 
> > +     /* 
> > +      * the non-blocking code above makes sure that this isn't true,
> > +      * essentially this is no-op
> > +      */
> >       while (nbytes > avail)
> >       {
> >           memcpy(conn->outBuffer + conn->outCount, s, avail);
> > ***************
> > *** 548,553 ****
> > --- 576,589 ----
> >           return EOF;
> >       }
> >   
> > +     /* 
> > +      * don't try to send zero data, allows us to use this function
> > +      * without too much worry about overhead
> > +      */
> > +     if (len == 0)
> > +         return (0);
> > + 
> > +     /* while there's still data to send */
> >       while (len > 0)
> >       {
> >           /* Prevent being SIGPIPEd if backend has closed the connection. */
> > ***************
> > *** 556,561 ****
> > --- 592,598 ----
> >   #endif
> >   
> >           int sent;
> > + 
> >   #ifdef USE_SSL
> >           if (conn->ssl) 
> >             sent = SSL_write(conn->ssl, ptr, len);
> > ***************
> > *** 585,590 ****
> > --- 622,629 ----
> >                   case EWOULDBLOCK:
> >                       break;
> >   #endif
> > +                 case EINTR:
> > +                     continue;
> >   
> >                   case EPIPE:
> >   #ifdef ECONNRESET
> > ***************
> > *** 616,628 ****
> >               ptr += sent;
> >               len -= sent;
> >           }
> >           if (len > 0)
> >           {
> >               /* We didn't send it all, wait till we can send more */
> >   
> > -             /* At first glance this looks as though it should block.  I think
> > -              * that it will be OK though, as long as the socket is
> > -              * non-blocking. */
> >               if (pqWait(FALSE, TRUE, conn))
> >                   return EOF;
> >           }
> > --- 655,685 ----
> >               ptr += sent;
> >               len -= sent;
> >           }
> > + 
> >           if (len > 0)
> >           {
> >               /* We didn't send it all, wait till we can send more */
> > + 
> > +             /* 
> > +              * if the socket is in non-blocking mode we may need
> > +              * to abort here 
> > +              */
> > + #ifdef USE_SSL
> > +             /* can't do anything for our SSL users yet */
> > +             if (conn->ssl == NULL)
> > +             {
> > + #endif
> > +                 if (PQisnonblocking(conn))
> > +                 {
> > +                     /* shift the contents of the buffer */
> > +                     memmove(conn->outBuffer, ptr, len);
> > +                     conn->outCount = len;
> > +                     return EOF;
> > +                 }
> > + #ifdef USE_SSL
> > +             }
> > + #endif
> >   
> >               if (pqWait(FALSE, TRUE, conn))
> >                   return EOF;
> >           }
> > Index: libpq-fe.h
> > ===================================================================
> > RCS file: /home/pgcvs/pgsql/src/interfaces/libpq/libpq-fe.h,v
> > retrieving revision 1.53
> > diff -u -c -r1.53 libpq-fe.h
> > cvs diff: conflicting specifications of output style
> > *** libpq-fe.h    1999/11/30 03:08:19    1.53
> > --- libpq-fe.h    1999/12/14 01:30:01
> > ***************
> > *** 269,274 ****
> > --- 269,281 ----
> >       extern int    PQputnbytes(PGconn *conn, const char *buffer, int nbytes);
> >       extern int    PQendcopy(PGconn *conn);
> >   
> > +     /* Set blocking/nonblocking connection to the backend */
> > +     extern int    PQsetnonblocking(PGconn *conn, int arg);
> > +     extern int    PQisnonblocking(PGconn *conn);
> > + 
> > +     /* Force the write buffer to be written (or at least try) */
> > +     extern int    PQflush(PGconn *conn);
> > + 
> >       /*
> >        * "Fast path" interface --- not really recommended for application
> >        * use
> > Index: libpq-int.h
> > ===================================================================
> > RCS file: /home/pgcvs/pgsql/src/interfaces/libpq/libpq-int.h,v
> > retrieving revision 1.14
> > diff -u -c -r1.14 libpq-int.h
> > cvs diff: conflicting specifications of output style
> > *** libpq-int.h    1999/11/30 03:08:19    1.14
> > --- libpq-int.h    1999/12/14 01:30:01
> > ***************
> > *** 215,220 ****
> > --- 215,223 ----
> >       int            inEnd;            /* offset to first position after avail
> >                                    * data */
> >   
> > +     int            nonblocking;    /* whether this connection is using a blocking
> > +                                  * socket to the backend or not */
> > + 
> >       /* Buffer for data not yet sent to backend */
> >       char       *outBuffer;        /* currently allocated buffer */
> >       int            outBufSize;        /* allocated size of buffer */
> > 
> > 
> > 
> > 
> > 
> > ************
> > 
> 
> 
> -- 
>   Bruce Momjian                        |  http://www.op.net/~candle
>   maillist@candle.pha.pa.us            |  (610) 853-3000
>   +  If your life is a hard drive,     |  830 Blythe Avenue
>   +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026
> 

Marc G. Fournier                   ICQ#7615664               IRC Nick: Scrappy
Systems Administrator @ hub.org 
primary: scrappy@hub.org           secondary: scrappy@{freebsd|postgresql}.org 



В списке pgsql-hackers по дате отправления:

Предыдущее
От: Bruce Momjian
Дата:
Сообщение: Re: [HACKERS] LIBPQ patches ...
Следующее
От: Tom Lane
Дата:
Сообщение: Re: [HACKERS] LIBPQ patches ...