diff --git a/src/coio.cc b/src/coio.cc index e3d92a0d7f7856c64c28a1f692eed6e99e7e712e..b8b5e5edd2f9e6d68109efc266e372eca31a02b7 100644 --- a/src/coio.cc +++ b/src/coio.cc @@ -220,7 +220,8 @@ coio_accept(struct ev_io *coio, struct sockaddr *addr, * available */ int fd = sio_accept(coio->fd, addr, &addrlen); if (fd >= 0) { - evio_setsockopt_tcp(fd, addr->sa_family); + evio_setsockopt_client(fd, addr->sa_family, + SOCK_STREAM); return fd; } /* The socket is not ready, yield */ diff --git a/src/evio.cc b/src/evio.cc index 75b721161c3f8d30fa18ec00cd17ec46856bde07..7ce4e681b19e447824aa7d212c62f9910b8f3e69 100644 --- a/src/evio.cc +++ b/src/evio.cc @@ -38,6 +38,9 @@ #define BIND_RETRY_DELAY 0.1 +static void +evio_setsockopt_server(int fd, int family, int type); + /** Note: this function does not throw. */ void evio_close(ev_loop *loop, struct ev_io *evio) @@ -60,38 +63,66 @@ evio_socket(struct ev_io *coio, int domain, int type, int protocol) assert(coio->fd == -1); /* Don't leak fd if setsockopt fails. */ coio->fd = sio_socket(domain, type, protocol); - if (type == SOCK_STREAM) { - evio_setsockopt_tcp(coio->fd, domain); - } else { - sio_setfl(coio->fd, O_NONBLOCK, 1); - } + evio_setsockopt_client(coio->fd, domain, type); } - -/** Set common tcp socket client options. */ -void -evio_setsockopt_tcp(int fd, int family) +static void +evio_setsockopt_keepalive(int fd) { int on = 1; - /* In case this throws, the socket is not leaked. */ - sio_setfl(fd, O_NONBLOCK, on); - /* SO_KEEPALIVE to ensure connections don't hang + /* + * SO_KEEPALIVE to ensure connections don't hang * around for too long when a link goes away. */ sio_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)); +#ifdef __linux__ /* - * Lower latency is more important than higher - * bandwidth, and we usually write entire - * request/response in a single syscall. + * On Linux, we are able to fine-tune keepalive + * intervals. Set smaller defaults, since the system-wide + * defaults are in days. */ - if (family != AF_UNIX) - sio_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); + int keepcnt = 5; + sio_setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &keepcnt, + sizeof(int)); + int keepidle = 30; + + sio_setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &keepidle, + sizeof(int)); + + int keepintvl = 60; + sio_setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &keepintvl, + sizeof(int)); +#endif } -/** Set tcp options for server sockets. */ +/** Set common client socket options. */ void -evio_setsockopt_tcpserver(int fd) +evio_setsockopt_client(int fd, int family, int type) +{ + int on = 1; + /* In case this throws, the socket is not leaked. */ + sio_setfl(fd, O_NONBLOCK, on); + if (type == SOCK_STREAM && family != AF_UNIX) { + if (family != AF_UNIX) { + /* + * SO_KEEPALIVE to ensure connections don't hang + * around for too long when a link goes away. + */ + evio_setsockopt_keepalive(fd); + /* + * Lower latency is more important than higher + * bandwidth, and we usually write entire + * request/response in a single syscall. + */ + sio_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); + } + } +} + +/** Set options for server sockets. */ +static void +evio_setsockopt_server(int fd, int family, int type) { int on = 1; /* In case this throws, the socket is not leaked. */ @@ -99,8 +130,6 @@ evio_setsockopt_tcpserver(int fd) /* Allow reuse local adresses. */ sio_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - sio_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, - &on, sizeof(on)); /* Send all buffered messages on socket before take * control out from close(2) or shutdown(2). */ @@ -108,6 +137,8 @@ evio_setsockopt_tcpserver(int fd) sio_setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)); + if (type == SOCK_STREAM && family != AF_UNIX) + evio_setsockopt_keepalive(fd); } static inline const char * @@ -136,8 +167,8 @@ evio_service_accept_cb(ev_loop * /* loop */, ev_io *watcher, if (fd < 0) /* EAGAIN, EWOULDLOCK, EINTR */ return; - /* set common tcp options */ - evio_setsockopt_tcp(fd, service->addr.sa_family); + /* set common client socket options */ + evio_setsockopt_client(fd, service->addr.sa_family, SOCK_STREAM); /* * Invoke the callback and pass it the accepted * socket. @@ -167,7 +198,7 @@ evio_service_bind_addr(struct evio_service *service) SOCK_STREAM, IPPROTO_TCP); try { - evio_setsockopt_tcpserver(fd); + evio_setsockopt_server(fd, service->addr.sa_family, SOCK_STREAM); if (sio_bind(fd, &service->addr, service->addr_len) || sio_listen(fd)) { diff --git a/src/evio.h b/src/evio.h index e05c017556f487fc0a6e979311fda288f495c2a0..906b968ca8c4ca56f1ec7c21d893649d5504e63c 100644 --- a/src/evio.h +++ b/src/evio.h @@ -152,9 +152,6 @@ evio_timeout_update(ev_loop *loop, ev_tstamp start, ev_tstamp *delay) } void -evio_setsockopt_tcp(int fd, int family); - -void -evio_setsockopt_tcpserver(int fd); +evio_setsockopt_client(int fd, int family, int type); #endif /* TARANTOOL_EVIO_H_INCLUDED */ diff --git a/src/sio.cc b/src/sio.cc index 3bafff5629503ea7d62c0d686af27bb1b08e5b7f..dc04c4eaea1b3ca8417caedc96b8363742f34ef1 100644 --- a/src/sio.cc +++ b/src/sio.cc @@ -33,6 +33,7 @@ #include <errno.h> #include <stdio.h> #include <limits.h> +#include <netinet/in.h> /* TCP_NODELAY */ #include <netinet/tcp.h> /* TCP_NODELAY */ #include <arpa/inet.h> /* inet_ntoa */ #include <poll.h> @@ -102,6 +103,10 @@ sio_option_name(int option) CASE_OPTION(SO_ERROR); CASE_OPTION(SO_REUSEADDR); CASE_OPTION(TCP_NODELAY); +#ifdef __linux__ + CASE_OPTION(TCP_KEEPCNT); + CASE_OPTION(TCP_KEEPINTVL); +#endif default: return "undefined"; } diff --git a/src/tarantool.cc b/src/tarantool.cc index 35ea9350497a6cc4c752e664cbeb2ac5cc0d6d20..92174466a75f27124e4032c083d5759df402e310 100644 --- a/src/tarantool.cc +++ b/src/tarantool.cc @@ -92,7 +92,7 @@ title(const char *role, const char *fmt, ...) (void) role; va_list ap; - char buf[128], *bufptr = buf, *bufend = buf + sizeof(buf); + char buf[256], *bufptr = buf, *bufend = buf + sizeof(buf); char *statusptr = status, *statusend = status + sizeof(status); statusptr += snprintf(statusptr, statusend - statusptr, "%s", role); bufptr += snprintf(bufptr, bufend - bufptr, "%s%s", role,