1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-30 11:03:19 +03:00

Fix unwanted flushing of libpq's input buffer when socket EOF is seen.

In commit 210eb9b743 I centralized libpq's logic for closing down
the backend communication socket, and made the new pqDropConnection
routine always reset the I/O buffers to empty.  Many of the call sites
previously had not had such code, and while that amounted to an oversight
in some cases, there was one place where it was intentional and necessary
*not* to flush the input buffer: pqReadData should never cause that to
happen, since we probably still want to process whatever data we read.

This is the true cause of the problem Robert was attempting to fix in
c3e7c24a1d, namely that libpq no longer reported the backend's final
ERROR message before reporting "server closed the connection unexpectedly".
But that only accidentally fixed it, by invoking parseInput before the
input buffer got flushed; and very likely there are timing scenarios
where we'd still lose the message before processing it.

To fix, pass a flag to pqDropConnection to tell it whether to flush the
input buffer or not.  On review I think flushing is actually correct for
every other call site.

Back-patch to 9.3 where the problem was introduced.  In HEAD, also improve
the comments added by c3e7c24a1d.
This commit is contained in:
Tom Lane
2015-11-12 13:03:52 -05:00
parent c3e7c24a1d
commit c405918858
5 changed files with 37 additions and 27 deletions

View File

@ -1553,8 +1553,10 @@ sendFailed:
/*
* pqHandleSendFailure: try to clean up after failure to send command.
*
* Primarily, what we want to accomplish here is to process any messages that
* the backend might have sent just before it died.
* Primarily, what we want to accomplish here is to process any ERROR or
* NOTICE messages that the backend might have sent just before it died.
* Since we're in IDLE state, all such messages will get sent to the notice
* processor.
*
* NOTE: this routine should only be called in PGASYNC_IDLE state.
*/
@ -1562,16 +1564,17 @@ void
pqHandleSendFailure(PGconn *conn)
{
/*
* Accept and parse any available input data. Note that if pqReadData
* decides the backend has closed the channel, it will close our side of
* the socket --- that's just what we want here.
* Accept and parse any available input data, ignoring I/O errors. Note
* that if pqReadData decides the backend has closed the channel, it will
* close our side of the socket --- that's just what we want here.
*/
while (pqReadData(conn) > 0)
parseInput(conn);
/*
* Make one attempt to parse available input messages even if we read no
* data.
* Be sure to parse available input messages even if we read no data.
* (Note: calling parseInput within the above loop isn't really necessary,
* but it prevents buffer bloat if there's a lot of data available.)
*/
parseInput(conn);
}