Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitc405918

Browse files
committed
Fix unwanted flushing of libpq's input buffer when socket EOF is seen.
In commit210eb9b I centralized libpq's logic for closing downthe backend communication socket, and made the new pqDropConnectionroutine always reset the I/O buffers to empty. Many of the call sitespreviously had not had such code, and while that amounted to an oversightin some cases, there was one place where it was intentional and necessary*not* to flush the input buffer: pqReadData should never cause that tohappen, since we probably still want to process whatever data we read.This is the true cause of the problem Robert was attempting to fix inc3e7c24, namely that libpq no longer reported the backend's finalERROR message before reporting "server closed the connection unexpectedly".But that only accidentally fixed it, by invoking parseInput before theinput buffer got flushed; and very likely there are timing scenarioswhere we'd still lose the message before processing it.To fix, pass a flag to pqDropConnection to tell it whether to flush theinput buffer or not. On review I think flushing is actually correct forevery other call site.Back-patch to 9.3 where the problem was introduced. In HEAD, also improvethe comments added byc3e7c24.
1 parentc3e7c24 commitc405918

File tree

5 files changed

+37
-27
lines changed

5 files changed

+37
-27
lines changed

‎src/interfaces/libpq/fe-connect.c

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -391,18 +391,24 @@ pgthreadlock_t pg_g_threadlock = default_threadlock;
391391
* Close any physical connection to the server, and reset associated
392392
* state inside the connection object. We don't release state that
393393
* would be needed to reconnect, though.
394+
*
395+
* We can always flush the output buffer, since there's no longer any hope
396+
* of sending that data. However, unprocessed input data might still be
397+
* valuable, so the caller must tell us whether to flush that or not.
394398
*/
395399
void
396-
pqDropConnection(PGconn*conn)
400+
pqDropConnection(PGconn*conn,boolflushInput)
397401
{
398402
/* Drop any SSL state */
399403
pqsecure_close(conn);
400404
/* Close the socket itself */
401405
if (conn->sock!=PGINVALID_SOCKET)
402406
closesocket(conn->sock);
403407
conn->sock=PGINVALID_SOCKET;
404-
/* Discard any unread/unsent data */
405-
conn->inStart=conn->inCursor=conn->inEnd=0;
408+
/* Optionally discard any unread data */
409+
if (flushInput)
410+
conn->inStart=conn->inCursor=conn->inEnd=0;
411+
/* Always discard any unsent data */
406412
conn->outCount=0;
407413
}
408414

@@ -1510,7 +1516,7 @@ connectDBStart(PGconn *conn)
15101516
return1;
15111517

15121518
connect_errReturn:
1513-
pqDropConnection(conn);
1519+
pqDropConnection(conn, true);
15141520
conn->status=CONNECTION_BAD;
15151521
return0;
15161522
}
@@ -1732,7 +1738,7 @@ PQconnectPoll(PGconn *conn)
17321738
{
17331739
if (!connectNoDelay(conn))
17341740
{
1735-
pqDropConnection(conn);
1741+
pqDropConnection(conn, true);
17361742
conn->addr_cur=addr_cur->ai_next;
17371743
continue;
17381744
}
@@ -1742,7 +1748,7 @@ PQconnectPoll(PGconn *conn)
17421748
appendPQExpBuffer(&conn->errorMessage,
17431749
libpq_gettext("could not set socket to nonblocking mode: %s\n"),
17441750
SOCK_STRERROR(SOCK_ERRNO,sebuf,sizeof(sebuf)));
1745-
pqDropConnection(conn);
1751+
pqDropConnection(conn, true);
17461752
conn->addr_cur=addr_cur->ai_next;
17471753
continue;
17481754
}
@@ -1753,7 +1759,7 @@ PQconnectPoll(PGconn *conn)
17531759
appendPQExpBuffer(&conn->errorMessage,
17541760
libpq_gettext("could not set socket to close-on-exec mode: %s\n"),
17551761
SOCK_STRERROR(SOCK_ERRNO,sebuf,sizeof(sebuf)));
1756-
pqDropConnection(conn);
1762+
pqDropConnection(conn, true);
17571763
conn->addr_cur=addr_cur->ai_next;
17581764
continue;
17591765
}
@@ -1800,7 +1806,7 @@ PQconnectPoll(PGconn *conn)
18001806

18011807
if (err)
18021808
{
1803-
pqDropConnection(conn);
1809+
pqDropConnection(conn, true);
18041810
conn->addr_cur=addr_cur->ai_next;
18051811
continue;
18061812
}
@@ -1887,7 +1893,7 @@ PQconnectPoll(PGconn *conn)
18871893
* failure and keep going if there are more addresses.
18881894
*/
18891895
connectFailureMessage(conn,SOCK_ERRNO);
1890-
pqDropConnection(conn);
1896+
pqDropConnection(conn, true);
18911897

18921898
/*
18931899
* Try the next address, if any.
@@ -1932,7 +1938,7 @@ PQconnectPoll(PGconn *conn)
19321938
* error message.
19331939
*/
19341940
connectFailureMessage(conn,optval);
1935-
pqDropConnection(conn);
1941+
pqDropConnection(conn, true);
19361942

