mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-18 18:44:06 +08:00
Add libpq connection timeout parameter.
Denis A Ustimenko
This commit is contained in:
parent
b7214a877c
commit
f0ed4311b6
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.92 2002/08/15 03:00:59 momjian Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/libpq.sgml,v 1.93 2002/08/17 12:33:17 momjian Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<chapter id="libpq">
|
<chapter id="libpq">
|
||||||
@ -171,6 +171,15 @@ PGconn *PQconnectdb(const char *conninfo)
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><literal>connect_timeout</literal></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Time space in seconds given to connect routine. Zero or not set means infinite.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><literal>options</literal></term>
|
<term><literal>options</literal></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.191 2002/08/15 02:56:19 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.192 2002/08/17 12:33:17 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -110,6 +110,9 @@ static const PQconninfoOption PQconninfoOptions[] = {
|
|||||||
{"password", "PGPASSWORD", DefaultPassword, NULL,
|
{"password", "PGPASSWORD", DefaultPassword, NULL,
|
||||||
"Database-Password", "*", 20},
|
"Database-Password", "*", 20},
|
||||||
|
|
||||||
|
{"connect_timeout", "PGCONNECT_TIMEOUT", NULL, NULL,
|
||||||
|
"Connect-timeout", "", 10}, /* strlen( INT32_MAX) == 10 */
|
||||||
|
|
||||||
{"dbname", "PGDATABASE", NULL, NULL,
|
{"dbname", "PGDATABASE", NULL, NULL,
|
||||||
"Database-Name", "", 20},
|
"Database-Name", "", 20},
|
||||||
|
|
||||||
@ -302,6 +305,8 @@ PQconnectStart(const char *conninfo)
|
|||||||
conn->pguser = tmp ? strdup(tmp) : NULL;
|
conn->pguser = tmp ? strdup(tmp) : NULL;
|
||||||
tmp = conninfo_getval(connOptions, "password");
|
tmp = conninfo_getval(connOptions, "password");
|
||||||
conn->pgpass = tmp ? strdup(tmp) : NULL;
|
conn->pgpass = tmp ? strdup(tmp) : NULL;
|
||||||
|
tmp = conninfo_getval(connOptions, "connect_timeout");
|
||||||
|
conn->connect_timeout = tmp ? strdup(tmp) : NULL;
|
||||||
#ifdef USE_SSL
|
#ifdef USE_SSL
|
||||||
tmp = conninfo_getval(connOptions, "requiressl");
|
tmp = conninfo_getval(connOptions, "requiressl");
|
||||||
if (tmp && tmp[0] == '1')
|
if (tmp && tmp[0] == '1')
|
||||||
@ -1052,11 +1057,38 @@ connectDBComplete(PGconn *conn)
|
|||||||
{
|
{
|
||||||
PostgresPollingStatusType flag = PGRES_POLLING_WRITING;
|
PostgresPollingStatusType flag = PGRES_POLLING_WRITING;
|
||||||
|
|
||||||
|
struct timeval remains, *rp = NULL, finish_time, start_time;
|
||||||
|
|
||||||
if (conn == NULL || conn->status == CONNECTION_BAD)
|
if (conn == NULL || conn->status == CONNECTION_BAD)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for (;;)
|
/*
|
||||||
|
* Prepare to time calculations, if connect_timeout isn't zero.
|
||||||
|
*/
|
||||||
|
if (conn->connect_timeout != NULL)
|
||||||
{
|
{
|
||||||
|
remains.tv_sec = atoi(conn->connect_timeout);
|
||||||
|
if (!remains.tv_sec)
|
||||||
|
{
|
||||||
|
conn->status = CONNECTION_BAD;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
remains.tv_usec = 0;
|
||||||
|
rp = &remains;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
while (NULL == rp || remains.tv_sec > 0 || remains.tv_sec == 0 && remains.tv_usec > 0)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* If connecting timeout is set, get current time.
|
||||||
|
*/
|
||||||
|
if ( NULL != rp && -1 == gettimeofday(&start_time, NULL))
|
||||||
|
{
|
||||||
|
conn->status = CONNECTION_BAD;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wait, if necessary. Note that the initial state (just after
|
* Wait, if necessary. Note that the initial state (just after
|
||||||
* PQconnectStart) is to wait for the socket to select for
|
* PQconnectStart) is to wait for the socket to select for
|
||||||
@ -1071,7 +1103,7 @@ connectDBComplete(PGconn *conn)
|
|||||||
return 1; /* success! */
|
return 1; /* success! */
|
||||||
|
|
||||||
case PGRES_POLLING_READING:
|
case PGRES_POLLING_READING:
|
||||||
if (pqWait(1, 0, conn))
|
if (pqWaitTimed(1, 0, conn, rp))
|
||||||
{
|
{
|
||||||
conn->status = CONNECTION_BAD;
|
conn->status = CONNECTION_BAD;
|
||||||
return 0;
|
return 0;
|
||||||
@ -1079,7 +1111,7 @@ connectDBComplete(PGconn *conn)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case PGRES_POLLING_WRITING:
|
case PGRES_POLLING_WRITING:
|
||||||
if (pqWait(0, 1, conn))
|
if (pqWaitTimed(0, 1, conn, rp))
|
||||||
{
|
{
|
||||||
conn->status = CONNECTION_BAD;
|
conn->status = CONNECTION_BAD;
|
||||||
return 0;
|
return 0;
|
||||||
@ -1096,7 +1128,31 @@ connectDBComplete(PGconn *conn)
|
|||||||
* Now try to advance the state machine.
|
* Now try to advance the state machine.
|
||||||
*/
|
*/
|
||||||
flag = PQconnectPoll(conn);
|
flag = PQconnectPoll(conn);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If connecting timeout is set, calculate remain time.
|
||||||
|
*/
|
||||||
|
if (NULL != rp) {
|
||||||
|
if (-1 == gettimeofday(&finish_time, NULL))
|
||||||
|
{
|
||||||
|
conn->status = CONNECTION_BAD;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (0 > (finish_time.tv_usec -= start_time.tv_usec))
|
||||||
|
{
|
||||||
|
remains.tv_sec++;
|
||||||
|
finish_time.tv_usec += 1000000;
|
||||||
|
}
|
||||||
|
if (0 > (remains.tv_usec -= finish_time.tv_usec))
|
||||||
|
{
|
||||||
|
remains.tv_sec--;
|
||||||
|
remains.tv_usec += 1000000;
|
||||||
|
}
|
||||||
|
remains.tv_sec -= finish_time.tv_sec - start_time.tv_sec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
conn->status = CONNECTION_BAD;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
@ -1928,6 +1984,8 @@ freePGconn(PGconn *conn)
|
|||||||
free(conn->pguser);
|
free(conn->pguser);
|
||||||
if (conn->pgpass)
|
if (conn->pgpass)
|
||||||
free(conn->pgpass);
|
free(conn->pgpass);
|
||||||
|
if (conn->connect_timeout)
|
||||||
|
free(conn->connect_timeout);
|
||||||
/* Note that conn->Pfdebug is not ours to close or free */
|
/* Note that conn->Pfdebug is not ours to close or free */
|
||||||
if (conn->notifyList)
|
if (conn->notifyList)
|
||||||
DLFreeList(conn->notifyList);
|
DLFreeList(conn->notifyList);
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.76 2002/06/20 20:29:54 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-misc.c,v 1.77 2002/08/17 12:33:18 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -775,11 +775,20 @@ pqFlush(PGconn *conn)
|
|||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
pqWait(int forRead, int forWrite, PGconn *conn)
|
pqWait(int forRead, int forWrite, PGconn *conn)
|
||||||
|
{
|
||||||
|
return pqWaitTimed( forRead, forWrite, conn, (const struct timeval *) NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
pqWaitTimed(int forRead, int forWrite, PGconn *conn, const struct timeval *timeout)
|
||||||
{
|
{
|
||||||
fd_set input_mask;
|
fd_set input_mask;
|
||||||
fd_set output_mask;
|
fd_set output_mask;
|
||||||
fd_set except_mask;
|
fd_set except_mask;
|
||||||
|
|
||||||
|
struct timeval tmp_timeout;
|
||||||
|
struct timeval *ptmp_timeout = NULL;
|
||||||
|
|
||||||
if (conn->sock < 0)
|
if (conn->sock < 0)
|
||||||
{
|
{
|
||||||
printfPQExpBuffer(&conn->errorMessage,
|
printfPQExpBuffer(&conn->errorMessage,
|
||||||
@ -807,8 +816,17 @@ retry5:
|
|||||||
if (forWrite)
|
if (forWrite)
|
||||||
FD_SET(conn->sock, &output_mask);
|
FD_SET(conn->sock, &output_mask);
|
||||||
FD_SET(conn->sock, &except_mask);
|
FD_SET(conn->sock, &except_mask);
|
||||||
if (select(conn->sock + 1, &input_mask, &output_mask, &except_mask,
|
|
||||||
(struct timeval *) NULL) < 0)
|
if (NULL != timeout)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* select may modify timeout argument on some platforms use copy
|
||||||
|
*/
|
||||||
|
tmp_timeout = *timeout;
|
||||||
|
ptmp_timeout = &tmp_timeout;
|
||||||
|
}
|
||||||
|
if (select(conn->sock + 1, &input_mask, &output_mask,
|
||||||
|
&except_mask, ptmp_timeout) < 0)
|
||||||
{
|
{
|
||||||
if (SOCK_ERRNO == EINTR)
|
if (SOCK_ERRNO == EINTR)
|
||||||
goto retry5;
|
goto retry5;
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: libpq-int.h,v 1.52 2002/07/20 05:43:31 momjian Exp $
|
* $Id: libpq-int.h,v 1.53 2002/08/17 12:33:18 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -286,6 +286,8 @@ struct pg_conn
|
|||||||
PQExpBufferData workBuffer; /* expansible string */
|
PQExpBufferData workBuffer; /* expansible string */
|
||||||
|
|
||||||
int client_encoding; /* encoding id */
|
int client_encoding; /* encoding id */
|
||||||
|
|
||||||
|
char *connect_timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* String descriptions of the ExecStatusTypes.
|
/* String descriptions of the ExecStatusTypes.
|
||||||
@ -332,6 +334,7 @@ extern int pqReadData(PGconn *conn);
|
|||||||
extern int pqFlush(PGconn *conn);
|
extern int pqFlush(PGconn *conn);
|
||||||
extern int pqSendSome(PGconn *conn);
|
extern int pqSendSome(PGconn *conn);
|
||||||
extern int pqWait(int forRead, int forWrite, PGconn *conn);
|
extern int pqWait(int forRead, int forWrite, PGconn *conn);
|
||||||
|
extern int pqWaitTimed(int forRead, int forWrite, PGconn *conn, const struct timeval* timeout);
|
||||||
extern int pqReadReady(PGconn *conn);
|
extern int pqReadReady(PGconn *conn);
|
||||||
extern int pqWriteReady(PGconn *conn);
|
extern int pqWriteReady(PGconn *conn);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user