Skip to content
This repository has been archived by the owner on Oct 11, 2018. It is now read-only.

Commit

Permalink
Support millisecond timeouts for reads, writes, and connects
Browse files Browse the repository at this point in the history
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 25, 2014
1 parent fb29837 commit c1d98eb
Show file tree
Hide file tree
Showing 53 changed files with 397 additions and 220 deletions.
17 changes: 16 additions & 1 deletion client/mysqltest.cc
Expand Up @@ -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;
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 3 additions & 1 deletion include/errmsg.h
Expand Up @@ -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 */
11 changes: 7 additions & 4 deletions include/mysql.h
Expand Up @@ -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)
Expand Down Expand Up @@ -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
};

/**
Expand All @@ -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;
Expand Down
22 changes: 19 additions & 3 deletions include/mysql.h.pp
Expand Up @@ -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 {
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
30 changes: 27 additions & 3 deletions include/mysql_com.h
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down
13 changes: 7 additions & 6 deletions include/violite.h
Expand Up @@ -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>


Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions libmysql/errmsg.c
Expand Up @@ -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",
""
};

Expand Down
4 changes: 2 additions & 2 deletions libmysql/libmysql.c
Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/include/linux_sys_vars.inc
Expand Up @@ -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
20 changes: 20 additions & 0 deletions mysql-test/r/connection_timeout.result
@@ -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)
4 changes: 2 additions & 2 deletions mysql-test/r/mysqld--help-notwin-profiling.result
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions mysql-test/r/mysqld--help-notwin.result
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/suite/sys_vars/inc/binlog_cache_size_basic.inc
Expand Up @@ -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';

Expand Down
Expand Up @@ -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';

Expand Down
6 changes: 3 additions & 3 deletions mysql-test/suite/sys_vars/r/binlog_cache_size_basic_64.result
Expand Up @@ -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;
Expand Down
Expand Up @@ -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;
Expand Down
8 changes: 4 additions & 4 deletions mysql-test/suite/sys_vars/r/connect_timeout_basic.result
Expand Up @@ -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:
Expand All @@ -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'
Expand Down

0 comments on commit c1d98eb

Please sign in to comment.