Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit d8cd283

Browse files
committed
Add TCP keepalive support to libpq.
This adds four additional connection parameters to libpq: keepalives, keepalives_idle, keepalives_count, and keepalives_interval. keepalives default to on, per discussion, but can be turned off by specifying keepalives=0. The remaining parameters, where supported, can be used to adjust how often keepalives are sent and how many can be lost before the connection is broken. The immediate motivation for this patch is to make sure that walreceiver will eventually notice if the master reboots without closing the connection cleanly, but it should be helpful in other cases as well. Tollef Fog Heen, Fujii Masao, and me.
1 parent c1b6179 commit d8cd283

File tree

3 files changed

+238
-3
lines changed

3 files changed

+238
-3
lines changed

doc/src/sgml/libpq.sgml

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.308 2010/06/17 16:03:30 tgl Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/libpq.sgml,v 1.309 2010/06/23 21:54:13 rhaas Exp $ -->
22

33
<chapter id="libpq">
44
<title><application>libpq</application> - C Library</title>
@@ -280,6 +280,57 @@
280280
</listitem>
281281
</varlistentry>
282282

283+
<varlistentry id="libpq-keepalives" xreflabel="keepalives">
284+
<term><literal>keepalives</literal></term>
285+
<listitem>
286+
<para>
287+
Controls whether TCP keepalives are used. The default value is 1,
288+
meaning on, but you can change this to 0, meaning off, if keepalives
289+
are not wanted. This parameter is ignored for connections made via
290+
a Unix-domain socket.
291+
</para>
292+
</listitem>
293+
</varlistentry>
294+
295+
<varlistentry id="libpq-keepalives-idle" xreflabel="keepalives_idle">
296+
<term><literal>keepalives_idle</literal></term>
297+
<listitem>
298+
<para>
299+
On systems that support the <symbol>TCP_KEEPIDLE</symbol> socket
300+
option, specifies the number of seconds between sending keepalives
301+
on an otherwise idle connection. A value of zero uses the system
302+
default. This parameter is ignored for connections made via a
303+
Unix-domain socket, or if keepalives are disabled.
304+
</para>
305+
</listitem>
306+
</varlistentry>
307+
308+
<varlistentry id="libpq-keepalives-interval" xreflabel="keepalives_interval">
309+
<term><literal>keepalives_interval</literal></term>
310+
<listitem>
311+
<para>
312+
On systems that support the <symbol>TCP_KEEPINTVL</symbol> socket
313+
option, specifies how long, in seconds, to wait for a response to a
314+
keepalive before retransmitting. A value of zero uses the system
315+
default. This parameter is ignored for connections made via a
316+
Unix-domain socket, or if keepalives are disabled.
317+
</para>
318+
</listitem>
319+
</varlistentry>
320+
321+
<varlistentry id="libpq-keepalives-count" xreflabel="keepalives_count">
322+
<term><literal>keepalives_count</literal></term>
323+
<listitem>
324+
<para>
325+
On systems that support the <symbol>TCP_KEEPCNT</symbol> socket
326+
option, specifies how many keepalives can be lost before the
327+
connection is considered dead. A value of zero uses the system
328+
default. This parameter is ignored for connections made via a
329+
Unix-domain socket, or if keepalives are disabled.
330+
</para>
331+
</listitem>
332+
</varlistentry>
333+
283334
<varlistentry id="libpq-connect-tty" xreflabel="tty">
284335
<term><literal>tty</literal></term>
285336
<listitem>

src/interfaces/libpq/fe-connect.c

