This repository has been archived by the owner. It is now read-only.
Permalink
Browse files

Support millisecond timeouts for reads, writes, and connects

Summary:
Feature: Millisecond Client Timeouts

This diff exposes three new client options:

MYSQL_OPT_CONNECT_TIMEOUT_MS
MYSQL_OPT_READ_TIMEOUT_MS
MYSQL_OPT_WRITE_TIMEOUT_MS

Which are similar to the non-_MS options, except the value is, of
course, in milliseconds.

This diff also changes a number of timeout-related codepaths to use a
structure rather than a naked integer.  This helps prevent many, many
classes of errors that come from accidentally multiplying or dividing by
1000 to convert (or forgetting to), and creates a form of type safety
for timeouts.

Test Plan: jenkins, mtr

Reviewers: pivanof, inaam-rana, darnaut

Reviewed By: darnaut

CC: jtolmer, MarkCallaghan, flamingcow, jeremycole, andrew-ford, liang.guo.752, chip, atcurtis

Differential Revision: https://reviews.facebook.net/D17019
  • Loading branch information...
steaphangreene committed Mar 17, 2014
1 parent fb29837 commit c1d98ebd607c571f554e96c2b477a7d9f826b4bf
Showing with 397 additions and 220 deletions.
  1. +16 −1 client/mysqltest.cc
  2. +3 −1 include/errmsg.h
  3. +7 −4 include/mysql.h
  4. +19 −3 include/mysql.h.pp
  5. +27 −3 include/mysql_com.h
  6. +7 −6 include/violite.h
  7. +2 −0 libmysql/errmsg.c
  8. +2 −2 libmysql/libmysql.c
  9. +1 −1 mysql-test/include/linux_sys_vars.inc
  10. +20 −0 mysql-test/r/connection_timeout.result
  11. +2 −2 mysql-test/r/mysqld--help-notwin-profiling.result
  12. +2 −2 mysql-test/r/mysqld--help-notwin.result
  13. +1 −1 mysql-test/suite/sys_vars/inc/binlog_cache_size_basic.inc
  14. +1 −1 mysql-test/suite/sys_vars/inc/binlog_stmt_cache_size_basic.inc
  15. +3 −3 mysql-test/suite/sys_vars/r/binlog_cache_size_basic_64.result
  16. +3 −3 mysql-test/suite/sys_vars/r/binlog_stmt_cache_size_basic_64.result
  17. +4 −4 mysql-test/suite/sys_vars/r/connect_timeout_basic.result
  18. +3 −3 mysql-test/suite/sys_vars/r/delayed_insert_timeout_basic.result
  19. +1 −1 mysql-test/suite/sys_vars/r/flush_time_basic.result
  20. +5 −5 mysql-test/suite/sys_vars/r/interactive_timeout_basic.result
  21. +22 −22 mysql-test/suite/sys_vars/r/lock_wait_timeout_basic.result
  22. +6 −6 mysql-test/suite/sys_vars/r/long_query_time_basic.result
  23. +5 −5 mysql-test/suite/sys_vars/r/net_read_timeout_basic.result
  24. +5 −5 mysql-test/suite/sys_vars/r/net_write_timeout_basic.result
  25. +7 −7 mysql-test/suite/sys_vars/r/rpl_stop_slave_timeout_basic.result
  26. +3 −3 mysql-test/suite/sys_vars/r/slave_net_timeout_basic.result
  27. +13 −13 mysql-test/suite/sys_vars/r/slow_launch_time_basic.result
  28. +1 −1 mysql-test/suite/sys_vars/r/table_definition_cache_basic.result
  29. +1 −1 mysql-test/suite/sys_vars/r/wait_timeout_basic.result
  30. +3 −3 mysql-test/suite/sys_vars/t/connect_timeout_basic.test
  31. +5 −5 mysql-test/suite/sys_vars/t/lock_wait_timeout_basic.test
  32. +2 −2 mysql-test/suite/sys_vars/t/long_query_time_basic.test
  33. +4 −4 mysql-test/suite/sys_vars/t/rpl_stop_slave_timeout_basic.test
  34. +3 −3 mysql-test/suite/sys_vars/t/slow_launch_time_basic.test
  35. +1 −1 mysql-test/suite/sys_vars/t/table_definition_cache_basic.test
  36. +1 −1 mysql-test/suite/sys_vars/t/wait_timeout_basic.test
  37. +1 −0 mysql-test/t/connection_timeout-mysqltest.opt
  38. +23 −0 mysql-test/t/connection_timeout.test
  39. +52 −29 sql-common/client.c
  40. +1 −1 sql/event_scheduler.cc
  41. +45 −6 sql/net_serv.cc
  42. +3 −2 sql/rpl_master.cc
  43. +4 −2 sql/sql_acl.cc
  44. +1 −1 sql/sql_class.cc
  45. +4 −4 sql/sql_class.h
  46. +6 −3 sql/sql_client.cc
  47. +8 −5 sql/sql_connect.cc
  48. +1 −1 sql/sql_const.h
  49. +4 −2 sql/sql_parse.cc
  50. +8 −6 sql/sys_vars.cc
  51. +1 −2 tests/mysql_client_test.c
  52. +10 −18 vio/vio.c
  53. +14 −10 vio/viosocket.c
@@ -5501,7 +5501,7 @@ void do_connect(struct st_command *command)
{
int con_port= opt_port;
char *con_options;
my_bool con_ssl= 0, con_compress= 0;
my_bool con_ssl= 0, con_compress= 0, con_timeout_1s=0, con_timeout_1500ms=0;
my_bool con_pipe= 0, con_shm= 0, con_cleartext_enable= 0;
my_bool con_secure_auth= 1;
struct st_connection* con_slot;
@@ -5589,6 +5589,10 @@ void do_connect(struct st_command *command)
con_ssl= 1;
else if (!strncmp(con_options, "COMPRESS", 8))
con_compress= 1;
else if (!strncmp(con_options, "TIMEOUT_1S", 10))
con_timeout_1s = 1;
else if (!strncmp(con_options, "TIMEOUT_1500MS", 14))
con_timeout_1500ms = 1;
else if (!strncmp(con_options, "PIPE", 4))
con_pipe= 1;
else if (!strncmp(con_options, "SHM", 3))
@@ -5629,6 +5633,17 @@ void do_connect(struct st_command *command)

if (opt_compress || con_compress)
mysql_options(&con_slot->mysql, MYSQL_OPT_COMPRESS, NullS);
if (con_timeout_1s) {
int timeout = 1;
mysql_options(&con_slot->mysql, MYSQL_OPT_READ_TIMEOUT, &timeout);
mysql_options(&con_slot->mysql, MYSQL_OPT_WRITE_TIMEOUT, &timeout);
mysql_options(&con_slot->mysql, MYSQL_OPT_CONNECT_TIMEOUT, &timeout);
} else if (con_timeout_1500ms) {
int timeout = 1500;
mysql_options(&con_slot->mysql, MYSQL_OPT_READ_TIMEOUT_MS, &timeout);
mysql_options(&con_slot->mysql, MYSQL_OPT_WRITE_TIMEOUT_MS, &timeout);
mysql_options(&con_slot->mysql, MYSQL_OPT_CONNECT_TIMEOUT_MS, &timeout);
}
mysql_options(&con_slot->mysql, MYSQL_OPT_LOCAL_INFILE, 0);
mysql_options(&con_slot->mysql, MYSQL_SET_CHARSET_NAME,
charset_info->csname);
@@ -104,7 +104,9 @@ extern const char *client_errors[]; /* Error messages */
#define CR_AUTH_PLUGIN_CANNOT_LOAD 2059
#define CR_DUPLICATE_CONNECTION_ATTR 2060
#define CR_AUTH_PLUGIN_ERR 2061
#define CR_ERROR_LAST /*Copy last error nr:*/ 2061
#define CR_NET_READ_INTERRUPTED 2062
#define CR_NET_WRITE_INTERRUPTED 2063
#define CR_ERROR_LAST /*Copy last error nr:*/ 2063
/* Add error numbers before CR_ERROR_LAST and change it accordingly. */

#endif /* ERRMSG_INCLUDED */
@@ -77,8 +77,8 @@ typedef int my_socket;
extern unsigned int mysql_port;
extern char *mysql_unix_port;

#define CLIENT_NET_READ_TIMEOUT 365*24*3600 /* Timeout on read */
#define CLIENT_NET_WRITE_TIMEOUT 365*24*3600 /* Timeout on write */
#define CLIENT_NET_READ_TIMEOUT 7*24*3600 /* Timeout on read */
#define CLIENT_NET_WRITE_TIMEOUT 7*24*3600 /* Timeout on write */

#define IS_PRI_KEY(n) ((n) & PRI_KEY_FLAG)
#define IS_NOT_NULL(n) ((n) & NOT_NULL_FLAG)
@@ -175,7 +175,10 @@ enum mysql_option
MYSQL_OPT_CONNECT_ATTR_DELETE,
MYSQL_SERVER_PUBLIC_KEY,
MYSQL_ENABLE_CLEARTEXT_PLUGIN,
MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS
MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS,
MYSQL_OPT_CONNECT_TIMEOUT_MS,
MYSQL_OPT_READ_TIMEOUT_MS,
MYSQL_OPT_WRITE_TIMEOUT_MS
};

