? 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 ---- + + tcp_keepalives_idle (integer) + + tcp_keepalives_idle configuration parameter + + + + 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. + + + + + + tcp_keepalives_interval (integer) + + tcp_keepalives_interval configuration parameter + + + + 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. + + + + + + tcp_keepalives_count (integer) + + tcp_keepalives_count configuration parameter + + + + 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. + + + + 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 #include #endif + #ifdef HAVE_NETINET_TCP_H + #include + #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);