19371943
/*
19381944
* If more addresses remain, keep trying, just as in the
@@ -2220,7 +2226,7 @@ PQconnectPoll(PGconn *conn)
22202226
/* only retry once */
22212227
conn->allow_ssl_try= false;
22222228
/* Must drop the old connection */
2223-
pqDropConnection(conn);
2229+
pqDropConnection(conn, true);
22242230
conn->status=CONNECTION_NEEDED;
22252231
gotokeep_going;
22262232
}
@@ -2331,7 +2337,7 @@ PQconnectPoll(PGconn *conn)
23312337
{
23322338
conn->pversion=PG_PROTOCOL(2,0);
23332339
/* Must drop the old connection */
2334-
pqDropConnection(conn);
2340+
pqDropConnection(conn, true);
23352341
conn->status=CONNECTION_NEEDED;
23362342
gotokeep_going;
23372343
}
@@ -2397,7 +2403,7 @@ PQconnectPoll(PGconn *conn)
23972403
/* only retry once */
23982404
conn->wait_ssl_try= false;
23992405
/* Must drop the old connection */
2400-
pqDropConnection(conn);
2406+
pqDropConnection(conn, true);
24012407
conn->status=CONNECTION_NEEDED;
24022408
gotokeep_going;
24032409
}
@@ -2413,7 +2419,7 @@ PQconnectPoll(PGconn *conn)
24132419
/* only retry once */
24142420
conn->allow_ssl_try= false;
24152421
/* Must drop the old connection */
2416-
pqDropConnection(conn);
2422+
pqDropConnection(conn, true);
24172423
conn->status=CONNECTION_NEEDED;
24182424
gotokeep_going;
24192425
}
@@ -2574,7 +2580,7 @@ PQconnectPoll(PGconn *conn)
25742580
PQclear(res);
25752581
conn->send_appname= false;
25762582
/* Must drop the old connection */
2577-
pqDropConnection(conn);
2583+
pqDropConnection(conn, true);
25782584
conn->status=CONNECTION_NEEDED;
25792585
gotokeep_going;
25802586
}
@@ -2971,7 +2977,7 @@ closePGconn(PGconn *conn)
29712977
/*
29722978
* Close the connection, reset all transient state, flush I/O buffers.
29732979
*/
2974-
pqDropConnection(conn);
2980+
pqDropConnection(conn, true);
29752981
conn->status=CONNECTION_BAD;/* Well, not really _bad_ - just
29762982
* absent */
29772983
conn->asyncStatus=PGASYNC_IDLE;

‎src/interfaces/libpq/fe-exec.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1553,25 +1553,28 @@ PQsendQueryGuts(PGconn *conn,
15531553
/*
15541554
* pqHandleSendFailure: try to clean up after failure to send command.
15551555
*
1556-
* Primarily, what we want to accomplish here is to process any messages that
1557-
* the backend might have sent just before it died.
1556+
* Primarily, what we want to accomplish here is to process any ERROR or
1557+
* NOTICE messages that the backend might have sent just before it died.
1558+
* Since we're in IDLE state, all such messages will get sent to the notice
1559+
* processor.
15581560
*
15591561
* NOTE: this routine should only be called in PGASYNC_IDLE state.
15601562
*/
15611563
void
15621564
pqHandleSendFailure(PGconn*conn)
15631565
{
15641566
/*
1565-
* Accept and parse any available input data. Note that if pqReadData
1566-
* decides the backend has closed the channel, it will close our side of
1567-
* the socket --- that's just what we want here.
1567+
* Accept and parse any available input data, ignoring I/O errors. Note
1568+
*that if pqReadDatadecides the backend has closed the channel, it will
1569+
*close our side ofthe socket --- that's just what we want here.
15681570
*/
15691571
while (pqReadData(conn)>0)
15701572
parseInput(conn);
15711573

15721574
/*
1573-
* Make one attempt to parse available input messages even if we read no
1574-
* data.
1575+
* Be sure to parse available input messages even if we read no data.
1576+
* (Note: calling parseInput within the above loop isn't really necessary,
1577+
* but it prevents buffer bloat if there's a lot of data available.)
15751578
*/
15761579
parseInput(conn);
15771580
}

‎src/interfaces/libpq/fe-misc.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -815,7 +815,8 @@ pqReadData(PGconn *conn)
815815

816816
/* Come here if lower-level code already set a suitable errorMessage */
817817
definitelyFailed:
818-
pqDropConnection(conn);
818+
/* Do *not* drop any already-read data; caller still wants it */
819+
pqDropConnection(conn, false);
819820
conn->status=CONNECTION_BAD;/* No more connection to backend */
820821
return-1;
821822
}

‎src/interfaces/libpq/fe-protocol3.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -446,8 +446,8 @@ handleSyncLoss(PGconn *conn, char id, int msgLength)
446446
/* build an error result holding the error message */
447447
pqSaveErrorResult(conn);
448448
conn->asyncStatus=PGASYNC_READY;/* drop out of GetResult wait loop */
449-
450-
pqDropConnection(conn);
449+
/* flush input data since we're giving up on processing it */
450+
pqDropConnection(conn, true);
451451
conn->status=CONNECTION_BAD;/* No more connection to backend */
452452
}
453453

‎src/interfaces/libpq/libpq-int.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ extern char *const pgresStatus[];
515515

516516
/* === in fe-connect.c === */
517517

518-
externvoidpqDropConnection(PGconn*conn);
518+
externvoidpqDropConnection(PGconn*conn,boolflushInput);
519519
externintpqPacketSend(PGconn*conn,charpack_type,
520520
constvoid*buf,size_tbuf_len);
521521
externboolpqGetHomeDirectory(char*buf,intbufsize);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp