Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MDEV-14412 Add functionality to set keepalive tcp options #400

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
18 changes: 17 additions & 1 deletion include/violite.h
Expand Up @@ -51,11 +51,26 @@ enum enum_vio_io_event
VIO_IO_EVENT_CONNECT
};

struct vio_keepalive_opts
{
int interval;
int idle;
int probes;
};


#define VIO_LOCALHOST 1U /* a localhost connection */
#define VIO_BUFFERED_READ 2U /* use buffered read */
#define VIO_READ_BUFFER_SIZE 16384U /* size of read buffer */
#define VIO_DESCRIPTION_SIZE 30 /* size of description */

#define VIO_DEFAULT_KEEPALIVE_TIME 7200
#define VIO_DEFAULT_KEEPALIVE_PROBES 9
#ifdef WIN32
#define VIO_DEFAULT_KEEPALIVE_INTVL 1
#else
#define VIO_DEFAULT_KEEPALIVE_INTVL 75
#endif
Vio* vio_new(my_socket sd, enum enum_vio_type type, uint flags);
Vio* mysql_socket_vio_new(MYSQL_SOCKET mysql_socket, enum enum_vio_type type, uint flags);
#ifdef __WIN__
Expand Down Expand Up @@ -84,6 +99,8 @@ my_bool vio_is_blocking(Vio *vio);
int vio_fastsend(Vio *vio);
/* setsockopt SO_KEEPALIVE at SOL_SOCKET level, when possible */
int vio_keepalive(Vio *vio, my_bool onoff);
void vio_set_keepalive_options(Vio * vio, const struct vio_keepalive_opts *opts);
struct vio_keepalive_opts vio_get_keepalive_options(Vio * vio);
/* Whenever we should retry the last read/write operation. */
my_bool vio_should_retry(Vio *vio);
/* Check that operation was timed out */
Expand Down Expand Up @@ -212,7 +229,6 @@ enum SSL_type
SSL_TYPE_SPECIFIED
};


/* HFTODO - hide this if we don't want client in embedded server */
/* This structure is for every connection on both sides */
struct st_vio
Expand Down
1 change: 1 addition & 0 deletions sql/sql_class.h
Expand Up @@ -701,6 +701,7 @@ typedef struct system_variables
my_bool session_track_state_change;

ulong threadpool_priority;
ulong keepalive_time, keepalive_intvl, keepalive_probes;
} SV;

/**
Expand Down
8 changes: 7 additions & 1 deletion sql/sql_connect.cc
Expand Up @@ -853,6 +853,7 @@ static int check_connection(THD *thd)
uint connect_errors= 0;
int auth_rc;
NET *net= &thd->net;
vio_keepalive_opts opts;

DBUG_PRINT("info",
("New connection received on %s", vio_description(net->vio)));
Expand Down Expand Up @@ -1000,7 +1001,12 @@ static int check_connection(THD *thd)
bzero((char*) &net->vio->remote, sizeof(net->vio->remote));
}
vio_keepalive(net->vio, TRUE);


opts.interval = global_system_variables.keepalive_intvl;
opts.idle = global_system_variables.keepalive_time;
opts.probes = global_system_variables.keepalive_probes;
vio_set_keepalive_options(net->vio, &opts);

if (thd->packet.alloc(thd->variables.net_buffer_length))
{
/*
Expand Down
27 changes: 27 additions & 0 deletions sql/sys_vars.cc
Expand Up @@ -5073,6 +5073,33 @@ static Sys_var_ulong Sys_host_cache_size(
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(NULL),
ON_UPDATE(fix_host_cache_size));

static Sys_var_ulong Sys_keepalive_time_seconds(
"keepalive_time",
"The interval between the last data packet sent and the first keepalive probe.",
AUTO_SET GLOBAL_VAR(Sys_keepalive_time_seconds),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 65536),
DEFAULT(VIO_DEFAULT_KEEPALIVE_TIME),
BLOCK_SIZE(1),
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(NULL));

static Sys_var_ulong Sys_keepalive_intvl_seconds(
"keepalive_intvl",
"The interval between subsequential keepalive probes, regardless of what the connection has exchanged in the meantime.",
AUTO_SET GLOBAL_VAR(Sys_keepalive_intvl_seconds),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 65536),
DEFAULT(VIO_DEFAULT_KEEPALIVE_INTVL),
BLOCK_SIZE(1),
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(NULL));

static Sys_var_ulong Sys_keepalive_probes(
"keepalive_probes",
"The number of unacknowledged probes to send before considering the connection dead and notifying the application layer.",
AUTO_SET GLOBAL_VAR(Sys_keepalive_probes),
CMD_LINE(REQUIRED_ARG), VALID_RANGE(0, 65536),
DEFAULT(VIO_DEFAULT_KEEPALIVE_PROBES),
BLOCK_SIZE(1),
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(NULL));

static Sys_var_charptr Sys_ignore_db_dirs(
"ignore_db_dirs",
"Specifies a directory to add to the ignore list when collecting "
Expand Down
83 changes: 83 additions & 0 deletions vio/viosocket.c
Expand Up @@ -37,6 +37,14 @@
# include <sys/filio.h>
#endif

#ifndef SOL_TCP
# ifdef IPPROTO_TCP
# define SOL_TCP IPPROTO_TCP
# else
# define SOL_TCP 6
# endif /* IPPROTO_TCP */
#endif /* SOL_TCP */

/* Network io wait callbacks for threadpool */
static void (*before_io_wait)(void)= 0;
static void (*after_io_wait)(void)= 0;
Expand Down Expand Up @@ -522,6 +530,81 @@ int vio_keepalive(Vio* vio, my_bool set_keep_alive)
DBUG_RETURN(r);
}

/*
Set socket options for keepalive e.g., TCP_KEEPCNT, TCP_KEEPIDLE/TCP_KEEPALIVE, TCP_KEEPINTVL
*/
void vio_set_keepalive_options(Vio* vio, const struct vio_keepalive_opts *opts)
{
struct vio_keepalive_opts current_opts = vio_get_keepalive_options(vio);
#if defined(WIN32) && defined(SIO_KEEPALIVE_VALS)
struct keepalive lpvInBuffer;
DWORD cbInBuffer;

lpvInBuffer.onoff = 1;
lpvInBuffer.keepalivetime = opts->idle * 1000;
lpvInBuffer.keepaliveinterval = opts->interval * 1000;

WSAIoctl(port->sock, SIO_KEEPALIVE_VALS, (LPVOID) &lpvInBuffer, sizeof(lpvInBuffer),
NULL, 0, &cbInBuffer, NULL, NULL)
#else
if (vio->type != VIO_TYPE_NAMEDPIPE && vio->type != VIO_TYPE_SHARED_MEMORY) {
if (current_opts.idle != opts->idle)
#ifdef TCP_KEEPIDLE // Linux only
mysql_socket_setsockopt(vio->mysql_socket, SOL_TCP, TCP_KEEPIDLE, (char *)&opts->idle, sizeof(&opts->idle));
#else // BSD
mysql_socket_setsockopt(vio->mysql_socket, SOL_TCP, TCP_KEEPALIVE, (char *)&opts->idle, sizeof(&opts->idle));
#endif

#ifdef TCP_KEEPCNT // Linux only
if (current_opts.probes != opts->probes)
mysql_socket_setsockopt(vio->mysql_socket, SOL_TCP, TCP_KEEPCNT, (char *)&opts->probes, sizeof(&opts->probes));
#endif

#ifdef TCP_KEEPINTVL // Linux only
if (current_opts.interval != opts->interval)
mysql_socket_setsockopt(vio->mysql_socket, SOL_TCP, TCP_KEEPINTVL, (char *)&opts->interval, sizeof(&opts->interval));
#endif
}
#endif
}

struct vio_keepalive_opts
vio_get_keepalive_options(Vio* vio)
{
struct vio_keepalive_opts opts;
#if defined(WIN32) && defined(SIO_KEEPALIVE_VALS)
// It is impossible to get default values on windows
opts.idle = -1;
opts.interval = -1;
opts.probes = -1;
#else
int optval;
IF_WIN(int, socklen_t) optlen= sizeof(optval);
#ifdef TCP_KEEPIDLE // Linux only
if (mysql_socket_getsockopt(vio->mysql_socket, SOL_TCP, TCP_KEEPIDLE, &optval, &optlen) < 0)
#else
if (mysql_socket_getsockopt(vio->mysql_socket, SOL_TCP, TCP_KEEPALIVE, &optval, &optlen) < 0)
#endif
opts.idle = -1;
else
opts.idle = optval;

#ifdef TCP_KEEPCNT // Linux only
if (mysql_socket_getsockopt(vio->mysql_socket, SOL_TCP, TCP_KEEPCNT, &optval, &optlen) < 0)
opts.probes = -1;
else
opts.probes = optval;
#endif

#ifdef TCP_KEEPINTVL // Linux only
if (mysql_socket_getsockopt(vio->mysql_socket, SOL_TCP, TCP_KEEPINTVL, &optval, &optlen) < 0)
opts.interval = -1;
else
opts.interval = optval;
#endif
#endif // WIN32
return opts;
}

/**
Indicate whether a I/O operation must be retried later.
Expand Down