Lines changed: 181 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.393 2010/05/26 21:39:27 tgl Exp $
11+
* $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.394 2010/06/23 21:54:13 rhaas Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -183,6 +183,18 @@ static const PQconninfoOption PQconninfoOptions[] = {
183183
{"fallback_application_name", NULL, NULL, NULL,
184184
"Fallback-Application-Name", "", 64},
185185

186+
{"keepalives", NULL, NULL, NULL,
187+
"TCP-Keepalives", "", 1}, /* should be just '0' or '1' */
188+
189+
{"keepalives_idle", NULL, NULL, NULL,
190+
"TCP-Keepalives-Idle", "", 10}, /* strlen(INT32_MAX) == 10 */
191+
192+
{"keepalives_interval", NULL, NULL, NULL,
193+
"TCP-Keepalives-Interval", "", 10}, /* strlen(INT32_MAX) == 10 */
194+
195+
{"keepalives_count", NULL, NULL, NULL,
196+
"TCP-Keepalives-Count", "", 10}, /* strlen(INT32_MAX) == 10 */
197+
186198
#ifdef USE_SSL
187199

188200
/*
@@ -552,6 +564,14 @@ fillPGconn(PGconn *conn, PQconninfoOption *connOptions)
552564
conn->pgpass = tmp ? strdup(tmp) : NULL;
553565
tmp = conninfo_getval(connOptions, "connect_timeout");
554566
conn->connect_timeout = tmp ? strdup(tmp) : NULL;
567+
tmp = conninfo_getval(connOptions, "keepalives");
568+
conn->keepalives = tmp ? strdup(tmp) : NULL;
569+
tmp = conninfo_getval(connOptions, "keepalives_idle");
570+
conn->keepalives_idle = tmp ? strdup(tmp) : NULL;
571+
tmp = conninfo_getval(connOptions, "keepalives_interval");
572+
conn->keepalives_interval = tmp ? strdup(tmp) : NULL;
573+
tmp = conninfo_getval(connOptions, "keepalives_count");
574+
conn->keepalives_count = tmp ? strdup(tmp) : NULL;
555575
tmp = conninfo_getval(connOptions, "sslmode");
556576
conn->sslmode = tmp ? strdup(tmp) : NULL;
557577
tmp = conninfo_getval(connOptions, "sslkey");
@@ -943,6 +963,119 @@ connectFailureMessage(PGconn *conn, int errorno)
943963
}
944964
}
945965

966+
/*
967+
* Should we use keepalives? Returns 1 if yes, 0 if no, and -1 if
968+
* conn->keepalives is set to a value which is not parseable as an
969+
* integer.
970+
*/
971+
static int
972+
useKeepalives(PGconn *conn)
973+
{
974+
char *ep;
975+
int val;
976+
977+
if (conn->keepalives == NULL)
978+
return 1;
979+
val = strtol(conn->keepalives, &ep, 10);
980+
if (*ep)
981+
return -1;
982+
return val != 0 ? 1 : 0;
983+
}
984+
985+
/*
986+
* Set the keepalive idle timer.
987+
*/
988+
static int
989+
setKeepalivesIdle(PGconn *conn)
990+
{
991+
int idle;
992+
993+
if (conn->keepalives_idle == NULL)
994+
return 1;
995+
996+
idle = atoi(conn->keepalives_idle);
997+
if (idle < 0)
998+
idle = 0;
999+
1000+
#ifdef TCP_KEEPIDLE
1001+
if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPIDLE,
1002+
(char *) &idle, sizeof(idle)) < 0)
1003+
{
1004+
char sebuf[256];
1005+
1006+
appendPQExpBuffer(&conn->errorMessage,
1007+
libpq_gettext("setsockopt(TCP_KEEPIDLE) failed: %s\n"),
1008+
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
1009+
return 0;
1010+
}
1011+
#endif
1012+
1013+
return 1;
1014+
}
1015+
1016+
/*
1017+
* Set the keepalive interval.
1018+
*/
1019+
static int
1020+
setKeepalivesInterval(PGconn *conn)
1021+
{
1022+
int interval;
1023+
1024+
if (conn->keepalives_interval == NULL)
1025+
return 1;
1026+
1027+
interval = atoi(conn->keepalives_interval);
1028+
if (interval < 0)
1029+
interval = 0;
1030+
1031+
#ifdef TCP_KEEPINTVL
1032+
if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPINTVL,
1033+
(char *) &interval, sizeof(interval)) < 0)
1034+
{
1035+
char sebuf[256];
1036+
1037+
appendPQExpBuffer(&conn->errorMessage,
1038+
libpq_gettext("setsockopt(TCP_KEEPINTVL) failed: %s\n"),
1039+
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
1040+
return 0;
1041+
}
1042+
#endif
1043+
1044+
return 1;
1045+
}
1046+
1047+
/*
1048+
* Set the count of lost keepalive packets that will trigger a connection
1049+
* break.
1050+
*/
1051+
static int
1052+
setKeepalivesCount(PGconn *conn)
1053+
{
1054+
int count;
1055+
1056+
if (conn->keepalives_count == NULL)
1057+
return 1;
1058+
1059+
count = atoi(conn->keepalives_count);
1060+
if (count < 0)
1061+
count = 0;
1062+
1063+
#ifdef TCP_KEEPCNT
1064+
if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPCNT,
1065+
(char *) &count, sizeof(count)) < 0)
1066+
{
1067+
char sebuf[256];
1068+
1069+
appendPQExpBuffer(&conn->errorMessage,
1070+
libpq_gettext("setsockopt(TCP_KEEPCNT) failed: %s\n"),
1071+
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
1072+
return 0;
1073+
}
1074+
#endif
1075+
1076+
return 1;
1077+
}
1078+
9461079

