Keepalive parameters
authorMarko Kreen <markokr@gmail.com>
Wed, 28 Apr 2010 11:07:04 +0000 (14:07 +0300)
committerMarko Kreen <markokr@gmail.com>
Wed, 7 Sep 2011 15:37:17 +0000 (17:37 +0200)
- keepalive_idle
- keepalive_interval
- keepalive_count

sql/plproxy_init.sql
src/cluster.c
src/execute.c
src/plproxy.h

index 0d7312342b1fae82fc7498236e71b97898e9241b..c8d55aae1c52eec3600f20486e7970562236acde 100644 (file)
@@ -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;
 
index 234f4a1341de4e14601d05f910593ffdf4dc4dba..de803adb533417001f70acc3751ebbf65c17e55f 100644 (file)
@@ -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);
 }
index 4db9052eac46982049397bed5ff5629782d2f154..00cd6cade0c65a1c11a781e4fd2e7917f4942808 100644 (file)
 
 #include "poll_compat.h"
 
+#ifdef WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+#ifdef SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#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();
 }
+
+
index 60ba3b2ad3cb620925b5ac1fa3b2438b69a9b2c6..9aad95aee5fb0c95575b32939bc2be888c6ea6b7 100644 (file)
@@ -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 */