Re: Implement support for TCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVL - Mailing list pgsql-patches
From | Bruce Momjian |
---|---|
Subject | Re: Implement support for TCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVL |
Date | |
Msg-id | 200507291458.j6TEwVW00616@candle.pha.pa.us Whole thread Raw |
In response to | Re: Implement support for TCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVL (Oliver Jowett <oliver@opencloud.com>) |
Responses |
Re: Implement support for TCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVL
|
List | pgsql-patches |
Is this the functionality we agreed we wanted? --------------------------------------------------------------------------- Oliver Jowett wrote: > Bruce Momjian wrote: > > Is this patch being worked on? > > Here's an updated version. It compiles and appears to work as expected > under Linux (supports TCP_KEEPIDLE etc) and Solaris 9 (no support). > > Main changes: > > - removed the tcp_keepalives GUC, SO_KEEPALIVE is now always on (as in > current CVS) > - {get,set}sockopt calls are only done when absolutely necessary (no > extra syscalls during backend startup in a default configuration). > > I still haven't had a chance to glue in support for the TCP_KEEPALIVE > (Solaris-style) option, but that should be fairly painless to add later. > > -O > ? postgresql-8.1devel.tar.gz > Index: doc/src/sgml/runtime.sgml > =================================================================== > RCS file: /projects/cvsroot/pgsql/doc/src/sgml/runtime.sgml,v > retrieving revision 1.335 > diff -u -c -r1.335 runtime.sgml > *** doc/src/sgml/runtime.sgml 2 Jul 2005 19:16:36 -0000 1.335 > --- doc/src/sgml/runtime.sgml 4 Jul 2005 10:41:33 -0000 > *************** > *** 894,899 **** > --- 894,946 ---- > </listitem> > </varlistentry> > > + <varlistentry id="guc-tcp-keepalives-idle" xreflabel="tcp_keepalives_idle"> > + <term><varname>tcp_keepalives_idle</varname> (<type>integer</type>)</term> > + <indexterm> > + <primary><varname>tcp_keepalives_idle</> configuration parameter</primary> > + </indexterm> > + <listitem> > + <para> > + On systems that support the TCP_KEEPIDLE socket option, specifies the > + number of seconds between sending keepalives on an otherwise idle > + connection. A value of 0 uses the system default. If TCP_KEEPIDLE is > + not supported, this parameter must be 0. This option is ignored for > + connections made via a Unix-domain socket. > + </para> > + </listitem> > + </varlistentry> > + > + <varlistentry id="guc-tcp-keepalives-interval" xreflabel="tcp_keepalives_interval"> > + <term><varname>tcp_keepalives_interval</varname> (<type>integer</type>)</term> > + <indexterm> > + <primary><varname>tcp_keepalives_interval</> configuration parameter</primary> > + </indexterm> > + <listitem> > + <para> > + On systems that support the TCP_KEEPINTVL socket option, specifies how > + long, in seconds, to wait for a response to a keepalive before > + retransmitting. A value of 0 uses the system default. If TCP_KEEPINTVL > + is not supported, this parameter must be 0. This option is ignored > + for connections made via a Unix-domain socket. > + </para> > + </listitem> > + </varlistentry> > + > + <varlistentry id="guc-tcp-keepalives-count" xreflabel="tcp_keepalives_count"> > + <term><varname>tcp_keepalives_count</varname> (<type>integer</type>)</term> > + <indexterm> > + <primary><varname>tcp_keepalives_count</> configuration parameter</primary> > + </indexterm> > + <listitem> > + <para> > + On systems that support the TCP_KEEPCNT socket option, specifies how > + many keepalives may be lost before the connection is considered dead. > + A value of 0 uses the system default. If TCP_KEEPINTVL is not > + supported, this parameter must be 0. > + </para> > + </listitem> > + </varlistentry> > + > </variablelist> > </sect3> > <sect3 id="runtime-config-connection-security"> > Index: src/backend/libpq/pqcomm.c > =================================================================== > RCS file: /projects/cvsroot/pgsql/src/backend/libpq/pqcomm.c,v > retrieving revision 1.176 > diff -u -c -r1.176 pqcomm.c > *** src/backend/libpq/pqcomm.c 22 Feb 2005 04:35:57 -0000 1.176 > --- src/backend/libpq/pqcomm.c 4 Jul 2005 10:41:33 -0000 > *************** > *** 87,93 **** > #include "libpq/libpq.h" > #include "miscadmin.h" > #include "storage/ipc.h" > ! > > /* > * Configuration options > --- 87,93 ---- > #include "libpq/libpq.h" > #include "miscadmin.h" > #include "storage/ipc.h" > ! #include "utils/guc.h" > > /* > * Configuration options > *************** > *** 594,599 **** > --- 594,612 ---- > elog(LOG, "setsockopt(SO_KEEPALIVE) failed: %m"); > return STATUS_ERROR; > } > + > + /* Set default keepalive parameters. This should also catch > + * misconfigurations (non-zero values when socket options aren't > + * supported) > + */ > + if (pq_setkeepalivesidle(tcp_keepalives_idle, port) != STATUS_OK) > + return STATUS_ERROR; > + > + if (pq_setkeepalivesinterval(tcp_keepalives_interval, port) != STATUS_OK) > + return STATUS_ERROR; > + > + if (pq_setkeepalivescount(tcp_keepalives_count, port) != STATUS_OK) > + return STATUS_ERROR; > } > > return STATUS_OK; > *************** > *** 1158,1160 **** > --- 1171,1369 ---- > /* in non-error case, copy.c will have emitted the terminator line */ > DoingCopyOut = false; > } > + > + int > + pq_getkeepalivesidle(Port *port) > + { > + #ifdef TCP_KEEPIDLE > + if (IS_AF_UNIX(port->laddr.addr.ss_family)) > + return 0; > + > + if (port->keepalives_idle != 0) > + return port->keepalives_idle; > + > + if (port->default_keepalives_idle == 0) > + { > + socklen_t size = sizeof(port->default_keepalives_idle); > + if (getsockopt(port->sock, SOL_TCP, TCP_KEEPIDLE, > + (char *) &port->default_keepalives_idle, > + &size) < 0) > + { > + elog(LOG, "getsockopt(TCP_KEEPIDLE) failed: %m"); > + return -1; > + } > + } > + > + return port->default_keepalives_idle; > + #else > + return 0; > + #endif > + } > + > + int > + pq_setkeepalivesidle(int idle, Port *port) > + { > + if (IS_AF_UNIX(port->laddr.addr.ss_family)) > + return STATUS_OK; > + > + #ifdef TCP_KEEPIDLE > + if (idle == port->keepalives_idle) > + return STATUS_OK; > + > + if (port->default_keepalives_idle == 0) > + { > + if (pq_getkeepalivesidle(port) < 0) > + return STATUS_ERROR; > + } > + > + if (idle == 0) > + idle = port->default_keepalives_idle; > + > + if (setsockopt(port->sock, SOL_TCP, TCP_KEEPIDLE, > + (char *) &idle, sizeof(idle)) < 0) > + { > + elog(LOG, "setsockopt(TCP_KEEPIDLE) failed: %m"); > + return STATUS_ERROR; > + } > + > + port->keepalives_idle = idle; > + #else > + if (idle != 0) > + { > + elog(LOG, "setsockopt(TCP_KEEPIDLE) not supported"); > + return STATUS_ERROR; > + } > + #endif > + > + return STATUS_OK; > + } > + > + int > + pq_getkeepalivesinterval(Port *port) > + { > + #ifdef TCP_KEEPINTVL > + if (IS_AF_UNIX(port->laddr.addr.ss_family)) > + return 0; > + > + if (port->keepalives_interval != 0) > + return port->keepalives_interval; > + > + if (port->default_keepalives_interval == 0) > + { > + socklen_t size = sizeof(port->default_keepalives_interval); > + if (getsockopt(port->sock, SOL_TCP, TCP_KEEPINTVL, > + (char *) &port->default_keepalives_interval, > + &size) < 0) > + { > + elog(LOG, "getsockopt(TCP_KEEPINTVL) failed: %m"); > + return -1; > + } > + } > + > + return port->default_keepalives_interval; > + #else > + return 0; > + #endif > + } > + > + int > + pq_setkeepalivesinterval(int interval, Port *port) > + { > + if (IS_AF_UNIX(port->laddr.addr.ss_family)) > + return STATUS_OK; > + > + #ifdef TCP_KEEPINTVL > + if (interval == port->keepalives_interval) > + return STATUS_OK; > + > + if (port->default_keepalives_interval == 0) { > + if (pq_getkeepalivesinterval(port) < 0) > + return STATUS_ERROR; > + } > + > + if (interval == 0) > + interval = port->default_keepalives_interval; > + > + if (setsockopt(port->sock, SOL_TCP, TCP_KEEPINTVL, > + (char *) &interval, sizeof(interval)) < 0) > + { > + elog(LOG, "setsockopt(TCP_KEEPINTVL) failed: %m"); > + return STATUS_ERROR; > + } > + > + port->keepalives_interval = interval; > + #else > + if (interval != 0) > + { > + elog(LOG, "setsockopt(TCP_KEEPINTVL) not supported"); > + return STATUS_ERROR; > + } > + #endif > + > + return STATUS_OK; > + } > + > + int > + pq_getkeepalivescount(Port *port) > + { > + #ifdef TCP_KEEPCNT > + if (IS_AF_UNIX(port->laddr.addr.ss_family)) > + return 0; > + > + if (port->keepalives_count != 0) > + return port->keepalives_count; > + > + if (port->default_keepalives_count == 0) > + { > + socklen_t size = sizeof(port->default_keepalives_count); > + if (getsockopt(port->sock, SOL_TCP, TCP_KEEPCNT, > + (char *) &port->default_keepalives_count, > + &size) < 0) > + { > + elog(LOG, "getsockopt(TCP_KEEPCNT) failed: %m"); > + return -1; > + } > + } > + > + return port->default_keepalives_count; > + #else > + return 0; > + #endif > + } > + > + int > + pq_setkeepalivescount(int count, Port *port) > + { > + if (IS_AF_UNIX(port->laddr.addr.ss_family)) > + return STATUS_OK; > + > + #ifdef TCP_KEEPCNT > + if (count == port->keepalives_count) > + return STATUS_OK; > + > + if (port->default_keepalives_count == 0) { > + if (pq_getkeepalivescount(port) < 0) > + return STATUS_ERROR; > + } > + > + if (count == 0) > + count = port->default_keepalives_count; > + > + if (setsockopt(port->sock, SOL_TCP, TCP_KEEPCNT, > + (char *) &count, sizeof(count)) < 0) > + { > + elog(LOG, "setsockopt(TCP_KEEPCNT) failed: %m"); > + return STATUS_ERROR; > + } > + > + port->keepalives_count = count; > + #else > + if (count != 0) > + { > + elog(LOG, "setsockopt(TCP_KEEPCNT) not supported"); > + return STATUS_ERROR; > + } > + #endif > + > + return STATUS_OK; > + } > Index: src/backend/utils/misc/guc.c > =================================================================== > RCS file: /projects/cvsroot/pgsql/src/backend/utils/misc/guc.c,v > retrieving revision 1.271 > diff -u -c -r1.271 guc.c > *** src/backend/utils/misc/guc.c 28 Jun 2005 05:09:02 -0000 1.271 > --- src/backend/utils/misc/guc.c 4 Jul 2005 10:41:33 -0000 > *************** > *** 117,122 **** > --- 117,128 ---- > static bool assign_transaction_read_only(bool newval, bool doit, GucSource source); > static const char *assign_canonical_path(const char *newval, bool doit, GucSource source); > > + static bool assign_tcp_keepalives_idle(int newval, bool doit, GucSource source); > + static bool assign_tcp_keepalives_interval(int newval, bool doit, GucSource source); > + static bool assign_tcp_keepalives_count(int newval, bool doit, GucSource source); > + static const char *show_tcp_keepalives_idle(void); > + static const char *show_tcp_keepalives_interval(void); > + static const char *show_tcp_keepalives_count(void); > > /* > * GUC option variables that are exported from this module > *************** > *** 158,163 **** > --- 164,172 ---- > char *IdentFileName; > char *external_pid_file; > > + int tcp_keepalives_idle; > + int tcp_keepalives_interval; > + int tcp_keepalives_count; > > /* > * These variables are all dummies that don't do anything, except in some > *************** > *** 1375,1380 **** > --- 1384,1418 ---- > BLCKSZ, BLCKSZ, BLCKSZ, NULL, NULL > }, > > + { > + {"tcp_keepalives_idle", PGC_USERSET, CLIENT_CONN_OTHER, > + gettext_noop("Seconds between issuing TCP keepalives."), > + gettext_noop("A value of 0 uses the system default."), > + }, > + &tcp_keepalives_idle, > + 0, 0, INT_MAX, assign_tcp_keepalives_idle, show_tcp_keepalives_idle > + }, > + > + { > + {"tcp_keepalives_interval", PGC_USERSET, CLIENT_CONN_OTHER, > + gettext_noop("Seconds between TCP keepalive retransmits."), > + gettext_noop("A value of 0 uses the system default."), > + }, > + &tcp_keepalives_interval, > + 0, 0, INT_MAX, assign_tcp_keepalives_interval, show_tcp_keepalives_interval > + }, > + > + { > + {"tcp_keepalives_count", PGC_USERSET, CLIENT_CONN_OTHER, > + gettext_noop("Maximum number of TCP keepalive retransmits."), > + gettext_noop("This controls the number of consecutive keepalive retransmits that can be " > + "lost before a connection is considered dead. A value of 0 uses the " > + "system default."), > + }, > + &tcp_keepalives_count, > + 0, 0, INT_MAX, assign_tcp_keepalives_count, show_tcp_keepalives_count > + }, > + > /* End-of-list marker */ > { > {NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL > *************** > *** 5744,5748 **** > --- 5782,5842 ---- > return newval; > } > > + static bool > + assign_tcp_keepalives_idle(int newval, bool doit, GucSource source) > + { > + if (doit && MyProcPort != NULL) > + { > + return (pq_setkeepalivesidle(newval, MyProcPort) == STATUS_OK); > + } > + > + return true; > + } > + > + static const char * > + show_tcp_keepalives_idle(void) > + { > + static char nbuf[32]; > + snprintf(nbuf, sizeof(nbuf), "%d", MyProcPort == NULL ? 0 : pq_getkeepalivesidle(MyProcPort)); > + return nbuf; > + } > + > + static bool > + assign_tcp_keepalives_interval(int newval, bool doit, GucSource source) > + { > + if (doit && MyProcPort != NULL) > + { > + return (pq_setkeepalivesinterval(newval, MyProcPort) == STATUS_OK); > + } > + > + return true; > + } > + > + static const char * > + show_tcp_keepalives_interval(void) > + { > + static char nbuf[32]; > + snprintf(nbuf, sizeof(nbuf), "%d", MyProcPort == NULL ? 0 : pq_getkeepalivesinterval(MyProcPort)); > + return nbuf; > + } > + > + static bool > + assign_tcp_keepalives_count(int newval, bool doit, GucSource source) > + { > + if (doit && MyProcPort != NULL) > + { > + return (pq_setkeepalivescount(newval, MyProcPort) == STATUS_OK); > + } > + > + return true; > + } > + > + static const char * > + show_tcp_keepalives_count(void) > + { > + static char nbuf[32]; > + snprintf(nbuf, sizeof(nbuf), "%d", MyProcPort == NULL ? 0 : pq_getkeepalivescount(MyProcPort)); > + return nbuf; > + } > > #include "guc-file.c" > Index: src/backend/utils/misc/postgresql.conf.sample > =================================================================== > RCS file: /projects/cvsroot/pgsql/src/backend/utils/misc/postgresql.conf.sample,v > retrieving revision 1.151 > diff -u -c -r1.151 postgresql.conf.sample > *** src/backend/utils/misc/postgresql.conf.sample 2 Jul 2005 18:46:45 -0000 1.151 > --- src/backend/utils/misc/postgresql.conf.sample 4 Jul 2005 10:41:33 -0000 > *************** > *** 70,75 **** > --- 70,80 ---- > #krb_caseins_users = off > #krb_srvname = 'postgres' > > + # - TCP Keepalives - > + # see 'man 7 tcp' for details > + #tcp_keepalives_idle = 0 # TCP_KEEPIDLE, in seconds; 0 uses the system default. > + #tcp_keepalives_interval = 0 # TCP_KEEPINTVL, in seconds; 0 uses the system default. > + #tcp_keepalives_count = 0 # TCP_KEEPCNT, in seconds; 0 uses the system default. > > #--------------------------------------------------------------------------- > # RESOURCE USAGE (except WAL) > Index: src/bin/psql/tab-complete.c > =================================================================== > RCS file: /projects/cvsroot/pgsql/src/bin/psql/tab-complete.c,v > retrieving revision 1.133 > diff -u -c -r1.133 tab-complete.c > *** src/bin/psql/tab-complete.c 22 Jun 2005 21:14:30 -0000 1.133 > --- src/bin/psql/tab-complete.c 4 Jul 2005 10:41:33 -0000 > *************** > *** 600,605 **** > --- 600,608 ---- > "superuser_reserved_connections", > "syslog_facility", > "syslog_ident", > + "tcp_keepalives_idle", > + "tcp_keepalives_interval", > + "tcp_keepalives_count", > "temp_buffers", > "TimeZone", > "trace_notify", > Index: src/include/libpq/libpq-be.h > =================================================================== > RCS file: /projects/cvsroot/pgsql/src/include/libpq/libpq-be.h,v > retrieving revision 1.49 > diff -u -c -r1.49 libpq-be.h > *** src/include/libpq/libpq-be.h 31 Dec 2004 22:03:32 -0000 1.49 > --- src/include/libpq/libpq-be.h 4 Jul 2005 10:41:33 -0000 > *************** > *** 25,30 **** > --- 25,33 ---- > #include <openssl/ssl.h> > #include <openssl/err.h> > #endif > + #ifdef HAVE_NETINET_TCP_H > + #include <netinet/tcp.h> > + #endif > > #include "libpq/hba.h" > #include "libpq/pqcomm.h" > *************** > *** 92,100 **** > --- 95,131 ---- > char peer_cn[SM_USER + 1]; > unsigned long count; > #endif > + > + /* > + * TCP keepalive settings; > + * default values are 0 if AF_UNIX or not yet known; > + * current values are 0 if AF_UNIX or using the default. > + */ > + #ifdef TCP_KEEPIDLE > + int default_keepalives_idle; > + int keepalives_idle; > + #endif > + #ifdef TCP_KEEPINTVL > + int default_keepalives_interval; > + int keepalives_interval; > + #endif > + #ifdef TCP_KEEPCNT > + int default_keepalives_count; > + int keepalives_count; > + #endif > } Port; > > > extern ProtocolVersion FrontendProtocol; > > + /* TCP keepalives configuration. These are no-ops on an AF_UNIX socket. */ > + > + extern int pq_getkeepalivesidle(Port *port); > + extern int pq_getkeepalivesinterval(Port *port); > + extern int pq_getkeepalivescount(Port *port); > + > + extern int pq_setkeepalivesidle(int idle, Port *port); > + extern int pq_setkeepalivesinterval(int interval, Port *port); > + extern int pq_setkeepalivescount(int count, Port *port); > + > #endif /* LIBPQ_BE_H */ > Index: src/include/utils/guc.h > =================================================================== > RCS file: /projects/cvsroot/pgsql/src/include/utils/guc.h,v > retrieving revision 1.61 > diff -u -c -r1.61 guc.h > *** src/include/utils/guc.h 26 Jun 2005 03:04:12 -0000 1.61 > --- src/include/utils/guc.h 4 Jul 2005 10:41:33 -0000 > *************** > *** 134,139 **** > --- 134,142 ---- > extern char *IdentFileName; > extern char *external_pid_file; > > + extern int tcp_keepalives_idle; > + extern int tcp_keepalives_interval; > + extern int tcp_keepalives_count; > > extern void SetConfigOption(const char *name, const char *value, > GucContext context, GucSource source); > > ---------------------------(end of broadcast)--------------------------- > TIP 4: Don't 'kill -9' the postmaster -- Bruce Momjian | http://candle.pha.pa.us pgman@candle.pha.pa.us | (610) 359-1001 + If your life is a hard drive, | 13 Roberts Road + Christ can be your backup. | Newtown Square, Pennsylvania 19073
pgsql-patches by date: