Thread: Implement support for TCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVL (was Re: [HACKERS] Feature freeze date for 8.1)
Implement support for TCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVL (was Re: [HACKERS] Feature freeze date for 8.1)
From
Oliver Jowett
Date:
Tom Lane wrote: > Oliver Jowett <oliver@opencloud.com> writes: > >>Tom Lane wrote: >> >>>I'm not convinced that Postgres ought to provide >>>a way to second-guess the TCP stack ... > > >>Would you be ok with a patch that allowed configuration of the >>TCP_KEEPCNT / TCP_KEEPIDLE / TCP_KEEPINTVL socket options on backend >>sockets? > > > [ shrug... ] As long as it doesn't fail to build on platforms that > don't offer those options, I couldn't complain too hard. But do we > really need all that? Here's a patch that adds four new GUCs: tcp_keepalives (defaults to on, controls SO_KEEPALIVE) tcp_keepalives_idle (controls TCP_KEEPIDLE) tcp_keepalives_interval (controls TCP_KEEPINTVL) tcp_keepalives_count (controls TCP_KEEPCNT) They're ignored for AF_UNIX connections and when running standalone. tcp_keepalives_* treat 0 as "use system default". If the underlying OS doesn't provide the TCP_KEEP* socket options, the GUCs are present but reject any value other than 0. SHOW reflects the currently-in-use value or 0 if not applicable or not known. i.e. if you set it to 0 and you have the socket options available, SHOW will show the result of getsockopt() which is non-zero. A default install on my Linux system produces: template1=# show all; name | setting --------------------------------+---------------------------------------------- [...] tcp_keepalives | on tcp_keepalives_count | 9 tcp_keepalives_idle | 7200 tcp_keepalives_interval | 75 [...] I haven't had a chance to check it builds on other systems or to test that this handles actual network failures nicely yet. -O Index: doc/src/sgml/runtime.sgml =================================================================== RCS file: /projects/cvsroot/pgsql/doc/src/sgml/runtime.sgml,v retrieving revision 1.315 diff -c -r1.315 runtime.sgml *** doc/src/sgml/runtime.sgml 23 Apr 2005 03:27:40 -0000 1.315 --- doc/src/sgml/runtime.sgml 3 May 2005 01:44:02 -0000 *************** *** 889,894 **** --- 889,961 ---- </listitem> </varlistentry> + <varlistentry id="guc-tcp-keepalives" xreflabel="tcp_keepalives"> + <term><varname>tcp_keepalives</varname> (<type>boolean</type>)</term> + <indexterm> + <primary><varname>tcp_keepalives</> configuration parameter</primary> + </indexterm> + <listitem> + <para> + Controls the use of TCP keepalives on client connections. When enabled, + idle connections will be periodically probed to check that the client + is still present. If sufficient probes are lost, the connection will + be broken. This option is ignored for connections made via a + Unix-domain socket. + </para> + </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, and will have no effect + unless the <varname>tcp_keepalives</varname> option is enabled. + </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, and will have no effect + unless the <varname>tcp_keepalives</varname> option is enabled. + </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. This option is ignored for + connections made via a Unix-domain socket, and will have no effect + unless the <varname>tcp_keepalives</varname> option is enabled. + </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 -c -r1.176 pqcomm.c *** src/backend/libpq/pqcomm.c 22 Feb 2005 04:35:57 -0000 1.176 --- src/backend/libpq/pqcomm.c 3 May 2005 01:44:03 -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 *************** *** 577,582 **** --- 577,583 ---- if (!IS_AF_UNIX(port->laddr.addr.ss_family)) { int on; + socklen_t size; #ifdef TCP_NODELAY on = 1; *************** *** 587,599 **** return STATUS_ERROR; } #endif ! on = 1; ! if (setsockopt(port->sock, SOL_SOCKET, SO_KEEPALIVE, ! (char *) &on, sizeof(on)) < 0) { ! elog(LOG, "setsockopt(SO_KEEPALIVE) failed: %m"); return STATUS_ERROR; } } return STATUS_OK; --- 588,645 ---- return STATUS_ERROR; } #endif ! ! if (pq_setkeepalives(tcp_keepalives, port) != STATUS_OK) ! return STATUS_ERROR; ! ! /* Grab default keepalive values, then apply ! * our GUC settings. ! */ ! #ifdef TCP_KEEPIDLE ! if (getsockopt(port->sock, SOL_TCP, TCP_KEEPIDLE, ! (char *) &port->default_keepalives_idle, &size) < 0) ! { ! elog(LOG, "getsockopt(TCP_KEEPIDLE) failed: %m"); ! return STATUS_ERROR; ! } ! #else ! port->default_keepalives_idle = 0; ! #endif ! ! #ifdef TCP_KEEPINTVL ! if (getsockopt(port->sock, SOL_TCP, TCP_KEEPINTVL, ! (char *) &port->default_keepalives_interval, &size) < 0) { ! elog(LOG, "getsockopt(TCP_KEEPINTVL) failed: %m"); return STATUS_ERROR; } + #else + port->default_keepalives_idle = 0; + #endif + + #ifdef TCP_KEEPCNT + if (getsockopt(port->sock, SOL_TCP, TCP_KEEPCNT, + (char *) &port->default_keepalives_count, &size) < 0) + { + elog(LOG, "getsockopt(TCP_KEEPCNT) failed: %m"); + return STATUS_ERROR; + } + #else + port->default_keepalives_idle = 0; + #endif + + /* 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 **** --- 1204,1305 ---- /* in non-error case, copy.c will have emitted the terminator line */ DoingCopyOut = false; } + + int + pq_setkeepalives(bool onoff, Port *port) + { + int on = (onoff ? 1 : 0); + + if (IS_AF_UNIX(port->laddr.addr.ss_family)) + return STATUS_OK; + + if (setsockopt(port->sock, SOL_SOCKET, SO_KEEPALIVE, + (char *) &on, sizeof(on)) < 0) + { + elog(LOG, "setsockopt(SO_KEEPALIVE) failed: %m"); + return STATUS_ERROR; + } + + return STATUS_OK; + } + + int + pq_setkeepalivesidle(int idle, Port *port) + { + if (IS_AF_UNIX(port->laddr.addr.ss_family)) + return STATUS_OK; + + #ifdef TCP_KEEPIDLE + 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; + } + #else + if (idle != 0) + { + elog(LOG, "setsockopt(TCP_KEEPIDLE) not supported"); + return STATUS_ERROR; + } + #endif + + return STATUS_OK; + } + + int + pq_setkeepalivesinterval(int interval, Port *port) + { + if (IS_AF_UNIX(port->laddr.addr.ss_family)) + return STATUS_OK; + + #ifdef TCP_KEEPINTVL + 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; + } + #else + if (interval != 0) + { + elog(LOG, "setsockopt(TCP_KEEPINTVL) not supported"); + return STATUS_ERROR; + } + #endif + + return STATUS_OK; + } + + int + pq_setkeepalivescount(int count, Port *port) + { + if (IS_AF_UNIX(port->laddr.addr.ss_family)) + return STATUS_OK; + + #ifdef TCP_KEEPCNT + 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; + } + #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.261 diff -c -r1.261 guc.c *** src/backend/utils/misc/guc.c 1 May 2005 18:56:19 -0000 1.261 --- src/backend/utils/misc/guc.c 3 May 2005 01:44:08 -0000 *************** *** 113,118 **** --- 113,125 ---- 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(bool 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 *************** *** 154,159 **** --- 161,170 ---- char *IdentFileName; char *external_pid_file; + bool tcp_keepalives = true; + 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 *************** *** 860,865 **** --- 871,885 ---- #endif }, + { + {"tcp_keepalives", PGC_USERSET, CLIENT_CONN_OTHER, + gettext_noop("Use keepalives on client TCP connections."), + NULL, + }, + &tcp_keepalives, + true, assign_tcp_keepalives, NULL + }, + /* End-of-list marker */ { {NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL *************** *** 1333,1338 **** --- 1353,1387 ---- 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 *************** *** 5677,5681 **** --- 5726,5802 ---- return newval; } + static bool + assign_tcp_keepalives(bool newval, bool doit, GucSource source) + { + if (doit && MyProcPort != NULL) + { + pq_setkeepalives(newval, MyProcPort); + } + return true; + } + + 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", + (tcp_keepalives_idle != 0 || MyProcPort == NULL) + ? tcp_keepalives_idle : MyProcPort->default_keepalives_idle); + 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", + (tcp_keepalives_interval != 0 || MyProcPort == NULL) + ? tcp_keepalives_interval : MyProcPort->default_keepalives_interval); + 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", + (tcp_keepalives_count != 0 || MyProcPort == NULL) + ? tcp_keepalives_count : MyProcPort->default_keepalives_count); + 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.140 diff -c -r1.140 postgresql.conf.sample *** src/backend/utils/misc/postgresql.conf.sample 21 Apr 2005 19:18:13 -0000 1.140 --- src/backend/utils/misc/postgresql.conf.sample 3 May 2005 01:44:08 -0000 *************** *** 66,71 **** --- 66,77 ---- #krb_server_keyfile = '' #db_user_namespace = false + # - TCP Keepalives - + # see 'man 7 tcp' for details + #tcp_keepalives = on # enables use of TCP keepalives + #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.125 diff -c -r1.125 tab-complete.c *** src/bin/psql/tab-complete.c 21 Apr 2005 19:18:13 -0000 1.125 --- src/bin/psql/tab-complete.c 3 May 2005 01:44:10 -0000 *************** *** 595,600 **** --- 595,604 ---- "superuser_reserved_connections", "syslog_facility", "syslog_ident", + "tcp_keepalives", + "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 -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 3 May 2005 01:44:10 -0000 *************** *** 92,100 **** --- 92,113 ---- char peer_cn[SM_USER + 1]; unsigned long count; #endif + + /* + * Default TCP keepalive values found after accept(); 0 if unsupported or AF_UNIX. + */ + int default_keepalives_idle; + int default_keepalives_interval; + int default_keepalives_count; } Port; extern ProtocolVersion FrontendProtocol; + /* TCP keepalives configuration. These are no-ops on an AF_UNIX socket. */ + extern int pq_setkeepalives(bool onoff, 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.60 diff -c -r1.60 guc.h *** src/include/utils/guc.h 25 Mar 2005 16:17:28 -0000 1.60 --- src/include/utils/guc.h 3 May 2005 01:44:10 -0000 *************** *** 133,138 **** --- 133,142 ---- extern char *IdentFileName; extern char *external_pid_file; + extern bool tcp_keepalives; + 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);
Oliver Jowett wrote: > Here's a patch that adds four new GUCs: > I haven't had a chance to check it builds on other systems or to test > that this handles actual network failures nicely yet. The patch builds OK on Solaris 9, which doesn't have the required socket options. Solaris (and some other OSes, apparently) supports TCP_KEEPALIVE instead of TCP_KEEPIDLE/TCP_KEEPCNT/TCP_KEEPINTVL. I will look at adding support for that next. -O
Where are we on this? I do think it solves a problem that some are having, and it seems it would detect a disconnected client and abort a long running query. I am not very excited about adding four more GUC variables, and I am thinking we could just have it use the OS defaults and see if we need more later, so that would add only one GUC. It compiles/tests fine on my BSD system. --------------------------------------------------------------------------- Oliver Jowett wrote: > Tom Lane wrote: > > Oliver Jowett <oliver@opencloud.com> writes: > > > >>Tom Lane wrote: > >> > >>>I'm not convinced that Postgres ought to provide > >>>a way to second-guess the TCP stack ... > > > > > >>Would you be ok with a patch that allowed configuration of the > >>TCP_KEEPCNT / TCP_KEEPIDLE / TCP_KEEPINTVL socket options on backend > >>sockets? > > > > > > [ shrug... ] As long as it doesn't fail to build on platforms that > > don't offer those options, I couldn't complain too hard. But do we > > really need all that? > > Here's a patch that adds four new GUCs: > > tcp_keepalives (defaults to on, controls SO_KEEPALIVE) > tcp_keepalives_idle (controls TCP_KEEPIDLE) > tcp_keepalives_interval (controls TCP_KEEPINTVL) > tcp_keepalives_count (controls TCP_KEEPCNT) > > They're ignored for AF_UNIX connections and when running standalone. > > tcp_keepalives_* treat 0 as "use system default". If the underlying OS > doesn't provide the TCP_KEEP* socket options, the GUCs are present but > reject any value other than 0. > > SHOW reflects the currently-in-use value or 0 if not applicable or not > known. i.e. if you set it to 0 and you have the socket options > available, SHOW will show the result of getsockopt() which is non-zero. > > A default install on my Linux system produces: > > template1=# show all; > name | setting > > --------------------------------+---------------------------------------------- > [...] > tcp_keepalives | on > tcp_keepalives_count | 9 > tcp_keepalives_idle | 7200 > tcp_keepalives_interval | 75 > [...] > > I haven't had a chance to check it builds on other systems or to test > that this handles actual network failures nicely yet. > > -O > Index: doc/src/sgml/runtime.sgml > =================================================================== > RCS file: /projects/cvsroot/pgsql/doc/src/sgml/runtime.sgml,v > retrieving revision 1.315 > diff -c -r1.315 runtime.sgml > *** doc/src/sgml/runtime.sgml 23 Apr 2005 03:27:40 -0000 1.315 > --- doc/src/sgml/runtime.sgml 3 May 2005 01:44:02 -0000 > *************** > *** 889,894 **** > --- 889,961 ---- > </listitem> > </varlistentry> > > + <varlistentry id="guc-tcp-keepalives" xreflabel="tcp_keepalives"> > + <term><varname>tcp_keepalives</varname> (<type>boolean</type>)</term> > + <indexterm> > + <primary><varname>tcp_keepalives</> configuration parameter</primary> > + </indexterm> > + <listitem> > + <para> > + Controls the use of TCP keepalives on client connections. When enabled, > + idle connections will be periodically probed to check that the client > + is still present. If sufficient probes are lost, the connection will > + be broken. This option is ignored for connections made via a > + Unix-domain socket. > + </para> > + </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, and will have no effect > + unless the <varname>tcp_keepalives</varname> option is enabled. > + </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, and will have no effect > + unless the <varname>tcp_keepalives</varname> option is enabled. > + </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. This option is ignored for > + connections made via a Unix-domain socket, and will have no effect > + unless the <varname>tcp_keepalives</varname> option is enabled. > + </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 -c -r1.176 pqcomm.c > *** src/backend/libpq/pqcomm.c 22 Feb 2005 04:35:57 -0000 1.176 > --- src/backend/libpq/pqcomm.c 3 May 2005 01:44:03 -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 > *************** > *** 577,582 **** > --- 577,583 ---- > if (!IS_AF_UNIX(port->laddr.addr.ss_family)) > { > int on; > + socklen_t size; > > #ifdef TCP_NODELAY > on = 1; > *************** > *** 587,599 **** > return STATUS_ERROR; > } > #endif > ! on = 1; > ! if (setsockopt(port->sock, SOL_SOCKET, SO_KEEPALIVE, > ! (char *) &on, sizeof(on)) < 0) > { > ! elog(LOG, "setsockopt(SO_KEEPALIVE) failed: %m"); > return STATUS_ERROR; > } > } > > return STATUS_OK; > --- 588,645 ---- > return STATUS_ERROR; > } > #endif > ! > ! if (pq_setkeepalives(tcp_keepalives, port) != STATUS_OK) > ! return STATUS_ERROR; > ! > ! /* Grab default keepalive values, then apply > ! * our GUC settings. > ! */ > ! #ifdef TCP_KEEPIDLE > ! if (getsockopt(port->sock, SOL_TCP, TCP_KEEPIDLE, > ! (char *) &port->default_keepalives_idle, &size) < 0) > ! { > ! elog(LOG, "getsockopt(TCP_KEEPIDLE) failed: %m"); > ! return STATUS_ERROR; > ! } > ! #else > ! port->default_keepalives_idle = 0; > ! #endif > ! > ! #ifdef TCP_KEEPINTVL > ! if (getsockopt(port->sock, SOL_TCP, TCP_KEEPINTVL, > ! (char *) &port->default_keepalives_interval, &size) < 0) > { > ! elog(LOG, "getsockopt(TCP_KEEPINTVL) failed: %m"); > return STATUS_ERROR; > } > + #else > + port->default_keepalives_idle = 0; > + #endif > + > + #ifdef TCP_KEEPCNT > + if (getsockopt(port->sock, SOL_TCP, TCP_KEEPCNT, > + (char *) &port->default_keepalives_count, &size) < 0) > + { > + elog(LOG, "getsockopt(TCP_KEEPCNT) failed: %m"); > + return STATUS_ERROR; > + } > + #else > + port->default_keepalives_idle = 0; > + #endif > + > + /* 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 **** > --- 1204,1305 ---- > /* in non-error case, copy.c will have emitted the terminator line */ > DoingCopyOut = false; > } > + > + int > + pq_setkeepalives(bool onoff, Port *port) > + { > + int on = (onoff ? 1 : 0); > + > + if (IS_AF_UNIX(port->laddr.addr.ss_family)) > + return STATUS_OK; > + > + if (setsockopt(port->sock, SOL_SOCKET, SO_KEEPALIVE, > + (char *) &on, sizeof(on)) < 0) > + { > + elog(LOG, "setsockopt(SO_KEEPALIVE) failed: %m"); > + return STATUS_ERROR; > + } > + > + return STATUS_OK; > + } > + > + int > + pq_setkeepalivesidle(int idle, Port *port) > + { > + if (IS_AF_UNIX(port->laddr.addr.ss_family)) > + return STATUS_OK; > + > + #ifdef TCP_KEEPIDLE > + 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; > + } > + #else > + if (idle != 0) > + { > + elog(LOG, "setsockopt(TCP_KEEPIDLE) not supported"); > + return STATUS_ERROR; > + } > + #endif > + > + return STATUS_OK; > + } > + > + int > + pq_setkeepalivesinterval(int interval, Port *port) > + { > + if (IS_AF_UNIX(port->laddr.addr.ss_family)) > + return STATUS_OK; > + > + #ifdef TCP_KEEPINTVL > + 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; > + } > + #else > + if (interval != 0) > + { > + elog(LOG, "setsockopt(TCP_KEEPINTVL) not supported"); > + return STATUS_ERROR; > + } > + #endif > + > + return STATUS_OK; > + } > + > + int > + pq_setkeepalivescount(int count, Port *port) > + { > + if (IS_AF_UNIX(port->laddr.addr.ss_family)) > + return STATUS_OK; > + > + #ifdef TCP_KEEPCNT > + 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; > + } > + #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.261 > diff -c -r1.261 guc.c > *** src/backend/utils/misc/guc.c 1 May 2005 18:56:19 -0000 1.261 > --- src/backend/utils/misc/guc.c 3 May 2005 01:44:08 -0000 > *************** > *** 113,118 **** > --- 113,125 ---- > 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(bool 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 > *************** > *** 154,159 **** > --- 161,170 ---- > char *IdentFileName; > char *external_pid_file; > > + bool tcp_keepalives = true; > + 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 > *************** > *** 860,865 **** > --- 871,885 ---- > #endif > }, > > + { > + {"tcp_keepalives", PGC_USERSET, CLIENT_CONN_OTHER, > + gettext_noop("Use keepalives on client TCP connections."), > + NULL, > + }, > + &tcp_keepalives, > + true, assign_tcp_keepalives, NULL > + }, > + > /* End-of-list marker */ > { > {NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL > *************** > *** 1333,1338 **** > --- 1353,1387 ---- > 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 > *************** > *** 5677,5681 **** > --- 5726,5802 ---- > return newval; > } > > + static bool > + assign_tcp_keepalives(bool newval, bool doit, GucSource source) > + { > + if (doit && MyProcPort != NULL) > + { > + pq_setkeepalives(newval, MyProcPort); > + } > + return true; > + } > + > + 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", > + (tcp_keepalives_idle != 0 || MyProcPort == NULL) > + ? tcp_keepalives_idle : MyProcPort->default_keepalives_idle); > + 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", > + (tcp_keepalives_interval != 0 || MyProcPort == NULL) > + ? tcp_keepalives_interval : MyProcPort->default_keepalives_interval); > + 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", > + (tcp_keepalives_count != 0 || MyProcPort == NULL) > + ? tcp_keepalives_count : MyProcPort->default_keepalives_count); > + 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.140 > diff -c -r1.140 postgresql.conf.sample > *** src/backend/utils/misc/postgresql.conf.sample 21 Apr 2005 19:18:13 -0000 1.140 > --- src/backend/utils/misc/postgresql.conf.sample 3 May 2005 01:44:08 -0000 > *************** > *** 66,71 **** > --- 66,77 ---- > #krb_server_keyfile = '' > #db_user_namespace = false > > + # - TCP Keepalives - > + # see 'man 7 tcp' for details > + #tcp_keepalives = on # enables use of TCP keepalives > + #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.125 > diff -c -r1.125 tab-complete.c > *** src/bin/psql/tab-complete.c 21 Apr 2005 19:18:13 -0000 1.125 > --- src/bin/psql/tab-complete.c 3 May 2005 01:44:10 -0000 > *************** > *** 595,600 **** > --- 595,604 ---- > "superuser_reserved_connections", > "syslog_facility", > "syslog_ident", > + "tcp_keepalives", > + "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 -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 3 May 2005 01:44:10 -0000 > *************** > *** 92,100 **** > --- 92,113 ---- > char peer_cn[SM_USER + 1]; > unsigned long count; > #endif > + > + /* > + * Default TCP keepalive values found after accept(); 0 if unsupported or AF_UNIX. > + */ > + int default_keepalives_idle; > + int default_keepalives_interval; > + int default_keepalives_count; > } Port; > > > extern ProtocolVersion FrontendProtocol; > > + /* TCP keepalives configuration. These are no-ops on an AF_UNIX socket. */ > + extern int pq_setkeepalives(bool onoff, 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.60 > diff -c -r1.60 guc.h > *** src/include/utils/guc.h 25 Mar 2005 16:17:28 -0000 1.60 > --- src/include/utils/guc.h 3 May 2005 01:44:10 -0000 > *************** > *** 133,138 **** > --- 133,142 ---- > extern char *IdentFileName; > extern char *external_pid_file; > > + extern bool tcp_keepalives; > + 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 5: Have you checked our extensive FAQ? > > http://www.postgresql.org/docs/faq -- 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
Bruce Momjian wrote: > Where are we on this? I do think it solves a problem that some are > having, and it seems it would detect a disconnected client and abort a > long running query. I haven't had a chance to do any work to support the Solaris stuff, but otherwise I'm just waiting on review. Note that the patch doesn't do anything about long-running queries, it's really about long-running connections/transactions. The server will only notice the disconnected client once it tries to read/write something. > I am not very excited about adding four more GUC variables, and I am > thinking we could just have it use the OS defaults and see if we need > more later, so that would add only one GUC. The whole point of the patch is that the system-wide defaults are usually not useful. The current, unpatched, server turns on SO_KEEPALIVE always, but the typical OS defaults set the timeout before probing to about 2 hours. -O
Re: Implement support for TCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVL (was Re: [HACKERS] Feature freeze date for 8.1)
From
Tom Lane
Date:
Oliver Jowett <oliver@opencloud.com> writes: > Here's a patch that adds four new GUCs: > tcp_keepalives (defaults to on, controls SO_KEEPALIVE) > tcp_keepalives_idle (controls TCP_KEEPIDLE) > tcp_keepalives_interval (controls TCP_KEEPINTVL) > tcp_keepalives_count (controls TCP_KEEPCNT) Do you think the system defaults are really going to be port-specific? I'm slightly annoyed by the number of syscalls this adds to every connection startup ... getting rid of redundant getsockopt calls would help. Getting rid of redundant setsockopt calls (ie, a call to establish the value that we already know is in force) would help more. Alternatively, we could lose the frammish that PostgreSQL can tell you what the system defaults are: 0 in the GUC just means "do nothing", not "find out what the current setting is on the off chance that the user might want to know". Or, if you really think that's important, it could be left to the SHOW routines to extract the value on-demand. That is: GUC = 0: do nothing at connection start GUC != 0: setsockopt at connection start SHOW: do getsockopt and report result regards, tom lane
Bruce Momjian <pgman@candle.pha.pa.us> writes: > I am not very excited about adding four more GUC variables, and I am > thinking we could just have it use the OS defaults and see if we need > more later, so that would add only one GUC. Huh? "Use the OS defaults" is where we are now. I'm unconvinced of the value of allowing people to turn off keepalive entirely, and therefore I question the need for the boolean tcp_keepalives GUC, but the other three appear useful. regards, tom lane
Tom Lane wrote: > Oliver Jowett <oliver@opencloud.com> writes: > >>Here's a patch that adds four new GUCs: > > >> tcp_keepalives (defaults to on, controls SO_KEEPALIVE) >> tcp_keepalives_idle (controls TCP_KEEPIDLE) >> tcp_keepalives_interval (controls TCP_KEEPINTVL) >> tcp_keepalives_count (controls TCP_KEEPCNT) > > Do you think the system defaults are really going to be port-specific? I don't understand what you mean. TCP_* override the system defaults on a per-connection basis, if that's what you mean. > I'm slightly annoyed by the number of syscalls this adds to every > connection startup ... getting rid of redundant getsockopt calls would > help. Getting rid of redundant setsockopt calls (ie, a call to > establish the value that we already know is in force) would help more. I originally did this but went in favor of simpler code. Are the extra syscalls an issue? I didn't think they were that expensive.. > Alternatively, we could lose the frammish that PostgreSQL can tell you > what the system defaults are: 0 in the GUC just means "do nothing", > not "find out what the current setting is on the off chance that the > user might want to know". I didn't do this as it meant that using SET tcp_whatever = 0 does *not* reset the setting to what you'd get with a value of 0 in postgresql.conf, which seemed confusing to me. This could all get simpler if we didn't allow per-connection changing of that GUC (i.e. set it once at startup and forget about it), which probably isn't unreasonable. I wonder if those socket options get inherited from the listening socket? Will check. -O
Is this patch being worked on? --------------------------------------------------------------------------- Oliver Jowett wrote: > Tom Lane wrote: > > Oliver Jowett <oliver@opencloud.com> writes: > > > >>Here's a patch that adds four new GUCs: > > > > > >> tcp_keepalives (defaults to on, controls SO_KEEPALIVE) > >> tcp_keepalives_idle (controls TCP_KEEPIDLE) > >> tcp_keepalives_interval (controls TCP_KEEPINTVL) > >> tcp_keepalives_count (controls TCP_KEEPCNT) > > > > Do you think the system defaults are really going to be port-specific? > > I don't understand what you mean. TCP_* override the system defaults on > a per-connection basis, if that's what you mean. > > > I'm slightly annoyed by the number of syscalls this adds to every > > connection startup ... getting rid of redundant getsockopt calls would > > help. Getting rid of redundant setsockopt calls (ie, a call to > > establish the value that we already know is in force) would help more. > > I originally did this but went in favor of simpler code. Are the extra > syscalls an issue? I didn't think they were that expensive.. > > > Alternatively, we could lose the frammish that PostgreSQL can tell you > > what the system defaults are: 0 in the GUC just means "do nothing", > > not "find out what the current setting is on the off chance that the > > user might want to know". > > I didn't do this as it meant that using SET tcp_whatever = 0 does *not* > reset the setting to what you'd get with a value of 0 in > postgresql.conf, which seemed confusing to me. > > This could all get simpler if we didn't allow per-connection changing of > that GUC (i.e. set it once at startup and forget about it), which > probably isn't unreasonable. I wonder if those socket options get > inherited from the listening socket? Will check. > > -O > > ---------------------------(end of broadcast)--------------------------- > TIP 9: the planner will ignore your desire to choose an index scan if your > joining column's datatypes do not match > -- 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
Bruce Momjian wrote: > Is this patch being worked on? I have shelved it for the moment, waiting on any further comments from Tom before reworking it. -O
Oliver Jowett wrote: > Bruce Momjian wrote: > > Is this patch being worked on? > > I have shelved it for the moment, waiting on any further comments from > Tom before reworking it. I thought he wanted the patch modified so keepalive could never be turned off, but that the OS default parameters could be changed. -- 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
Bruce Momjian <pgman@candle.pha.pa.us> writes: > Oliver Jowett wrote: >> I have shelved it for the moment, waiting on any further comments from >> Tom before reworking it. > I thought he wanted the patch modified so keepalive could never be > turned off, but that the OS default parameters could be changed. I wanted it fixed to not do a lot of extra kernel calls during backend startup... regards, tom lane
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);
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
Bruce Momjian wrote: > Is this the functionality we agreed we wanted? I think it covers Tom's comments on the first version: - a GUC to turn off SO_KEEPALIVE isn't particularly useful - don't do redundant get/setsockopt calls on backend startup -O
Patch applied. Thanks. --------------------------------------------------------------------------- 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