[Maria-developers] mysql_get_timeout_value returning 0 always

I am basing my work on the async_queries.c example. In my code, I am calling mysql_real_connect_start(), and the return value indicates that MySQL is waiting for READ and TIMEOUT. However, if I call mysql_get_timeout_value() (or the _ms() version) right after that, it returns 0. Is this expected? As far as I can see, this is causing the next call to mysql_real_connect_cont() (which happens immediately, because the timeout triggers right away) to return an error. This is on OS X 10.11.6 with the MariaDB client just installed via brew; mariadb_config --version says 5.5.1. This is the code I'm calling: status = mysql_real_connect_start(&ret, &mysql, h, u, p, d, 0, 0, 0); printf("MYSQL connect %d", status); if (status & MYSQL_WAIT_TIMEOUT) { unsigned int ms = mysql_get_timeout_value_ms(&mysql); printf(" and includes a timeout of %u ms", ms); } printf("\n"); That code prints: MYSQL connect 9 and includes a timeout of 0 ms I did find two ways to make the code work: 1. Not passing MYSQL_WAIT_TIMEOUT back to the mysql_real_connect_cont() (so it thinks a timeout has not happened at all). This allows all the queries to actually complete, but the code ends up polling heavily. 2. Forcing the return value of mysql_get_timeout_value_ms() to be > 0. This makes the code work beautifully, but of course I would rather follow MySQL's hint as to the timeout extension. I would appreciate any hints as to what I am missing. Thanks much in advance. -- Gonzalo Diethelm gonzalo.diethelm@gmail.com

Gonzalo Diethelm <gonzalo.diethelm@gmail.com> writes:
In my code, I am calling mysql_real_connect_start(), and the return value indicates that MySQL is waiting for READ and TIMEOUT. However, if I call mysql_get_timeout_value() (or the _ms() version) right after that, it returns 0. Is this expected? As far as I can see, this is causing the next
No, it is not expected. MYSQL_WAIT_TIMEOUT should only be returned in status if a non-zero MYSQL_OPT_CONNECT_TIMEOUT is set with mysql_options().
This is on OS X 10.11.6 with the MariaDB client just installed via brew; mariadb_config --version says 5.5.1.
Hm. Can you clarify exactly which version of the library you are using? Are you using the library that is bundled with the server (seems likely since you are using the async_queries.c example from the server source tree)? Or are you using the separate connector-c library? Version 5.5.1 of the server did not include the non-blocking library...
This is the code I'm calling:
status = mysql_real_connect_start(&ret, &mysql, h, u, p, d, 0, 0, 0); printf("MYSQL connect %d", status); if (status & MYSQL_WAIT_TIMEOUT) { unsigned int ms = mysql_get_timeout_value_ms(&mysql); printf(" and includes a timeout of %u ms", ms); } printf("\n");
I tried adding this to async_queries.c, but I could not reproduce. I get MYSQL connect 2 If I add to the source unsigned int my_timeout = 10; mysql_options(&sds[i].mysql, MYSQL_OPT_CONNECT_TIMEOUT, &my_timeout); I get: MYSQL connect 10 and includes a timeout of 10000 ms Can you try to apply the attached patch to async_queries.c and see if you can reproduce the problem with that code? If so, maybe it is something specific to OS X? If not, then maybe something goes wrong in your code?
That code prints: MYSQL connect 9 and includes a timeout of 0 ms
The thing is, the only places in the code that set MYSQL_WAIT_TIMEOUT() look like this: if (vio_timeout >= 0) { b->timeout_value= vio_timeout; b->events_to_wait_for|= MYSQL_WAIT_TIMEOUT; } And mysql_get_timeout_value_ms() basically returns b->timeout_value. So it is surprising to see your code getting MYSQL_WAIT_TIMEOUT with a zero value for timeout...
I did find two ways to make the code work:
1. Not passing MYSQL_WAIT_TIMEOUT back to the mysql_real_connect_cont() (so it thinks a timeout has not happened at all). This allows all the queries to actually complete, but the code ends up polling heavily.
Not passing MYSQL_WAIT_TIMEOUT back should not cause any polling (though it will disable the timeout functionality). But nor should it be necessary to special case this, obviously. Hope this helps, - Kristian.

Hi Kristian, thanks for your reply. This is what brew info says: $ brew info mariadb-connector-c mariadb-connector-c: stable 2.2.2 (bottled) MariaDB database connector for C applications https://downloads.mariadb.org/connector-c/ Notice that in the code snippet you sent, the comparison is greater than *or equal to* zero; this could in fact add a zero timeout, right? if (vio_timeout >= 0) { b->timeout_value= vio_timeout; b->events_to_wait_for|= MYSQL_WAIT_TIMEOUT; } By not passing MYSQL_WAIT_TIMEOUT back to the mysql_real_connect_cont() call, the call returns right away, and I end up busy-polling it until the connection is complete. That's what I meant by polling; I was just mentioning that I tried that, of course that would not be a long-term solution. I tried adding the CONNECT_TIMEOUT option, and now the timeout for the mysql_real_connect_start() call does come back as 10_000 ms, but the timeout for the mysql_real_connect_cont() still keeps coming as zero. Cheers, Gonzo On Fri, Sep 23, 2016 at 4:21 PM, Kristian Nielsen <knielsen@knielsen-hq.org> wrote:
Gonzalo Diethelm <gonzalo.diethelm@gmail.com> writes:
In my code, I am calling mysql_real_connect_start(), and the return value indicates that MySQL is waiting for READ and TIMEOUT. However, if I call mysql_get_timeout_value() (or the _ms() version) right after that, it returns 0. Is this expected? As far as I can see, this is causing the next
No, it is not expected. MYSQL_WAIT_TIMEOUT should only be returned in status if a non-zero MYSQL_OPT_CONNECT_TIMEOUT is set with mysql_options().
This is on OS X 10.11.6 with the MariaDB client just installed via brew; mariadb_config --version says 5.5.1.
Hm. Can you clarify exactly which version of the library you are using? Are you using the library that is bundled with the server (seems likely since you are using the async_queries.c example from the server source tree)? Or are you using the separate connector-c library?
Version 5.5.1 of the server did not include the non-blocking library...
This is the code I'm calling:
status = mysql_real_connect_start(&ret, &mysql, h, u, p, d, 0, 0, 0); printf("MYSQL connect %d", status); if (status & MYSQL_WAIT_TIMEOUT) { unsigned int ms = mysql_get_timeout_value_ms(&mysql); printf(" and includes a timeout of %u ms", ms); } printf("\n");
I tried adding this to async_queries.c, but I could not reproduce. I get
MYSQL connect 2
If I add to the source
unsigned int my_timeout = 10; mysql_options(&sds[i].mysql, MYSQL_OPT_CONNECT_TIMEOUT, &my_timeout);
I get:
MYSQL connect 10 and includes a timeout of 10000 ms
Can you try to apply the attached patch to async_queries.c and see if you can reproduce the problem with that code? If so, maybe it is something specific to OS X? If not, then maybe something goes wrong in your code?
That code prints: MYSQL connect 9 and includes a timeout of 0 ms
The thing is, the only places in the code that set MYSQL_WAIT_TIMEOUT() look like this:
if (vio_timeout >= 0) { b->timeout_value= vio_timeout; b->events_to_wait_for|= MYSQL_WAIT_TIMEOUT; }
And mysql_get_timeout_value_ms() basically returns b->timeout_value. So it is surprising to see your code getting MYSQL_WAIT_TIMEOUT with a zero value for timeout...
I did find two ways to make the code work:
1. Not passing MYSQL_WAIT_TIMEOUT back to the mysql_real_connect_cont() (so it thinks a timeout has not happened at all). This allows all the queries to actually complete, but the code ends up polling heavily.
Not passing MYSQL_WAIT_TIMEOUT back should not cause any polling (though it will disable the timeout functionality). But nor should it be necessary to special case this, obviously.
Hope this helps,
- Kristian.
diff --git a/tests/async_queries.c b/tests/async_queries.c index 76e884e..486458c 100644 --- a/tests/async_queries.c +++ b/tests/async_queries.c @@ -168,6 +168,12 @@ state_machine_handler(int fd __attribute__((unused)), short event, void *arg) case 0: /* Initial state, start making the connection. */ status= mysql_real_connect_start(&sd->ret, &sd->mysql, opt_host, opt_user, opt_password, opt_db, opt_port, opt_socket, 0); + printf("MYSQL connect %d", status); + if (status & MYSQL_WAIT_TIMEOUT) { + unsigned int ms = mysql_get_timeout_value_ms(&sd->mysql); + printf(" and includes a timeout of %u ms", ms); + } + printf("\n"); if (status) /* Wait for connect to complete. */ next_event(1, status, sd); @@ -410,9 +416,11 @@ main(int argc, char *argv[]) num_active_connections= 0; for (i= 0; i < opt_connections; i++) { + unsigned int my_timeout = 10; mysql_init(&sds[i].mysql); mysql_options(&sds[i].mysql, MYSQL_OPT_NONBLOCK, 0); mysql_options(&sds[i].mysql, MYSQL_READ_DEFAULT_GROUP, "async_queries"); + mysql_options(&sds[i].mysql, MYSQL_OPT_CONNECT_TIMEOUT, &my_timeout);
/* We put the initial connect call in the first state 0 of the state machine
-- Gonzalo Diethelm gonzalo.diethelm@gmail.com

Gonzalo Diethelm <gonzalo.diethelm@gmail.com> writes:
$ brew info mariadb-connector-c mariadb-connector-c: stable 2.2.2 (bottled) MariaDB database connector for C applications https://downloads.mariadb.org/connector-c/
Ok, so this is the separate client library, not the one in the server.
Notice that in the code snippet you sent, the comparison is greater than *or equal to* zero; this could in fact add a zero timeout, right?
if (vio_timeout >= 0) { b->timeout_value= vio_timeout; b->events_to_wait_for|= MYSQL_WAIT_TIMEOUT; }
Yes, you are right of course. But now I see it: For the application, zero means no timeout. Internally in the code, this is converted to -1 meaning no timeout. And while this looks correct in the server library, the connector-c standalone library seems to do this incorrectly: void vio_read_timeout(Vio *vio, uint timeout) { vio->read_timeout= (timeout >= 0) ? timeout * 1000 : -1; } int vio_timeout= (mysql->options.connect_timeout >= 0) ? mysql->options.connect_timeout * 1000 : -1; This code is comparing an unsigned value >= 0; the comparison should be >0 (an unsigned value is always >= 0, so this is obviously wrong). So I was able to reproduce your problem with version 2.2.2 of the standalone library. However, recent changes seem to have fixed it, I could no longer reproduce. In particular it seems fixed after these three commits which seem to rewrite the I/O part of the library: ----------------------------------------------------------------------- commit a349bee53d38ee133b949b20f84ccc29d3aa4465 (refs/bisect/bad) Author: Georg Richter <georg@mariadb.com> Date: Thu Aug 6 15:10:34 2015 +0200 Added more files commit cc85e256666a826d3247e72ea39c5332bff721bf (refs/bisect/skip-cc85e256666a826d3247e72ea39c5332bff721bf) Author: Georg Richter <georg@mariadb.com> Date: Thu Aug 6 15:08:25 2015 +0200 Added missing cio components commit f886562fb2c411bc7ff870d75a872d906674015b (refs/bisect/skip-f886562fb2c411bc7ff870d75a872d906674015b) Author: Georg Richter <georg@mariadb.com> Date: Thu Aug 6 13:06:54 2015 +0200 Initial cio implementation ----------------------------------------------------------------------- Wlad, Georg, what are the plans for Connector-C? Will the current master branch be released as an update for the stand-alone client library? Or only as part of 10.2? In the latter case, do you agree that a bugfix like the below patch is needed for existing stable releases of Connector-C? Since it seems that without it, timeout for non-blocking connects (and read/writes?) is completely broken? Gonzola, thanks for bringing this to attention! If possible, you could try checking the latest git source code if your problem is indeed solved. Otherwise, one workaround until a fix is released is to use the libmysqlclient supplied as part of the MariaDB server release. Alternatively, change your code to interpret MYSQL_WAIT_TIMEOUT with a zero value from mysql_get_timeout_value() the same as no MYSQL_WAIT_TIMEOUT. This change will still be correct (though redundant) after the library is fixed, as MYSQL_WAIT_TIMEOUT can never legally have a zero timeout. Thanks, - Kristian.

Hi Kristian, Well, that's awesome. Thanks for taking the time to dig into this. I have added the workaround you suggested (ignoring timeouts with a zero value), and on Monday I will check the connector github repo and test again. Best regards, Gonzalo On Sat, Sep 24, 2016 at 1:42 PM, Kristian Nielsen <knielsen@knielsen-hq.org> wrote:
Gonzalo Diethelm <gonzalo.diethelm@gmail.com> writes:
$ brew info mariadb-connector-c mariadb-connector-c: stable 2.2.2 (bottled) MariaDB database connector for C applications https://downloads.mariadb.org/connector-c/
Ok, so this is the separate client library, not the one in the server.
Notice that in the code snippet you sent, the comparison is greater than *or equal to* zero; this could in fact add a zero timeout, right?
if (vio_timeout >= 0) { b->timeout_value= vio_timeout; b->events_to_wait_for|= MYSQL_WAIT_TIMEOUT; }
Yes, you are right of course. But now I see it: For the application, zero means no timeout. Internally in the code, this is converted to -1 meaning no timeout.
And while this looks correct in the server library, the connector-c standalone library seems to do this incorrectly:
void vio_read_timeout(Vio *vio, uint timeout) { vio->read_timeout= (timeout >= 0) ? timeout * 1000 : -1; }
int vio_timeout= (mysql->options.connect_timeout >= 0) ? mysql->options.connect_timeout * 1000 : -1;
This code is comparing an unsigned value >= 0; the comparison should be >0 (an unsigned value is always >= 0, so this is obviously wrong).
So I was able to reproduce your problem with version 2.2.2 of the standalone library. However, recent changes seem to have fixed it, I could no longer reproduce. In particular it seems fixed after these three commits which seem to rewrite the I/O part of the library:
----------------------------------------------------------------------- commit a349bee53d38ee133b949b20f84ccc29d3aa4465 (refs/bisect/bad) Author: Georg Richter <georg@mariadb.com> Date: Thu Aug 6 15:10:34 2015 +0200
Added more files
commit cc85e256666a826d3247e72ea39c5332bff721bf (refs/bisect/skip- cc85e256666a826d3247e72ea39c5332bff721bf) Author: Georg Richter <georg@mariadb.com> Date: Thu Aug 6 15:08:25 2015 +0200
Added missing cio components
commit f886562fb2c411bc7ff870d75a872d906674015b (refs/bisect/skip- f886562fb2c411bc7ff870d75a872d906674015b) Author: Georg Richter <georg@mariadb.com> Date: Thu Aug 6 13:06:54 2015 +0200
Initial cio implementation -----------------------------------------------------------------------
Wlad, Georg, what are the plans for Connector-C? Will the current master branch be released as an update for the stand-alone client library? Or only as part of 10.2?
In the latter case, do you agree that a bugfix like the below patch is needed for existing stable releases of Connector-C? Since it seems that without it, timeout for non-blocking connects (and read/writes?) is completely broken?
Gonzola, thanks for bringing this to attention! If possible, you could try checking the latest git source code if your problem is indeed solved.
Otherwise, one workaround until a fix is released is to use the libmysqlclient supplied as part of the MariaDB server release.
Alternatively, change your code to interpret MYSQL_WAIT_TIMEOUT with a zero value from mysql_get_timeout_value() the same as no MYSQL_WAIT_TIMEOUT. This change will still be correct (though redundant) after the library is fixed, as MYSQL_WAIT_TIMEOUT can never legally have a zero timeout.
Thanks,
- Kristian.
diff --git a/libmariadb/libmariadb.c b/libmariadb/libmariadb.c index 8fd87ba..23aa407 100644 --- a/libmariadb/libmariadb.c +++ b/libmariadb/libmariadb.c @@ -254,7 +254,7 @@ static int connect_sync_or_async(MYSQL *mysql, NET *net, my_socket fd, const struct sockaddr *name, uint namelen) { - int vio_timeout= (mysql->options.connect_timeout >= 0) ? + int vio_timeout= (mysql->options.connect_timeout > 0) ? mysql->options.connect_timeout * 1000 : -1;
if (mysql->options.extension && mysql->options.extension->async_context && @@ -1767,7 +1767,7 @@ MYSQL *mthd_my_real_connect(MYSQL *mysql, const char *host, const char *user, vio_write_timeout(net->vio, mysql->options.read_timeout); /* Get version info */ mysql->protocol_version= PROTOCOL_VERSION; /* Assume this */ - if (mysql->options.connect_timeout >= 0 && + if (mysql->options.connect_timeout > 0 && vio_wait_or_timeout(net->vio, FALSE, mysql->options.connect_timeout * 1000) < 1) { my_set_error(mysql, CR_SERVER_LOST, SQLSTATE_UNKNOWN, diff --git a/libmariadb/violite.c b/libmariadb/violite.c index 1fbdcc3..722724f 100644 --- a/libmariadb/violite.c +++ b/libmariadb/violite.c @@ -127,13 +127,13 @@ void vio_timeout(Vio *vio, int type, uint timeval)
void vio_read_timeout(Vio *vio, uint timeout) { - vio->read_timeout= (timeout >= 0) ? timeout * 1000 : -1; + vio->read_timeout= (timeout > 0) ? timeout * 1000 : -1; vio_timeout(vio, SO_RCVTIMEO, vio->read_timeout); }
void vio_write_timeout(Vio *vio, uint timeout) { - vio->write_timeout= (timeout >= 0) ? timeout * 1000 : -1; + vio->write_timeout= (timeout > 0) ? timeout * 1000 : -1; vio_timeout(vio, SO_SNDTIMEO, vio->write_timeout); }
-- Gonzalo Diethelm gonzalo.diethelm@gmail.com
participants (2)
-
Gonzalo Diethelm
-
Kristian Nielsen