From 8e9c3b46602c3854d13fed766a4c658b9e623097 Mon Sep 17 00:00:00 2001 From: Marko Kreen Date: Wed, 28 Apr 2010 14:07:04 +0300 Subject: [PATCH] Keepalive parameters - keepalive_idle - keepalive_interval - keepalive_count --- sql/plproxy_init.sql | 3 ++ src/cluster.c | 9 ++++ src/execute.c | 113 +++++++++++++++++++++++++++++++++++++++++++ src/plproxy.h | 4 ++ 4 files changed, 129 insertions(+) diff --git a/sql/plproxy_init.sql b/sql/plproxy_init.sql index 0d73123..c8d55aa 100644 --- a/sql/plproxy_init.sql +++ b/sql/plproxy_init.sql @@ -41,6 +41,9 @@ create or replace function plproxy.get_cluster_config(cluster_name text, out key text, out val text) returns setof record as $$ begin + key = 'keepalive_idle'; val = '240'; return next; + key = 'keepalive_interval'; val = '15'; return next; + key = 'keepalive_count'; val = '4'; return next; return; end; $$ language plpgsql; diff --git a/src/cluster.c b/src/cluster.c index 234f4a1..de803ad 100644 --- a/src/cluster.c +++ b/src/cluster.c @@ -69,6 +69,9 @@ static const char *cluster_config_options[] = { "connection_lifetime", "query_timeout", "disable_binary", + "keepalive_idle", + "keepalive_interval", + "keepalive_count", NULL }; @@ -257,6 +260,12 @@ set_config_key(ProxyFunction *func, ProxyConfig *cf, const char *key, const char cf->query_timeout = atoi(val); else if (pg_strcasecmp("disable_binary", key) == 0) cf->disable_binary = atoi(val); + else if (pg_strcasecmp("keepalive_idle", key) == 0) + cf->keepidle = atoi(val); + else if (pg_strcasecmp("keepalive_interval", key) == 0) + cf->keepintvl = atoi(val); + else if (pg_strcasecmp("keepalive_count", key) == 0) + cf->keepcnt = atoi(val); else plproxy_error(func, "Unknown config param: %s", key); } diff --git a/src/execute.c b/src/execute.c index 4db9052..00cd6ca 100644 --- a/src/execute.c +++ b/src/execute.c @@ -31,6 +31,24 @@ #include "poll_compat.h" +#ifdef WIN32 +#include +#include +#endif +#ifdef SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#ifdef HAVE_NETINET_TCP_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif + + #if PG_VERSION_NUM < 80400 static int geterrcode(void) { @@ -258,6 +276,97 @@ intr_loop: return true; } +static bool +socket_set_keepalive(int fd, int onoff, int keepidle, int keepintvl, int keepcnt) +{ + int val, res; + + if (!onoff) { + /* turn keepalive off */ + val = 0; + res = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)); + return (res == 0); + } + + /* turn keepalive on */ + val = 1; + res = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)); + if (res < 0) + return false; + + /* Darwin */ +#ifdef TCP_KEEPALIVE + if (keepidle) { + val = keepidle; + res = setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &val, sizeof(val)); + if (res < 0 && errno != ENOPROTOOPT) + return false; + } +#endif + + /* Linux, NetBSD */ +#ifdef TCP_KEEPIDLE + if (keepidle) { + val = keepidle; + res = setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)); + if (res < 0 && errno != ENOPROTOOPT) + return false; + } +#endif +#ifdef TCP_KEEPINTVL + if (keepintvl) { + val = keepintvl; + res = setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)); + if (res < 0 && errno != ENOPROTOOPT) + return false; + } +#endif +#ifdef TCP_KEEPCNT + if (keepcnt > 0) { + val = keepcnt; + res = setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)); + if (res < 0 && errno != ENOPROTOOPT) + return false; + } +#endif + + /* Windows */ +#ifdef SIO_KEEPALIVE_VALS + if (keepidle || keepintvl) { + struct tcp_keepalive vals; + DWORD outlen = 0; + if (!keepidle) keepidle = 5 * 60; + if (!keepintvl) keepintvl = 15; + vals.onoff = 1; + vals.keepalivetime = keepidle * 1000; + vals.keepaliveinterval = keepintvl * 1000; + res = WSAIoctl(fd, SIO_KEEPALIVE_VALS, &vals, sizeof(vals), NULL, 0, &outlen, NULL, NULL, NULL, NULL); + if (res != 0) + return false; + } +#endif + return true; +} + +static void setup_keepalive(ProxyConnection *conn) +{ + struct sockaddr sa; + socklen_t salen = sizeof(sa); + int fd = PQsocket(conn->db); + ProxyConfig *config = &conn->cluster->config; + + /* turn on keepalive */ + if (!config->keepidle && !config->keepintvl && !config->keepcnt) + return; +#ifdef AF_UNIX + if (getsockname(fd, &sa, &salen) != 0) + return; + if (sa.sa_family == AF_UNIX) + return; +#endif + socket_set_keepalive(fd, 1, config->keepidle, config->keepintvl, config->keepcnt); +} + static void handle_notice(void *arg, const PGresult *res) { @@ -312,6 +421,8 @@ prepare_conn(ProxyFunction *func, ProxyConnection *conn) /* override default notice handler */ PQsetNoticeReceiver(conn->db, handle_notice, conn); + + setup_keepalive(conn); } /* @@ -1047,3 +1158,5 @@ plproxy_exec(ProxyFunction *func, FunctionCallInfo fcinfo) } PG_END_TRY(); } + + diff --git a/src/plproxy.h b/src/plproxy.h index 60ba3b2..9aad95a 100644 --- a/src/plproxy.h +++ b/src/plproxy.h @@ -120,6 +120,10 @@ typedef struct ProxyConfig int query_timeout; /* How long query may take (secs) */ int connection_lifetime; /* How long the connection may live (secs) */ int disable_binary; /* Avoid binary I/O */ + /* keepalive parameters */ + int keepidle; + int keepintvl; + int keepcnt; } ProxyConfig; /* Single database connection */ -- 2.39.5