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

Commit8878eaa

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 parent2ed7ef9 commit8878eaa

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
@@ -3919,7 +3919,14 @@ int PQflush(PGconn *conn);
39193919
<para>
39203920
After sending any command or data on a nonblocking connection, call
39213921
<function>PQflush</function>. If it returns 1, wait for the socket
3922-
to be write-ready and call it again; repeat until it returns 0. Once
3922+
to become read- or write-ready. If it becomes write-ready, call
3923+
<function>PQflush</function> again. If it becomes read-ready, call
3924+
<function>PQconsumeInput</function>, then call
3925+
<function>PQflush</function> again. Repeat until
3926+
<function>PQflush</function> returns 0. (It is necessary to check for
3927+
read-ready and drain the input with <function>PQconsumeInput</function>,
3928+
because the server can block trying to send us data, e.g. NOTICE
3929+
messages, and won't read our data until we read its.) Once
39233930
<function>PQflush</function> returns 0, wait for the socket to be
39243931
read-ready and then read the response as described above.
39253932
</para>

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

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -874,16 +874,6 @@ pqSendSome(PGconn *conn, int len)
874874
/*
875875
* We didn't send it all, wait till we can send more.
876876
*
877-
* If the connection is in non-blocking mode we don't wait, but
878-
* return 1 to indicate that data is still pending.
879-
*/
880-
if (pqIsnonblocking(conn))
881-
{
882-
result=1;
883-
break;
884-
}
885-
886-
/*
887877
* There are scenarios in which we can't send data because the
888878
* communications channel is full, but we cannot expect the server
889879
* to clear the channel eventually because it's blocked trying to
@@ -894,12 +884,29 @@ pqSendSome(PGconn *conn, int len)
894884
* again. Furthermore, it is possible that such incoming data
895885
* might not arrive until after we've gone to sleep. Therefore,
896886
* we wait for either read ready or write ready.
887+
*
888+
* In non-blocking mode, we don't wait here directly, but return
889+
* 1 to indicate that data is still pending. The caller should
890+
* wait for both read and write ready conditions, and call
891+
* PQconsumeInput() on read ready, but just in case it doesn't, we
892+
* call pqReadData() ourselves before returning. That's not
893+
* enough if the data has not arrived yet, but it's the best we
894+
* can do, and works pretty well in practice. (The documentation
895+
* used to say that you only need to wait for write-ready, so
896+
* there are still plenty of applications like that out there.)
897897
*/
898898
if (pqReadData(conn)<0)
899899
{
900900
result=-1;/* error message already set up */
901901
break;
902902
}
903+
904+
if (pqIsnonblocking(conn))
905+
{
906+
result=1;
907+
break;
908+
}
909+
903910
if (pqWait(TRUE, TRUE,conn))
904911
{
905912
result=-1;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp