| Bug #97853 | main.ssl-big-packet fails for async client | ||
|---|---|---|---|
| Submitted: | 2 Dec 2019 18:18 | Modified: | 18 Mar 2020 13:44 |
| Reporter: | Manuel Ung | Email Updates: | |
| Status: | Closed | Impact on me: | |
| Category: | MySQL Server: C API (client library) | Severity: | S3 (Non-critical) |
| Version: | 8.0.17 | OS: | Any |
| Assigned to: | CPU Architecture: | Any | |
[2 Dec 2019 18:55]
Manuel Ung
Another possible fix is just to call ppoll with timeout.
[2 Dec 2019 21:15]
MySQL Verification Team
Thank you for the bug report.
[3 Dec 2019 14:11]
Manuel Ung
Actually, the problem here seems to be mysqltest.cc should be listening for both reads/writes with SSL, because writes can happen during reads (and vice versa).
This change also fixes the issue:
diff --git a/client/mysqltest.cc b/client/mysqltest.cc
index bca4a6f3573..639f456fb28 100644
--- a/client/mysqltest.cc
+++ b/client/mysqltest.cc
@@ -857,19 +857,11 @@ static int socket_event_listen(net_async_block_state async_blocking_state,
int result;
pollfd pfd;
pfd.fd = fd;
- switch (async_blocking_state) {
- case NET_NONBLOCKING_READ:
- pfd.events = POLLIN;
- break;
- case NET_NONBLOCKING_WRITE:
- pfd.events = POLLOUT;
- break;
- case NET_NONBLOCKING_CONNECT:
- pfd.events = POLLIN | POLLOUT;
- break;
- default:
- DBUG_ASSERT(false);
- }
+ /*
+ Listen to both in/out because SSL can perform reads during writes (and
+ vice versa).
+ */
+ pfd.events = POLLIN | POLLOUT;
result = poll(&pfd, 1, -1);
if (result < 0) {
perror("poll");
[18 Mar 2020 13:44]
Paul DuBois
Posted by developer: Fixed in 8.0.21. Work was done for test suite. No changelog entry required.

Description: The main.ssl-big-packet mtr test fails for the async client because the client/server hangs, ending in timeout. The problem is that the mysqltest.cc driver calls ppoll when NET_ASYNC_NOT_READY is returned. However, the async client sometimes returns NET_ASYNC_NOT_READY even when it isn't necessarily waiting for more IO. You can verify this by removing the ppoll and spinning in a loop: diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 30d842436d1..ceaa815aa5f 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -901,10 +901,6 @@ static MYSQL_RES *async_mysql_store_result_wrapper(MYSQL *mysql) { while (mysql_store_result_nonblocking(mysql, &result) == NET_ASYNC_NOT_READY) { t.check(); - NET_ASYNC *net_async = NET_ASYNC_DATA(&(mysql->net)); - int result = socket_event_listen(net_async->async_blocking_state, - mysql_get_socket_descriptor(mysql)); - if (result == -1) return NULL; } return result; } How to repeat: ./mtr --async-client main.ssl-big-packet Suggested fix: Ideally, we should not be returning NET_ASYNC_NOT_READY up the API if there is no IO to do. Most async clients on upon receiving NET_ASYNC_NOT_READY, will not retry right away in a spinning fashion, and will most likely call ppoll on the file descriptor. This can block indefinitely if there is no actual io to do.