Обсуждение: non-blocking connections in libpq, fix proposal

Поиск
Список
Период
Сортировка

non-blocking connections in libpq, fix proposal

От
Bernhard Herzog
Дата:
Hi,

after finding out that libpq apparently doesn't work properly when
sending long queries ('long' meaning somewhere larger than 8KB), I had a
look at the sources and also found some mails in the archives where this
issue had been discussed. The problem appears to be still present in the
current CVS version.

I've worked on a fix today that works for me. It's perhaps not the best
solution but it's simple :-)

The basic strategy is to fix pqFlush and pqPutBytes.

The problem with pqFlush as it stands now is that it returns EOF when an
error occurs or when not all data could be sent. The latter case is
clearly not an error for a non-blocking connection but the caller can't
distringuish it from an error very well.

The first part of the fix is therefore to fix pqFlush. This is done by
to renaming it to pqFlushSome which only differs from pqFlush in its
return values to allow the caller to make the above distinction and a
new pqFlush which is implemented in terms of pqFlushSome and behaves
exactly like the old pqFlush.

The second part of the fix modifies pqPutBytes to use pqFlushSome
instead of pqFlush and to either send all the data or if not all data
can be sent on a non-blocking connection to at least put all data into
the output buffer, enlarging it if necessary.

I've also added a new API function PQflushSome which analogously to
PQflush just calls pqFlushSome. Programs using PQsendQuery should use
this new function. The main difference is that this function will have
to be called repeatedly (calling select() properly in between) until all
data has been written.


Being new to postgresql development I'm not completely sure how to
proceed from here. Is it OK if I post the patch here?

  Bernhard


-- 
Intevation GmbH                                 http://intevation.de/
Sketch                                 http://sketch.sourceforge.net/
MapIt!                                               http://mapit.de/


Re: non-blocking connections in libpq, fix proposal

От
Tom Lane
Дата:
Bernhard Herzog <bh@intevation.de> writes:
> after finding out that libpq apparently doesn't work properly when
> sending long queries ('long' meaning somewhere larger than 8KB), I had a
> look at the sources and also found some mails in the archives where this
> issue had been discussed. The problem appears to be still present in the
> current CVS version.