9471080
/* ----------
9481081
* connectDBStart -
@@ -1329,6 +1462,45 @@ PQconnectPoll(PGconn *conn)
13291462
}
13301463
#endif /* F_SETFD */
13311464

1465+
if (!IS_AF_UNIX(addr_cur->ai_family))
1466+
{
1467+
int on = 1;
1468+
int usekeepalives = useKeepalives(conn);
1469+
int err = 0;
1470+
1471+
if (usekeepalives < 0)
1472+
{
1473+
appendPQExpBuffer(&conn->errorMessage,
1474+
libpq_gettext("keepalives parameter must be an integer\n"));
1475+
err = 1;
1476+
}
1477+
else if (usekeepalives == 0)
1478+
{
1479+
/* Do nothing */
1480+
}
1481+
else if (setsockopt(conn->sock,
1482+
SOL_SOCKET, SO_KEEPALIVE,
1483+
(char *) &on, sizeof(on)) < 0)
1484+
{
1485+
appendPQExpBuffer(&conn->errorMessage,
1486+
libpq_gettext("setsockopt(SO_KEEPALIVE) failed: %s\n"),
1487+
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
1488+
err = 1;
1489+
}
1490+
else if (!setKeepalivesIdle(conn)
1491+
|| !setKeepalivesInterval(conn)
1492+
|| !setKeepalivesCount(conn))
1493+
err = 1;
1494+
1495+
if (err)
1496+
{
1497+
closesocket(conn->sock);
1498+
conn->sock = -1;
1499+
conn->addr_cur = addr_cur->ai_next;
1500+
continue;
1501+
}
1502+
}
1503+
13321504
/*----------
13331505
* We have three methods of blocking SIGPIPE during
13341506
* send() calls to this socket:
@@ -2290,6 +2462,14 @@ freePGconn(PGconn *conn)
22902462
free(conn->pguser);
22912463
if (conn->pgpass)
22922464
free(conn->pgpass);
2465+
if (conn->keepalives)
2466+
free(conn->keepalives);
2467+
if (conn->keepalives_idle)
2468+
free(conn->keepalives_idle);
2469+
if (conn->keepalives_interval)
2470+
free(conn->keepalives_interval);
2471+
if (conn->keepalives_count)
2472+
free(conn->keepalives_count);
22932473
if (conn->sslmode)
22942474
free(conn->sslmode);
22952475
if (conn->sslcert)

src/interfaces/libpq/libpq-int.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
1313
* Portions Copyright (c) 1994, Regents of the University of California
1414
*
15-
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.150 2010/03/13 14:55:57 momjian Exp $
15+
* $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.151 2010/06/23 21:54:13 rhaas Exp $
1616
*
1717
*-------------------------------------------------------------------------
1818
*/
@@ -300,6 +300,10 @@ struct pg_conn
300300
char *replication; /* connect as the replication standby? */
301301
char *pguser; /* Postgres username and password, if any */
302302
char *pgpass;
303+
char *keepalives; /* use TCP keepalives? */
304+
char *keepalives_idle; /* time between TCP keepalives */
305+
char *keepalives_interval; /* time between TCP keepalive retransmits */
306+
char *keepalives_count; /* maximum number of TCP keepalive retransmits */
303307
char *sslmode; /* SSL mode (require,prefer,allow,disable) */
304308
char *sslkey; /* client key filename */
305309
char *sslcert; /* client certificate filename */

0 commit comments

Comments
 (0)