diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/libpq/pqcomm.c | 213 | ||||
-rw-r--r-- | src/backend/utils/misc/guc.c | 96 | ||||
-rw-r--r-- | src/backend/utils/misc/postgresql.conf.sample | 5 |
3 files changed, 311 insertions, 3 deletions
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index ce321af4b13..43c2a88a451 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -30,7 +30,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/libpq/pqcomm.c,v 1.176 2005/02/22 04:35:57 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/libpq/pqcomm.c,v 1.177 2005/07/30 15:17:20 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -87,7 +87,7 @@ #include "libpq/libpq.h" #include "miscadmin.h" #include "storage/ipc.h" - +#include "utils/guc.h" /* * Configuration options @@ -594,6 +594,19 @@ StreamConnection(int server_fd, Port *port) 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,3 +1171,199 @@ pq_endcopyout(bool errorAbort) /* 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; +} diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index da6aa1a9c36..f3426b18cab 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -10,7 +10,7 @@ * Written by Peter Eisentraut <peter_e@gmx.net>. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.279 2005/07/29 19:30:07 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.280 2005/07/30 15:17:20 momjian Exp $ * *-------------------------------------------------------------------- */ @@ -120,6 +120,12 @@ static bool assign_log_stats(bool newval, bool doit, GucSource source); 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 @@ -161,6 +167,9 @@ char *HbaFileName; 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 @@ -1437,6 +1446,35 @@ static struct config_int ConfigureNamesInt[] = 500, 0, INT_MAX, 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 @@ -5815,5 +5853,61 @@ assign_canonical_path(const char *newval, bool doit, GucSource source) 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" diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index db8c28814db..5eabe09552e 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -70,6 +70,11 @@ #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) |