Indeed, the "non blocking" support in libpq is completely broken IMHO,
and has been since it was put in; but I've not had time to work on it
myself.  And the original developer of the feature apparently never
stressed it hard enough to have a problem, so he insisted there was
no problem :-(  I think you're the first person to come along and
actually want to do something about it.

> The problem with pqFlush as it stands now is that it returns EOF when an
> error occurs or when not all data could be sent. The latter case is
> clearly not an error for a non-blocking connection but the caller can't
> distringuish it from an error very well.

Right.  The real problem with the design is that the return codes of a
lot of routines aren't adequate to distinguish these cases.  However,
I'm dubious that pqFlush is the only place where there's a problem;
AFAIR the problem propagates out to quite a lot of places.

> The second part of the fix modifies pqPutBytes to use pqFlushSome
> instead of pqFlush and to either send all the data or if not all data
> can be sent on a non-blocking connection to at least put all data into
> the output buffer, enlarging it if necessary.

I think that was the same approach I had in mind awhile back --- if
pqPutBytes only fails when it can neither send nor queue data, then
that reduces the number of places that need to cope with "can't send
yet" conditions.

> I've also added a new API function PQflushSome which analogously to
> PQflush just calls pqFlushSome. Programs using PQsendQuery should use
> this new function.

You mean "programs using nonblocking send should use this function", no?

I don't like the name "pqFlushSome" --- to me "flush" means "get rid of
all the data or else".  Maybe "pqSendSome"?  Any other ideas out there?

> Being new to postgresql development I'm not completely sure how to
> proceed from here. Is it OK if I post the patch here?

Patches should go to pgsql-patches, especially if they're more than
a few lines long.
        regards, tom lane


Re: non-blocking connections in libpq, fix proposal

От
Bernhard Herzog
Дата:
Tom Lane <tgl@sss.pgh.pa.us> writes:

> Bernhard Herzog <bh@intevation.de> writes:
> Right.  The real problem with the design is that the return codes of a
> lot of routines aren't adequate to distinguish these cases.  However,
> I'm dubious that pqFlush is the only place where there's a problem;
> AFAIR the problem propagates out to quite a lot of places.

pqFlush is called in a lot of places, that's true. However, it seems to
me that in many of those places, it doesn't have to be called at all.

For one, for a blocking connection, pqFlush only needs to be called
after data has been put into the output buffer and most public functions
(and many internal functions) already do that before they return
(notable exceptions: PQputline and PQputnbytes). Calling pqFlush at the
beginning of a function shouldn't be necessary.

For a non-blocking connection, the program using the library can be
expected to call PQsendSome until all pending data has been sent, I
think, so it wouldn't be necessary to call pqFlush/pqSendSome at the
beginning of e.g. PQsendQuery. PQsendQuery should perhaps check whether
the buffer is empty instead.

> I think that was the same approach I had in mind awhile back --- if
> pqPutBytes only fails when it can neither send nor queue data, then
> that reduces the number of places that need to cope with "can't send
> yet" conditions.

Exactly. that's why I did it that way. I tried to make as few changes as
possible.

> > I've also added a new API function PQflushSome which analogously to
> > PQflush just calls pqFlushSome. Programs using PQsendQuery should use
> > this new function.
> 
> You mean "programs using nonblocking send should use this function", no?

Yes.

> I don't like the name "pqFlushSome" --- to me "flush" means "get rid of
> all the data or else".  Maybe "pqSendSome"?  Any other ideas out there?

I'll call it pqSendSome for now.

> Patches should go to pgsql-patches, especially if they're more than
> a few lines long.

I've sent it there. 

Regards,
  Bernhard

-- 
Intevation GmbH                                 http://intevation.de/
Sketch                                 http://sketch.sourceforge.net/
MapIt!                                               http://mapit.de/


Re: non-blocking connections in libpq, fix proposal

От
Bruce Momjian
Дата:
Thread has been saved for the 7.3 release:
http://candle.pha.pa.us/cgi-bin/pgpatches2

---------------------------------------------------------------------------

Bernhard Herzog wrote:
> 
> Hi,
> 
> after finding out that libpq apparently doesn't work properly when
> sending long queries ('long' meaning somewhere larger than 8KB), I had a
> look at the sources and also found some mails in the archives where this
> issue had been discussed. The problem appears to be still present in the
> current CVS version.
> 
> I've worked on a fix today that works for me. It's perhaps not the best
> solution but it's simple :-)
> 
> The basic strategy is to fix pqFlush and pqPutBytes.
> 
> The problem with pqFlush as it stands now is that it returns EOF when an
> error occurs or when not all data could be sent. The latter case is
> clearly not an error for a non-blocking connection but the caller can't
> distringuish it from an error very well.
> 
> The first part of the fix is therefore to fix pqFlush. This is done by
> to renaming it to pqFlushSome which only differs from pqFlush in its
> return values to allow the caller to make the above distinction and a
> new pqFlush which is implemented in terms of pqFlushSome and behaves
> exactly like the old pqFlush.
> 
> The second part of the fix modifies pqPutBytes to use pqFlushSome
> instead of pqFlush and to either send all the data or if not all data
> can be sent on a non-blocking connection to at least put all data into
> the output buffer, enlarging it if necessary.
> 
> I've also added a new API function PQflushSome which analogously to
> PQflush just calls pqFlushSome. Programs using PQsendQuery should use
> this new function. The main difference is that this function will have
> to be called repeatedly (calling select() properly in between) until all
> data has been written.
> 
> 
> Being new to postgresql development I'm not completely sure how to
> proceed from here. Is it OK if I post the patch here?
> 
> 
>    Bernhard
> 
> 
> -- 
> Intevation GmbH                                 http://intevation.de/
> Sketch                                 http://sketch.sourceforge.net/
> MapIt!                                               http://mapit.de/
> 
> ---------------------------(end of broadcast)---------------------------
> TIP 5: Have you checked our extensive FAQ?
> 
> http://www.postgresql.org/users-lounge/docs/faq.html
> 

--  Bruce Momjian                        |  http://candle.pha.pa.us pgman@candle.pha.pa.us               |  (610)
853-3000+  If your life is a hard drive,     |  830 Blythe Avenue +  Christ can be your backup.        |  Drexel Hill,
Pennsylvania19026