On Sat, Feb 13, 2010 at 2:13 AM, Euler Taveira de Oliveira
<eu...@timbira.com> wrote:
> Marko Kreen escreveu:
>> 3) Support all 3 parameters (keepidle, keepintvl, keepcnt)
>>  and ignore parameters not supported by OS.
>>
> +1. AFAIR, we already do that for the backend.

+1 from me, too.

Here is the patch which provides those three parameters as conninfo
options. Should this patch be added into the first CommitFest for v9.1?

Regards,

-- 
Fujii Masao
NIPPON TELEGRAPH AND TELEPHONE CORPORATION
NTT Open Source Software Center
*** a/doc/src/sgml/libpq.sgml
--- b/doc/src/sgml/libpq.sgml
***************
*** 280,285 ****
--- 280,327 ----
           </listitem>
          </varlistentry>
  
+         <varlistentry id="libpq-keepalives-idle" xreflabel="keepalives_idle">
+          <term><literal>keepalives_idle</literal></term>
+          <listitem>
+           <para>
+            On systems that support the <symbol>TCP_KEEPIDLE</symbol> socket option,
+            specifies the number of seconds between sending keepalives on an otherwise
+            idle connection. A value of zero uses the system default.
+            If <symbol>TCP_KEEPIDLE</symbol> is not supported, this parameter must be
+            zero or must not be specified. This parameter is ignored for connections
+            made via a Unix-domain socket.
+           </para>
+          </listitem>
+         </varlistentry>
+ 
+         <varlistentry id="libpq-keepalives-interval" xreflabel="keepalives_interval">
+          <term><literal>keepalives_interval</literal></term>
+          <listitem>
+           <para>
+            On systems that support the <symbol>TCP_KEEPINTVL</symbol> socket option,
+            specifies how long, in seconds, to wait for a response to a keepalive before
+            retransmitting. A value of zero uses the system default.
+            If <symbol>TCP_KEEPINTVL</symbol> is not supported, this parameter must be
+            zero or must not be specified. This parameter is ignored for connections
+            made via a Unix-domain socket.
+           </para>
+          </listitem>
+         </varlistentry>
+ 
+         <varlistentry id="libpq-keepalives-count" xreflabel="keepalives_count">
+          <term><literal>keepalives_count</literal></term>
+          <listitem>
+           <para>
+            On systems that support the <symbol>TCP_KEEPCNT</symbol> socket option,
+            specifies how many keepalives can be lost before the connection is
+            considered dead. A value of zero uses the system default.
+            If <symbol>TCP_KEEPCNT</symbol> is not supported, this parameter must be
+            zero or must not be specified. This parameter is ignored for connections
+            made via a Unix-domain socket.
+           </para>
+          </listitem>
+         </varlistentry>
+ 
          <varlistentry id="libpq-connect-tty" xreflabel="tty">
           <term><literal>tty</literal></term>
           <listitem>
***************
*** 6013,6018 **** myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
--- 6055,6090 ----
      <listitem>
       <para>
        <indexterm>
+        <primary><envar>PGKEEPALIVESIDLE</envar></primary>
+       </indexterm>
+       <envar>PGKEEPALIVESIDLE</envar> behaves the same as the <xref
+       linkend="libpq-keepalives-idle"> connection parameter.
+      </para>
+     </listitem>
+ 
+     <listitem>
+      <para>
+       <indexterm>
+        <primary><envar>PGKEEPALIVESINTERVAL</envar></primary>
+       </indexterm>
+       <envar>PGKEEPALIVESINTERVAL</envar> behaves the same as the <xref
+       linkend="libpq-keepalives-interval"> connection parameter.
+      </para>
+     </listitem>
+ 
+     <listitem>
+      <para>
+       <indexterm>
+        <primary><envar>PGKEEPALIVESCOUNT</envar></primary>
+       </indexterm>
+       <envar>PGKEEPALIVESCOUNT</envar> behaves the same as the <xref
+       linkend="libpq-keepalives-count"> connection parameter.
+      </para>
+     </listitem>
+ 
+     <listitem>
+      <para>
+       <indexterm>
         <primary><envar>PGSSLMODE</envar></primary>
        </indexterm>
        <envar>PGSSLMODE</envar> behaves the same as the <xref
*** a/src/interfaces/libpq/fe-connect.c
--- b/src/interfaces/libpq/fe-connect.c
***************
*** 180,185 **** static const PQconninfoOption PQconninfoOptions[] = {
--- 180,194 ----
  	{"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
  
  	/*
***************
*** 547,552 **** fillPGconn(PGconn *conn, PQconninfoOption *connOptions)
--- 556,567 ----
  	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");
***************
*** 937,942 **** connectFailureMessage(PGconn *conn, int errorno)
--- 952,1065 ----
  }
  
  
+ 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.
***************
*** 1285,1292 **** 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.
  					 */
  					if (!IS_AF_UNIX(addr_cur->ai_family))
  					{
--- 1408,1415 ----
  
  					/*
  					 * Select socket options: no delay of outgoing data for
! 					 * TCP sockets, nonblock mode, close-on-exec and keepalives.
! 					 * Fail if any of this fails.
  					 */
  					if (!IS_AF_UNIX(addr_cur->ai_family))
  					{
***************
*** 1322,1327 **** keep_going:						/* We will come back to here until there is
--- 1445,1476 ----
  					}
  #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:
***************
*** 2280,2285 **** freePGconn(PGconn *conn)
--- 2429,2440 ----
  		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)
*** a/src/interfaces/libpq/libpq-int.h
--- b/src/interfaces/libpq/libpq-int.h
***************
*** 301,306 **** struct pg_conn
--- 301,309 ----
  	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

Reply via email to