connect_timeout parameter in libpq

From: Denis A Ustimenko <denis(at)oldham(dot)ru>
To: pgsql-patches(at)postgresql(dot)org
Subject: connect_timeout parameter in libpq
Date: 2002-08-13 02:54:11
Message-ID: 20020813025411.GA8313@denis.oldham.ru
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-patches

Hi there!

I need to change current connectDBComplete() behavior ( hang if backend are not responding). Here is the patch. Please apply.

*** fe-connect.c.orig Чт Авг 8 12:22:46 2002
--- fe-connect.c Пт Авг 9 14:57:18 2002
***************
*** 114,119 ****
--- 114,122 ----
{"password", "PGPASSWORD", DefaultPassword, NULL,
"Database-Password", "*", 20},

+ {"connect_timeout", "PGCONNECT_TIMEOUT", NULL, NULL,
+ "Connect-timeout", "", 10}, /* strlen( INT32_MAX) == 10 */
+
{"dbname", "PGDATABASE", NULL, NULL,
"Database-Name", "", 20},

***************
*** 307,312 ****
--- 310,317 ----
conn->pguser = tmp ? strdup(tmp) : NULL;
tmp = conninfo_getval(connOptions, "password");
conn->pgpass = tmp ? strdup(tmp) : NULL;
+ tmp = conninfo_getval(connOptions, "connect_timeout");
+ conn->connect_timeout = tmp ? strdup(tmp) : NULL;
#ifdef USE_SSL
tmp = conninfo_getval(connOptions, "requiressl");
conn->require_ssl = tmp ? (tmp[0] == '1' ? true : false) : false;
***************
*** 1050,1060 ****
{
PostgresPollingStatusType flag = PGRES_POLLING_WRITING;

if (conn == NULL || conn->status == CONNECTION_BAD)
return 0;

! for (;;)
{
/*
* Wait, if necessary. Note that the initial state (just after
* PQconnectStart) is to wait for the socket to select for
--- 1055,1086 ----
{
PostgresPollingStatusType flag = PGRES_POLLING_WRITING;

+ time_t finish_time, start_time;
+ struct timeval remains, *rp = NULL;
+
if (conn == NULL || conn->status == CONNECTION_BAD)
return 0;

! 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 (rp == NULL || remains.tv_sec > 0)
+ {
+ if ((time_t)-1 == (start_time = time(NULL)))
+ {
+ conn->status = CONNECTION_BAD;
+ return 0;
+ }
/*
* Wait, if necessary. Note that the initial state (just after
* PQconnectStart) is to wait for the socket to select for
***************
*** 1069,1075 ****
return 1; /* success! */

case PGRES_POLLING_READING:
! if (pqWait(1, 0, conn))
{
conn->status = CONNECTION_BAD;
return 0;
--- 1095,1101 ----
return 1; /* success! */

case PGRES_POLLING_READING:
! if (pqWaitTimed(1, 0, conn, rp))
{
conn->status = CONNECTION_BAD;
return 0;
***************
*** 1077,1083 ****
break;

case PGRES_POLLING_WRITING:
! if (pqWait(0, 1, conn))
{
conn->status = CONNECTION_BAD;
return 0;
--- 1103,1109 ----
break;

case PGRES_POLLING_WRITING:
! if (pqWaitTimed(0, 1, conn, rp))
{
conn->status = CONNECTION_BAD;
return 0;
***************
*** 1094,1100 ****
--- 1120,1135 ----
* Now try to advance the state machine.
*/
flag = PQconnectPoll(conn);
+
+ if ((time_t)-1 == (finish_time = time(NULL)))
+ {
+ conn->status = CONNECTION_BAD;
+ return 0;
+ }
+ remains.tv_sec -= finish_time - start_time;
}
+ conn->status = CONNECTION_BAD;
+ return 0;
}

/* ----------------
***************
*** 1929,1934 ****
--- 1964,1971 ----
free(conn->pguser);
if (conn->pgpass)
free(conn->pgpass);
+ if (conn->connect_timeout)
+ free(conn->connect_timeout);
/* Note that conn->Pfdebug is not ours to close or free */
if (conn->notifyList)
DLFreeList(conn->notifyList);
*** fe-misc.c.orig Чт Авг 8 16:33:34 2002
--- fe-misc.c Чт Авг 8 16:33:45 2002
***************
*** 748,753 ****
--- 748,759 ----
int
pqWait(int forRead, int forWrite, PGconn *conn)
{
+ return pqWaitTimed( forRead, forWrite, conn, (struct timeval *) NULL);
+ }
+
+ int
+ pqWaitTimed(int forRead, int forWrite, PGconn *conn, struct timeval *timeout)
+ {
fd_set input_mask;
fd_set output_mask;
fd_set except_mask;
***************
*** 770,777 ****
if (forWrite)
FD_SET(conn->sock, &output_mask);
FD_SET(conn->sock, &except_mask);
! if (select(conn->sock + 1, &input_mask, &output_mask, &except_mask,
! (struct timeval *) NULL) < 0)
{
if (SOCK_ERRNO == EINTR)
goto retry;
--- 776,783 ----
if (forWrite)
FD_SET(conn->sock, &output_mask);
FD_SET(conn->sock, &except_mask);
! if (select(conn->sock + 1, &input_mask, &output_mask,
! &except_mask, timeout) < 0)
{
if (SOCK_ERRNO == EINTR)
goto retry;
*** libpq-int.h.orig Чт Авг 8 16:37:56 2002
--- libpq-int.h Чт Авг 8 16:37:37 2002
***************
*** 279,284 ****
--- 279,286 ----
PQExpBufferData workBuffer; /* expansible string */

int client_encoding; /* encoding id */
+
+ char *connect_timeout;
};

/* String descriptions of the ExecStatusTypes.
***************
*** 324,329 ****
--- 326,332 ----
extern int pqReadData(PGconn *conn);
extern int pqFlush(PGconn *conn);
extern int pqWait(int forRead, int forWrite, PGconn *conn);
+ extern int pqWaitTimed(int forRead, int forWrite, PGconn *conn, struct timeval* timeout);
extern int pqReadReady(PGconn *conn);
extern int pqWriteReady(PGconn *conn);

--
Regards
Denis

Responses

Browse pgsql-patches by date

  From Date Subject
Next Message Tom Lane 2002-08-13 03:35:17 Re: connect_timeout parameter in libpq
Previous Message Tom Lane 2002-08-12 22:25:25 Re: Antw: Re: Patch for NetWare support