/**
@@ -185,7 +188,7 @@ enum mysql_option
struct st_mysql_options_extention;

struct st_mysql_options {
unsigned int connect_timeout, read_timeout, write_timeout;
timeout_t connect_timeout, read_timeout, write_timeout;
unsigned int port, protocol;
unsigned long client_flag;
char *host,*user,*password,*unix_socket,*db;
@@ -14,6 +14,18 @@
COM_BINLOG_DUMP_GTID,
COM_END
};
C_MODE_START
typedef struct {
uint value_ms_;
} timeout_t;
timeout_t timeout_from_seconds(uint seconds);
timeout_t timeout_from_millis(uint ms);
timeout_t timeout_infinite();
my_bool timeout_is_infinite(const timeout_t t);
int timeout_is_nonzero(const timeout_t t);
uint timeout_to_millis(const timeout_t t);
uint timeout_to_seconds(const timeout_t t);
C_MODE_END
struct st_vio;
typedef struct st_vio Vio;
typedef struct st_net {
@@ -23,7 +35,8 @@
unsigned long remain_in_buf,length, buf_length, where_b;
unsigned long max_packet,max_packet_size;
unsigned int pkt_nr,compress_pkt_nr;
unsigned int write_timeout, read_timeout, retry_count;
timeout_t write_timeout, read_timeout;
uint retry_count;
int fcntl;
unsigned int *return_status;
unsigned char reading_or_writing;
@@ -272,11 +285,14 @@
MYSQL_OPT_CONNECT_ATTR_DELETE,
MYSQL_SERVER_PUBLIC_KEY,
MYSQL_ENABLE_CLEARTEXT_PLUGIN,
MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS
MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS,
MYSQL_OPT_CONNECT_TIMEOUT_MS,
MYSQL_OPT_READ_TIMEOUT_MS,
MYSQL_OPT_WRITE_TIMEOUT_MS
};
struct st_mysql_options_extention;
struct st_mysql_options {
unsigned int connect_timeout, read_timeout, write_timeout;
timeout_t connect_timeout, read_timeout, write_timeout;
unsigned int port, protocol;
unsigned long client_flag;
char *host,*user,*password,*unix_socket,*db;
@@ -301,6 +301,29 @@ enum enum_server_command

#define ONLY_KILL_QUERY 1

C_MODE_START

/*
In order to avoid confusion about whether a timeout value is in
seconds or milliseconds, a timeout_t struct is used. It simply tracks
milliseconds but this helps ensure type safety and clear intention
when converting for use in syscalls etc.
*/

typedef struct {
uint value_ms_;
} timeout_t;

timeout_t timeout_from_seconds(uint seconds);
timeout_t timeout_from_millis(uint ms);
timeout_t timeout_infinite();
my_bool timeout_is_infinite(const timeout_t t);
int timeout_is_nonzero(const timeout_t t);
uint timeout_to_millis(const timeout_t t);
// toSeconds rounds down.
uint timeout_to_seconds(const timeout_t t);

C_MODE_END

