On Tue, Feb 9, 2010 at 11:34 PM, Andrew Chernow <[email protected]> wrote:
> If you really want libpq to manage this, I think you need to expose the
> probe interval and timeouts.
Agreed.
Previously I was making the patch that exposes them as conninfo
options so that the standby can detect a network outage ASAP in SR.
I attached that WIP patch as a reference. Hope this helps.
Regards,
--
Fujii Masao
NIPPON TELEGRAPH AND TELEPHONE CORPORATION
NTT Open Source Software Center
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 31ee680..2687827 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -180,6 +180,15 @@ static const PQconninfoOption PQconninfoOptions[] = {
{"fallback_application_name", NULL, NULL, NULL,
"Fallback-Application-Name", "", 64},
+ {"keepalives_idle", "PGKEEPALIVESIDLE", NULL, NULL,
+ "TCP-Keepalive-Idle", "", 10}, /* strlen(INT32_MAX) == 10 */
+
+ {"keepalives_interval", "PGKEEPALIVESINTERVAL", NULL, NULL,
+ "TCP-Keepalive-Interval", "", 10}, /* strlen(INT32_MAX) == 10 */
+
+ {"keepalives_count", "PGKEEPALIVESCOUNT", NULL, NULL,
+ "TCP-Keepalive-Count", "", 10}, /* strlen(INT32_MAX) == 10 */
+
#ifdef USE_SSL
/*
@@ -452,6 +461,12 @@ connectOptions1(PGconn *conn, const char *conninfo)
conn->pgpass = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "connect_timeout");
conn->connect_timeout = tmp ? strdup(tmp) : NULL;
+ tmp = conninfo_getval(connOptions, "keepalives_idle");
+ conn->keepalives_idle = tmp ? strdup(tmp) : NULL;
+ tmp = conninfo_getval(connOptions, "keepalives_interval");
+ conn->keepalives_interval = tmp ? strdup(tmp) : NULL;
+ tmp = conninfo_getval(connOptions, "keepalives_count");
+ conn->keepalives_count = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "sslmode");
conn->sslmode = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "sslkey");
@@ -809,6 +824,114 @@ connectFailureMessage(PGconn *conn, int errorno)
}
+static int
+setKeepalivesIdle(PGconn *conn)
+{
+ int idle;
+
+ if (conn->keepalives_idle == NULL || IS_AF_UNIX(conn->laddr.addr.ss_family))
+ return 1;
+
+ idle = atoi(conn->keepalives_idle);
+ if (idle < 0)
+ idle = 0;
+
+#ifdef TCP_KEEPIDLE
+ if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPIDLE,
+ (char *) &idle, sizeof(idle)) < 0)
+ {
+ char sebuf[256];
+
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("setsockopt(TCP_KEEPIDLE) failed: %s\n"),
+ SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
+ return 0;
+ }
+#else
+ if (idle != 0)
+ {
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("setsockopt(TCP_KEEPIDLE) not supported"));
+ return 0;
+ }
+#endif
+
+ return 1;
+}
+
+
+static int
+setKeepalivesInterval(PGconn *conn)
+{
+ int interval;
+
+ if (conn->keepalives_interval == NULL || IS_AF_UNIX(conn->laddr.addr.ss_family))
+ return 1;
+
+ interval = atoi(conn->keepalives_interval);
+ if (interval < 0)
+ interval = 0;
+
+#ifdef TCP_KEEPINTVL
+ if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPINTVL,
+ (char *) &interval, sizeof(interval)) < 0)
+ {
+ char sebuf[256];
+
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("setsockopt(TCP_KEEPINTVL) failed: %s\n"),
+ SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
+ return 0;
+ }
+#else
+ if (interval != 0)
+ {
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("setsockopt(TCP_KEEPINTVL) not supported"));
+ return 0;
+ }
+#endif
+
+ return 1;
+}
+
+
+static int
+setKeepalivesCount(PGconn *conn)
+{
+ int count;
+
+ if (conn->keepalives_count == NULL || IS_AF_UNIX(conn->laddr.addr.ss_family))
+ return 1;
+
+ count = atoi(conn->keepalives_count);
+ if (count < 0)
+ count = 0;
+
+#ifdef TCP_KEEPCNT
+ if (setsockopt(conn->sock, IPPROTO_TCP, TCP_KEEPCNT,
+ (char *) &count, sizeof(count)) < 0)
+ {
+ char sebuf[256];
+
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("setsockopt(TCP_KEEPCNT) failed: %s\n"),
+ SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
+ return 0;
+ }
+#else
+ if (count != 0)
+ {
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("setsockopt(TCP_KEEPCNT) not supported"));
+ return 0;
+ }
+#endif
+
+ return 1;
+}
+
+
/* ----------
* connectDBStart -
* Begin the process of making a connection to the backend.
@@ -1157,8 +1280,8 @@ keep_going: /* We will come back to here until there is
/*
* Select socket options: no delay of outgoing data for
- * TCP sockets, nonblock mode, close-on-exec. Fail if any
- * of this fails.
+ * TCP sockets, nonblock mode, close-on-exec and keepalives.
+ * Fail if any of this fails.
*/
if (!IS_AF_UNIX(addr_cur->ai_family))
{
@@ -1194,6 +1317,32 @@ keep_going: /* We will come back to here until there is
}
#endif /* F_SETFD */
+ if (!IS_AF_UNIX(conn->laddr.addr.ss_family))
+ {
+ int on;
+
+ on = 1;
+ if (setsockopt(conn->sock, SOL_SOCKET, SO_KEEPALIVE,
+ (char *) &on, sizeof(on)) < 0)
+ {
+ appendPQExpBuffer(&conn->errorMessage,
+ libpq_gettext("setsockopt(SO_KEEPALIVE) failed: %s\n"),
+ SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
+ closesocket(conn->sock);
+ conn->sock = -1;
+ conn->addr_cur = addr_cur->ai_next;
+ continue;
+ }
+ }
+ if (!setKeepalivesIdle(conn) || !setKeepalivesInterval(conn) ||
+ !setKeepalivesCount(conn))
+ {
+ closesocket(conn->sock);
+ conn->sock = -1;
+ conn->addr_cur = addr_cur->ai_next;
+ continue;
+ }
+
/*----------
* We have three methods of blocking SIGPIPE during
* send() calls to this socket:
@@ -2152,6 +2301,12 @@ freePGconn(PGconn *conn)
free(conn->pguser);
if (conn->pgpass)
free(conn->pgpass);
+ if (conn->keepalives_idle)
+ free(conn->keepalives_idle);
+ if (conn->keepalives_interval)
+ free(conn->keepalives_interval);
+ if (conn->keepalives_count)
+ free(conn->keepalives_count);
if (conn->sslmode)
free(conn->sslmode);
if (conn->sslcert)
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 944e6ca..338dbbd 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -301,6 +301,9 @@ struct pg_conn
char *replication; /* connect as the replication standby? */
char *pguser; /* Postgres username and password, if any */
char *pgpass;
+ char *keepalives_idle; /* time between issuing TCP keepalives */
+ char *keepalives_interval; /* time between TCP keepalive retransmits */
+ char *keepalives_count; /* maximum number of TCP keepalive retransmits */
char *sslmode; /* SSL mode (require,prefer,allow,disable) */
char *sslkey; /* client key filename */
char *sslcert; /* client certificate filename */
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers