Description:
After fixing the top-level nonblocking issue for mysql_real_connect_nonblocking() (https://bugs.mysql.com/bug.php?id=98574) it appears that the csm_complete_connect state inside it is still blocking. The function always goes into a wait state if there is a connect timeout specified.
How to repeat:
After applying the fix for 98574, make the following changes:
diff --git a/testclients/mysql_client_test.cc b/testclients/mysql_client_test.cc
index 2c45d41da89..31b33cbd025 100644
--- a/testclients/mysql_client_test.cc
+++ b/testclients/mysql_client_test.cc
@@ -30,6 +30,8 @@
contains only the actual tests, plus the list of test functions to call.
*/
+#include <chrono>
+
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
@@ -20580,6 +20592,42 @@ static void test_bug30032302() {
check_warning(mysql);
}
+static void test_csm_complete_connect() {
+ MYSQL *mysql_local;
+
+ // Create a socket for the client to connect to. If nonblocking is working
+ // correctly the mysql_real_connect_nonblocking will always return
+ // NET_ASYNC_NOT_READY almost immediately.
+ if (!(mysql_local = mysql_client_init(NULL))) {
+ myerror("mysql_client_init() failed");
+ exit(1);
+ }
+
+ uint ctimeout = 5;
+ mysql_options(mysql_local, MYSQL_OPT_CONNECT_TIMEOUT, &ctimeout);
+
+ auto port = 30000;
+ auto sock = socket(AF_INET, SOCK_STREAM, 0);
+ sockaddr_in addr;
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ auto res = bind(sock, (sockaddr*) &addr, sizeof(addr));
+ DIE_UNLESS(res != -1);
+ res = listen(sock, 1);
+ DIE_UNLESS(res != -1);
+ for (auto ii = 0; ii < 5; ii++) {
+ auto start = std::chrono::steady_clock::now();
+ auto status = mysql_real_connect_nonblocking(
+ mysql_local, "127.0.0.1", opt_user, opt_password, current_db, port,
+ opt_unix_socket, CLIENT_MULTI_STATEMENTS);
+ auto end = std::chrono::steady_clock::now();
+ auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(end - start);
+ DIE_UNLESS(elapsed.count() < 1);
+ DIE_UNLESS(status == NET_ASYNC_NOT_READY);
+ }
+}
+
static struct my_tests_st my_tests[] = {
{"disable_query_logs", disable_query_logs},
{"test_view_sp_list_fields", test_view_sp_list_fields},
@@ -20866,6 +20914,7 @@ static struct my_tests_st my_tests[] = {
{"test_wl11772", test_wl11772},
{"test_wl12475", test_wl12475},
{"test_bug30032302", test_bug30032302},
+ {"test_csm_complete_connect", test_csm_complete_connect},
{0, 0}};
static struct my_tests_st *get_my_tests() { return my_tests; }
Then when running the mysql_client_test the system will fail because the mysql_real_connect_nonblocking will block for 5 seconds. With the following fix the test will run correctly.
Suggested fix:
diff --git a/sql-common/client.cc b/sql-common/client.cc
index fd36e9950cf..8d66cbdbb0c 100644
--- a/sql-common/client.cc
+++ b/sql-common/client.cc
@@ -6174,6 +6179,7 @@ static mysql_state_machine_status csm_complete_connect(
/* Get version info */
mysql->protocol_version = PROTOCOL_VERSION; /* Assume this */
if (mysql->options.connect_timeout &&
+ !ctx->non_blocking &&
(vio_io_wait(net->vio, VIO_IO_EVENT_READ,
get_vio_connect_timeout(mysql)) < 1)) {
set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,