tcp_defer_accept improvements.
authorMarko Kreen <markokr@gmail.com>
Tue, 22 Jan 2008 15:27:17 +0000 (15:27 +0000)
committerMarko Kreen <markokr@gmail.com>
Tue, 22 Jan 2008 15:27:17 +0000 (15:27 +0000)
- support freebsd accept filter
- remove user control of actual value, as its basically undocumented
- allow online setting change

include/pooler.h
src/main.c
src/pooler.c

index 5775d224334f9b0560e85f3edebdcffe8852f0ee..3a98ca932137d3375c55a683dfd7bff90f5b98bc 100644 (file)
@@ -22,4 +22,4 @@ void resume_pooler(void);
 void suspend_pooler(void);
 void get_pooler_fds(int *p_net, int *p_unix);
 void per_loop_pooler_maint(void);
-
+void pooler_tune_accept(bool on);
index 7235872c61e56e8994184fe60b49009c5782f3d9..2963f460717a13bc06dfdd006d3496040b2b8871 100644 (file)
@@ -31,6 +31,7 @@ static bool set_mode(ConfElem *elem, const char *val, PgSocket *console);
 static const char *get_mode(ConfElem *elem);
 static bool set_auth(ConfElem *elem, const char *val, PgSocket *console);
 static const char *get_auth(ConfElem *elem);
+static bool set_defer_accept(ConfElem *elem, const char *val, PgSocket *console);
 
 static const char *usage_str =
 "usage: pgbouncer [-d] [-R] [-q] [-v] [-h|-V] config.ini\n";
@@ -64,8 +65,8 @@ int cf_pool_mode = POOL_SESSION;
 /* sbuf config */
 int cf_sbuf_len = 2048;
 int cf_tcp_socket_buffer = 0;
-#ifdef TCP_DEFER_ACCEPT
-int cf_tcp_defer_accept = 45;
+#if defined(TCP_DEFER_ACCEPT) || defined(SO_ACCEPTFILTER)
+int cf_tcp_defer_accept = 1;
 #else
 int cf_tcp_defer_accept = 0;
 #endif
@@ -141,7 +142,7 @@ ConfElem bouncer_params[] = {
 {"suspend_timeout",    true, CF_TIME, &cf_suspend_timeout},
 
 {"pkt_buf",            false, CF_INT, &cf_sbuf_len},
-{"tcp_defer_accept",   false, CF_INT, &cf_tcp_defer_accept},
+{"tcp_defer_accept",   true, {cf_get_int, set_defer_accept}},
 {"tcp_socket_buffer",  true, CF_INT, &cf_tcp_socket_buffer},
 {"tcp_keepalive",      true, CF_INT, &cf_tcp_keepalive},
 {"tcp_keepcnt",                true, CF_INT, &cf_tcp_keepcnt},
@@ -223,6 +224,16 @@ static bool set_auth(ConfElem *elem, const char *val, PgSocket *console)
        return true;
 }
 
+static bool set_defer_accept(ConfElem *elem, const char *val, PgSocket *console)
+{
+       bool ok;
+       int oldval = cf_tcp_defer_accept;
+       ok = cf_set_int(elem, val, console);
+       if (ok && !!oldval != !!cf_tcp_defer_accept)
+               pooler_tune_accept(cf_tcp_defer_accept);
+       return true;
+}
+
 static void set_dbs_dead(bool flag)
 {
        List *item;
index c37033d76aad5f7c7a596bd50106a37ba067f2f7..60f3d39cb12f52a38f543d8071ced7da532f5c98 100644 (file)
@@ -111,6 +111,47 @@ static int create_unix_socket(const char *socket_dir, int listen_port)
        return sock;
 }
 
+/*
+ * Notify pooler only when also data is arrived.
+ *
+ * optval specifies how long after connection attempt to wait for data.
+ *
+ * Related to tcp_synack_retries sysctl, default 5 (corresponds 180 secs).
+ *
+ * SO_ACCEPTFILTER needs to be set after listern(), maybe TCP_DEFER_ACCEPT too.
+ */
+static void tune_accept(int sock, bool on)
+{
+       const char *act = on ? "install" : "uninstall";
+       int res = 0;
+#ifdef TCP_DEFER_ACCEPT
+       int val = 45; /* fixme: proper value */
+       res = getsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &val, sizeof(val));
+       log_noise("old TCP_DEFER_ACCEPT on %d = %d", sock, val);
+       val = on ? 1 : 0;
+       log_noise("%s TCP_DEFER_ACCEPT on %d", act, sock);
+       res = setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &val, sizeof(val));
+#else
+#ifdef SO_ACCEPTFILTER
+       struct accept_filter_arg af, *afp = on ? &af : NULL;
+       socklen_t af_len = on ? sizeof(af) : 0;
+       memset(&af, 0, sizeof(af));
+       strcpy(af.af_name, "dataready");
+       log_noise("%s SO_ACCEPTFILTER on %d", act, sock);
+       res = setsockopt(sock, SOL_SOCKET, SO_ACCEPTFILTER, afp, af_len);
+#endif
+#endif
+       if (res < 0)
+               log_warning("tune_accept: %s TCP_DEFER_ACCEPT/SO_ACCEPTFILTER: %s",
+                           act, strerror(errno));
+}
+
+void pooler_tune_accept(bool on)
+{
+       if (fd_net > 0)
+               tune_accept(fd_net, on);
+}
+
 static int create_net_socket(const char *listen_addr, int listen_port)
 {
        int sock;
@@ -149,27 +190,13 @@ static int create_net_socket(const char *listen_addr, int listen_port)
        /* set common options */
        tune_socket(sock, false);
 
-#ifdef TCP_DEFER_ACCEPT
-       /*
-        * Notify pooler only when also data is arrived.
-        *
-        * optval specifies how long after connection attempt to wait for data.
-        *
-        * Related to tcp_synack_retries sysctl, default 5 (corresponds 180 secs).
-        */
-       if (cf_tcp_defer_accept > 0) {
-               val = cf_tcp_defer_accept;
-               res = setsockopt(sock, IPPROTO_TCP, TCP_DEFER_ACCEPT, &val, sizeof(val));
-               if (res < 0)
-                       fatal_perror("setsockopt TCP_DEFER_ACCEPT");
-       }
-#endif
-
-       /* finally, accept connections */
+       /* make it accept connections */
        res = listen(sock, 100);
        if (res < 0)
                fatal_perror("listen");
 
+       tune_accept(sock, cf_tcp_defer_accept);
+
        log_info("listening on %s:%d", cf_listen_addr, cf_listen_port);
 
        return sock;