On Tue, Feb 9, 2010 at 11:34 PM, Andrew Chernow <a...@esilo.com> 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 (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers