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

Commit22c9c8a

Browse files
committed
Fix potential deadlock with libpq non-blocking mode.
If libpq output buffer is full, pqSendSome() function tries to drain anyincoming data. This avoids deadlock, if the server e.g. sends a lot ofNOTICE messages, and blocks until we read them. However, pqSendSome() onlydid that in blocking mode. In non-blocking mode, the deadlock could stillhappen.To fix, take a two-pronged approach:1. Change the documentation to instruct that when PQflush() returns 1, youshould wait for both read- and write-ready, and call PQconsumeInput() if itbecomes read-ready. That fixes the deadlock, but applications are not goingto change overnight.2. In pqSendSome(), drain the input buffer before returning 1. Thisalleviates the problem for applications that only wait for write-ready. Inparticular, a slow but steady stream of NOTICE messages during COPY FROMSTDIN will no longer cause a deadlock. The risk remains that the serverattempts to send a large burst of data and fills its output buffer, and atthe same time the client also sends enough data to fill its output buffer.The application will deadlock if it goes to sleep, waiting for the socketto become write-ready, before the server's data arrives. In practice,NOTICE messages and such that the server might be sending are usuallyshort, so it's highly unlikely that the server would fill its output bufferso quickly.Backpatch to all supported versions.
1 parent83c3115 commit22c9c8a

File tree

2 files changed

+25
-11
lines changed

2 files changed

+25
-11
lines changed

‎doc/src/sgml/libpq.sgml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4272,7 +4272,14 @@ int PQflush(PGconn *conn);
42724272
<para>
42734273
After sending any command or data on a nonblocking connection, call
42744274
<function>PQflush</function>. If it returns 1, wait for the socket
4275-
to be write-ready and call it again; repeat until it returns 0. Once
4275+
to become read- or write-ready. If it becomes write-ready, call
4276+
<function>PQflush</function> again. If it becomes read-ready, call
4277+
<function>PQconsumeInput</function>, then call
4278+
<function>PQflush</function> again. Repeat until
4279+
<function>PQflush</function> returns 0. (It is necessary to check for
4280+
read-ready and drain the input with <function>PQconsumeInput</function>,
4281+
because the server can block trying to send us data, e.g. NOTICE
4282+
messages, and won't read our data until we read its.) Once
42764283
<function>PQflush</function> returns 0, wait for the socket to be
42774284
read-ready and then read the response as described above.
42784285
</para>

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

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -908,16 +908,6 @@ pqSendSome(PGconn *conn, int len)
908908
/*
909909
* We didn't send it all, wait till we can send more.
910910
*
911-
* If the connection is in non-blocking mode we don't wait, but
912-
* return 1 to indicate that data is still pending.
913-
*/
914-
if (pqIsnonblocking(conn))
915-
{
916-
result=1;
917-
break;
918-
}
919-
920-
/*
921911
* There are scenarios in which we can't send data because the
922912
* communications channel is full, but we cannot expect the server
923913
* to clear the channel eventually because it's blocked trying to
@@ -928,12 +918,29 @@ pqSendSome(PGconn *conn, int len)
928918
* again. Furthermore, it is possible that such incoming data
929919
* might not arrive until after we've gone to sleep. Therefore,
930920
* we wait for either read ready or write ready.
921+
*
922+
* In non-blocking mode, we don't wait here directly, but return
923+
* 1 to indicate that data is still pending. The caller should
924+
* wait for both read and write ready conditions, and call
925+
* PQconsumeInput() on read ready, but just in case it doesn't, we
926+
* call pqReadData() ourselves before returning. That's not
927+
* enough if the data has not arrived yet, but it's the best we
928+
* can do, and works pretty well in practice. (The documentation
929+
* used to say that you only need to wait for write-ready, so
930+
* there are still plenty of applications like that out there.)
931931
*/
932932
if (pqReadData(conn)<0)
933933
{
934934
result=-1;/* error message already set up */
935935
break;
936936
}
937+
938+
if (pqIsnonblocking(conn))
939+
{
940+
result=1;
941+
break;
942+
}
943+
937944
if (pqWait(TRUE, TRUE,conn))
938945
{
939946
result=-1;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp