aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBruce Momjian <bruce@momjian.us>2005-07-30 15:17:26 +0000
committerBruce Momjian <bruce@momjian.us>2005-07-30 15:17:26 +0000
commit1f54d43075d8c457935cd9fe8adfea949104995d (patch)
tree1dae9895c68da69a255b08d5e5f349ea8cdc0a3f /src
parentb2b6548c79eb63faf1d0939893b3bf183d5410a1 (diff)
downloadpostgresql-1f54d43075d8c457935cd9fe8adfea949104995d.tar.gz
postgresql-1f54d43075d8c457935cd9fe8adfea949104995d.zip
Add GUC variables to control keep-alive times for idle, interval, and
count. Oliver Jowett
Diffstat (limited to 'src')
-rw-r--r--src/backend/libpq/pqcomm.c213
-rw-r--r--src/backend/utils/misc/guc.c96
-rw-r--r--src/backend/utils/misc/postgresql.conf.sample5
-rw-r--r--src/bin/psql/tab-complete.c5
-rw-r--r--src/include/libpq/libpq-be.h33
-rw-r--r--src/include/utils/guc.h5
6 files changed, 351 insertions, 6 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)
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 80441733fb1..2be131993bb 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -3,7 +3,7 @@
*
* Copyright (c) 2000-2005, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.135 2005/07/28 22:14:30 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.136 2005/07/30 15:17:22 momjian Exp $
*/
/*----------------------------------------------------------------------
@@ -601,6 +601,9 @@ psql_completion(char *text, int start, int end)
"superuser_reserved_connections",
"syslog_facility",
"syslog_ident",
+ "tcp_keepalives_idle",
+ "tcp_keepalives_interval",
+ "tcp_keepalives_count",
"temp_buffers",
"TimeZone",
"trace_notify",
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index cec679577bd..bbc218a0e1e 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -11,7 +11,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/libpq/libpq-be.h,v 1.49 2004/12/31 22:03:32 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/libpq/libpq-be.h,v 1.50 2005/07/30 15:17:25 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -25,6 +25,9 @@
#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,9 +95,37 @@ typedef struct Port
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 */
diff --git a/src/include/utils/guc.h b/src/include/utils/guc.h
index c08ecd4db42..00399bd488c 100644
--- a/src/include/utils/guc.h
+++ b/src/include/utils/guc.h
@@ -7,7 +7,7 @@
* Copyright (c) 2000-2005, PostgreSQL Global Development Group
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
- * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.61 2005/06/26 03:04:12 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.62 2005/07/30 15:17:26 momjian Exp $
*--------------------------------------------------------------------
*/
#ifndef GUC_H
@@ -134,6 +134,9 @@ extern char *HbaFileName;
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);