Default: 5
+### so_reuseport
+
+Specifies whether to set the socket option `SO_REUSEPORT` on TCP
+listening sockets. On some operating systems, this allows running
+multiple PgBouncer instances on the same host listening on the same
+port and having the kernel distribute the connections automatically.
+This option is a way to get PgBouncer to use more CPU cores.
+(PgBouncer is single-threaded and uses one CPU core per instance.)
+
+The behavior in detail depends on the operating system kernel. As of
+this writing, this setting has the desired effect on (sufficiently
+recent versions of) Linux, DragonFlyBSD, and FreeBSD. (On FreeBSD, it
+applies the socket option `SO_REUSEPORT_LB` instead.) Some other
+operating systems support the socket option but it won't have the
+desired effect: It will allow multiple processes to bind to the same
+port but only one of them will get the connections. See your
+operating system's setsockopt() documentation for details.
+
+On systems that don't support the socket option at all, turning this
+setting on will result in an error.
+
+Each PgBouncer instance on the same host needs different settings for
+at least `unix_socket_dir` and `pidfile`, as well as `logfile` if that
+is used. Also note that if you make use of this option, you can no
+longer connect to a specific PgBouncer instance via TCP/IP, which
+might have implications for monitoring and metrics collection.
+
+Default: 0
+
### tcp_defer_accept
For details on this and other tcp options, please see `man 7 tcp`.
;; Maximum PostgreSQL protocol packet size.
;max_packet_size = 2147483647
+;; Set SO_REUSEPORT socket option
+;so_reuseport = 0
+
;; networking options, for info: man 7 tcp
;; Linux: Notify program about new connection only if there is also
extern unsigned int cf_max_packet_size;
extern int cf_sbuf_loopcnt;
+extern int cf_so_reuseport;
extern int cf_tcp_keepalive;
extern int cf_tcp_keepcnt;
extern int cf_tcp_keepidle;
/* sbuf config */
int cf_sbuf_len;
int cf_sbuf_loopcnt;
+int cf_so_reuseport;
int cf_tcp_socket_buffer;
#if defined(TCP_DEFER_ACCEPT) || defined(SO_ACCEPTFILTER)
int cf_tcp_defer_accept = 1;
CF_ABS("pidfile", CF_STR, cf_pidfile, CF_NO_RELOAD, ""),
CF_ABS("listen_addr", CF_STR, cf_listen_addr, CF_NO_RELOAD, ""),
CF_ABS("listen_port", CF_INT, cf_listen_port, CF_NO_RELOAD, "6432"),
+CF_ABS("so_reuseport", CF_INT, cf_so_reuseport, CF_NO_RELOAD, "0"),
CF_ABS("listen_backlog", CF_INT, cf_listen_backlog, CF_NO_RELOAD, "128"),
#ifndef WIN32
CF_ABS("unix_socket_dir", CF_STR, cf_unix_socket_dir, CF_NO_RELOAD, "/tmp"),
}
#endif
+ /*
+ * If configured, set SO_REUSEPORT or equivalent. If it's not
+ * enabled, just leave the socket alone. (We could also unset
+ * the socket option in that case, but this area is fairly
+ * unportable, so perhaps better to avoid it.)
+ */
+ if (af != AF_UNIX && cf_so_reuseport) {
+#if defined(SO_REUSEPORT)
+ int val = 1;
+ errpos = "setsockopt/SO_REUSEPORT";
+ res = setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
+ if (res < 0)
+ goto failed;
+#elif defined(SO_REUSEPORT_LB)
+ int val = 1;
+ errpos = "setsockopt/SO_REUSEPORT_LB";
+ res = setsockopt(sock, SOL_SOCKET, SO_REUSEPORT_LB, &val, sizeof(val));
+ if (res < 0)
+ goto failed;
+#else
+ fatal("so_reuseport not supported on this platform");
+#endif
+ }
+
/* bind it */
errpos = "bind";
res = bind(sock, sa, salen);