struct st_vio; /* Only C */
typedef struct st_vio Vio;
@@ -326,7 +349,8 @@ typedef struct st_net {
unsigned long remain_in_buf,length, buf_length, where_b;
unsigned long max_packet,max_packet_size;
unsigned int pkt_nr,compress_pkt_nr;
unsigned int write_timeout, read_timeout, retry_count;
timeout_t write_timeout, read_timeout;
uint retry_count;
int fcntl;
unsigned int *return_status;
unsigned char reading_or_writing;
@@ -492,8 +516,8 @@ my_bool net_write_packet(NET *net, const unsigned char *packet, size_t length);
unsigned long my_net_read(NET *net);

#ifdef MY_GLOBAL_INCLUDED
void my_net_set_write_timeout(NET *net, uint timeout);
void my_net_set_read_timeout(NET *net, uint timeout);
void my_net_set_write_timeout(NET *net, const timeout_t timeout);
void my_net_set_read_timeout(NET *net, const timeout_t timeout);
#endif

struct rand_struct {
@@ -22,6 +22,7 @@
#define vio_violite_h_

#include "my_net.h" /* needed because of struct in_addr */
#include "mysql_com.h"
#include <mysql/psi/mysql_socket.h>


@@ -97,16 +98,16 @@ my_socket vio_fd(Vio*vio);
/* Remote peer's address and name in text form */
my_bool vio_peer_addr(Vio *vio, char *buf, uint16 *port, size_t buflen);
/* Wait for an I/O event notification. */
int vio_io_wait(Vio *vio, enum enum_vio_io_event event, int timeout);
int vio_io_wait(Vio *vio, enum enum_vio_io_event event, timeout_t timeout);
my_bool vio_is_connected(Vio *vio);
#ifndef DBUG_OFF
ssize_t vio_pending(Vio *vio);
#endif
/* Set timeout for a network operation. */
int vio_timeout(Vio *vio, uint which, int timeout_sec);
int vio_timeout(Vio *vio, uint which, timeout_t timeout);
/* Connect to a peer. */
my_bool vio_socket_connect(Vio *vio, struct sockaddr *addr, socklen_t len,
int timeout);
timeout_t timeout);

my_bool vio_get_normalized_ip_string(const struct sockaddr *addr, int addr_length,
char *ip_string, size_t ip_string_size);
@@ -226,8 +227,8 @@ struct st_vio
char *read_pos; /* start of unfetched data in the
read buffer */
char *read_end; /* end of unfetched data */
int read_timeout; /* Timeout value (ms) for read ops. */
int write_timeout; /* Timeout value (ms) for write ops. */
timeout_t read_timeout; /* Timeout value for read ops. */
timeout_t write_timeout; /* Timeout value for write ops. */

/*
VIO vtable interface to be implemented by VIO's like SSL, Socket,
@@ -257,7 +258,7 @@ struct st_vio
int (*vioshutdown)(Vio*);
my_bool (*is_connected)(Vio*);
my_bool (*has_data) (Vio*);
int (*io_wait)(Vio*, enum enum_vio_io_event, int);
int (*io_wait)(Vio*, enum enum_vio_io_event, timeout_t);
my_bool (*connect)(Vio*, struct sockaddr *, socklen_t, int);
#ifdef _WIN32
OVERLAPPED overlapped;
@@ -87,6 +87,8 @@ const char *client_errors[]=
"Authentication plugin '%s' cannot be loaded: %s",
"There is an attribute with the same name already",
"Authentication plugin '%s' reported error: %s",
"Read timeout is reached",
"Write timeout is reached",
""
};

@@ -1132,8 +1132,8 @@ my_bool STDCALL mysql_embedded(void)
void my_net_local_init(NET *net)
{
net->max_packet= (uint) net_buffer_length;
my_net_set_read_timeout(net, CLIENT_NET_READ_TIMEOUT);
my_net_set_write_timeout(net, CLIENT_NET_WRITE_TIMEOUT);
my_net_set_read_timeout(net, timeout_from_seconds(CLIENT_NET_READ_TIMEOUT));
my_net_set_write_timeout(net, timeout_from_seconds(CLIENT_NET_WRITE_TIMEOUT));
net->retry_count= 1;
net->max_packet_size= MY_MAX(net_buffer_length, max_allowed_packet);
}
@@ -20,6 +20,6 @@ SET @max_sql_select_limit = 4294967295;

SET @default_wait_timeout= 28800;
SET @min_wait_timeout= 1;
SET @max_wait_timeout= 31536000;
SET @max_wait_timeout= 604800;

--enable_query_log
@@ -0,0 +1,20 @@
select "no timeout, should work";
no timeout, should work
no timeout, should work
select "short timeout, should work", sleep(0.90);
short timeout, should work sleep(0.90)
short timeout, should work 0
select "long timeout, should fail 1s accuracty", sleep(1.01);
ERROR HY000: Read timeout is reached
select "no timeout, should work";
no timeout, should work
no timeout, should work
select "short timeout, should work", sleep(0.5);
short timeout, should work sleep(0.5)
short timeout, should work 0
select "short timeout, over one second, should also work", sleep(1.49);
short timeout, over one second, should also work sleep(1.49)
short timeout, over one second, should also work 0
select "long timeout, should 1500ms accuracy", sleep(1.51);
ERROR HY000: Read timeout is reached
ERROR HY000: Can't connect to MySQL server on '192.0.2.1' (110)
@@ -1067,7 +1067,7 @@ lc-messages en_US
lc-messages-dir MYSQL_SHAREDIR/
lc-time-names en_US
local-infile TRUE
lock-wait-timeout 31536000
lock-wait-timeout 604800
log-bin (No default value)
log-bin-index (No default value)
log-bin-trust-function-creators FALSE
@@ -1214,7 +1214,7 @@ report-host (No default value)
report-password (No default value)
report-port 0
report-user (No default value)
rpl-stop-slave-timeout 31536000
rpl-stop-slave-timeout 604800
safe-user-create FALSE
secure-auth TRUE
secure-file-priv (No default value)
@@ -1065,7 +1065,7 @@ lc-messages en_US
lc-messages-dir MYSQL_SHAREDIR/
lc-time-names en_US
local-infile TRUE
lock-wait-timeout 31536000
lock-wait-timeout 604800
log-bin (No default value)
log-bin-index (No default value)
log-bin-trust-function-creators FALSE
@@ -1211,7 +1211,7 @@ report-host (No default value)
report-password (No default value)
report-port 0
report-user (No default value)
rpl-stop-slave-timeout 31536000
rpl-stop-slave-timeout 604800
safe-user-create FALSE
secure-auth TRUE
secure-file-priv (No default value)
@@ -64,7 +64,7 @@ SET @@global.binlog_cache_size = 4294967295;
SELECT @@global.binlog_cache_size;
SET @@global.binlog_cache_size = 10000;
SELECT @@global.binlog_cache_size;
SET @@global.binlog_cache_size = 21221204;
SET @@global.binlog_cache_size = 212204;
SELECT @@global.binlog_cache_size;
echo 'Bug: Invalid values are coming in variable on assigning valid values';

@@ -64,7 +64,7 @@ SET @@global.binlog_stmt_cache_size = 4294967295;
SELECT @@global.binlog_stmt_cache_size;
SET @@global.binlog_stmt_cache_size = 10000;
SELECT @@global.binlog_stmt_cache_size;
SET @@global.binlog_stmt_cache_size = 21221204;
SET @@global.binlog_stmt_cache_size = 212204;
SELECT @@global.binlog_stmt_cache_size;
echo 'Bug: Invalid values are coming in variable on assigning valid values';

@@ -32,12 +32,12 @@ Warning 1292 Truncated incorrect binlog_cache_size value: '10000'
SELECT @@global.binlog_cache_size;
@@global.binlog_cache_size
8192
SET @@global.binlog_cache_size = 21221204;
SET @@global.binlog_cache_size = 212204;
Warnings:
Warning 1292 Truncated incorrect binlog_cache_size value: '21221204'
Warning 1292 Truncated incorrect binlog_cache_size value: '212204'
SELECT @@global.binlog_cache_size;
@@global.binlog_cache_size
21217280
208896
'Bug: Invalid values are coming in variable on assigning valid values'
'#--------------------FN_DYNVARS_006_04-------------------------#'
SET @@global.binlog_cache_size = 1024;
@@ -32,12 +32,12 @@ Warning 1292 Truncated incorrect binlog_stmt_cache_size value: '10000'
SELECT @@global.binlog_stmt_cache_size;
@@global.binlog_stmt_cache_size
8192
SET @@global.binlog_stmt_cache_size = 21221204;
SET @@global.binlog_stmt_cache_size = 212204;
Warnings:
Warning 1292 Truncated incorrect binlog_stmt_cache_size value: '21221204'
Warning 1292 Truncated incorrect binlog_stmt_cache_size value: '212204'
SELECT @@global.binlog_stmt_cache_size;
@@global.binlog_stmt_cache_size
21217280
208896
'Bug: Invalid values are coming in variable on assigning valid values'
'#--------------------FN_DYNVARS_006_04-------------------------#'
SET @@global.binlog_stmt_cache_size = 1024;
@@ -22,10 +22,10 @@ SET @@global.connect_timeout = 10000;
SELECT @@global.connect_timeout;
@@global.connect_timeout
10000
SET @@global.connect_timeout = 21221204;
SET @@global.connect_timeout = 212204;
SELECT @@global.connect_timeout;
@@global.connect_timeout
21221204
212204
'#--------------------FN_DYNVARS_019_04-------------------------#'
SET @@global.connect_timeout = 1;
Warnings:
@@ -44,8 +44,8 @@ Warnings:
Warning 1292 Truncated incorrect connect_timeout value: '42949672950'
SELECT @@global.connect_timeout;
@@global.connect_timeout
31536000
SET @@global.connect_timeout = 21221204.10;
604800
SET @@global.connect_timeout = 212204.10;
ERROR 42000: Incorrect argument type to variable 'connect_timeout'
SET @@global.connect_timeout = ON;
ERROR 42000: Incorrect argument type to variable 'connect_timeout'
Oops, something went wrong.

0 comments on commit c1d98eb

Please sign in to comment.