1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-27 12:41:57 +03:00

Add support TCP user timeout in libpq and the backend server

Similarly to the set of parameters for keepalive, a connection parameter
for libpq is added as well as a backend GUC, called tcp_user_timeout.

Increasing the TCP user timeout is useful to allow a connection to
survive extended periods without end-to-end connection, and decreasing
it allows application to fail faster.  By default, the parameter is 0,
which makes the connection use the system default, and follows a logic
close to the keepalive parameters in its handling.  When connecting
through a Unix-socket domain, the parameters have no effect.

Author: Ryohei Nagaura
Reviewed-by: Fabien Coelho, Robert Haas, Kyotaro Horiguchi, Kirk
Jamison, Mikalai Keida, Takayuki Tsunakawa, Andrei Yahorau
Discussion: https://postgr.es/m/EDA4195584F5064680D8130B1CA91C45367328@G01JPEXMBYT04
This commit is contained in:
Michael Paquier
2019-04-06 15:23:37 +09:00
parent 959d00e9db
commit 249d649996
11 changed files with 198 additions and 2 deletions

View File

@ -825,6 +825,7 @@ StreamConnection(pgsocket server_fd, Port *port)
(void) pq_setkeepalivesidle(tcp_keepalives_idle, port);
(void) pq_setkeepalivesinterval(tcp_keepalives_interval, port);
(void) pq_setkeepalivescount(tcp_keepalives_count, port);
(void) pq_settcpusertimeout(tcp_user_timeout, port);
}
return STATUS_OK;
@ -1926,3 +1927,75 @@ pq_setkeepalivescount(int count, Port *port)
return STATUS_OK;
}
int
pq_gettcpusertimeout(Port *port)
{
#ifdef TCP_USER_TIMEOUT
if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family))
return 0;
if (port->tcp_user_timeout != 0)
return port->tcp_user_timeout;
if (port->default_tcp_user_timeout == 0)
{
ACCEPT_TYPE_ARG3 size = sizeof(port->default_tcp_user_timeout);
if (getsockopt(port->sock, IPPROTO_TCP, TCP_USER_TIMEOUT,
(char *) &port->default_tcp_user_timeout,
&size) < 0)
{
elog(LOG, "getsockopt(%s) failed: %m", "TCP_USER_TIMEOUT");
port->default_tcp_user_timeout = -1; /* don't know */
}
}
return port->default_tcp_user_timeout;
#else
return 0;
#endif
}
int
pq_settcpusertimeout(int timeout, Port *port)
{
if (port == NULL || IS_AF_UNIX(port->laddr.addr.ss_family))
return STATUS_OK;
#ifdef TCP_USER_TIMEOUT
if (timeout == port->tcp_user_timeout)
return STATUS_OK;
if (port->default_tcp_user_timeout <= 0)
{
if (pq_gettcpusertimeout(port) < 0)
{
if (timeout == 0)
return STATUS_OK; /* default is set but unknown */
else
return STATUS_ERROR;
}
}
if (timeout == 0)
timeout = port->default_tcp_user_timeout;
if (setsockopt(port->sock, IPPROTO_TCP, TCP_USER_TIMEOUT,
(char *) &timeout, sizeof(timeout)) < 0)
{
elog(LOG, "setsockopt(%s) failed: %m", "TCP_USER_TIMEOUT");
return STATUS_ERROR;
}
port->tcp_user_timeout = timeout;
#else
if (timeout != 0)
{
elog(LOG, "setsockopt(%s) not supported", "TCP_USER_TIMEOUT");
return STATUS_ERROR;
}
#endif
return STATUS_OK;
}