diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml index c24a69f00cc..80e55f5f382 100644 --- a/doc/src/sgml/libpq.sgml +++ b/doc/src/sgml/libpq.sgml @@ -1110,10 +1110,11 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname connect_timeout - Maximum wait for connection, in seconds (write as a decimal integer - string). Zero or not specified means wait indefinitely. It is not - recommended to use a timeout of less than 2 seconds. - This timeout applies separately to each connection attempt. + Maximum wait for connection, in seconds (write as a decimal integer, + e.g. 10). Zero, negative, or not specified means + wait indefinitely. The minimum allowed timeout is 2 seconds, therefore + a value of 1 is interpreted as 2. + This timeout applies separately to each host name or IP address. For example, if you specify two hosts and connect_timeout is 5, each host will time out if no connection is made within 5 seconds, so the total time spent waiting for a connection might be diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 986f74ff006..9315a27561f 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -1905,6 +1905,8 @@ connectDBComplete(PGconn *conn) PostgresPollingStatusType flag = PGRES_POLLING_WRITING; time_t finish_time = ((time_t) -1); int timeout = 0; + int last_whichhost = -2; /* certainly different from whichhost */ + struct addrinfo *last_addr_cur = NULL; if (conn == NULL || conn->status == CONNECTION_BAD) return 0; @@ -1918,12 +1920,12 @@ connectDBComplete(PGconn *conn) if (timeout > 0) { /* - * Rounding could cause connection to fail; need at least 2 secs + * Rounding could cause connection to fail unexpectedly quickly; + * to prevent possibly waiting hardly-at-all, insist on at least + * two seconds. */ if (timeout < 2) timeout = 2; - /* calculate the finish time based on start + timeout */ - finish_time = time(NULL) + timeout; } } @@ -1931,6 +1933,21 @@ connectDBComplete(PGconn *conn) { int ret = 0; + /* + * (Re)start the connect_timeout timer if it's active and we are + * considering a different host than we were last time through. If + * we've already succeeded, though, needn't recalculate. + */ + if (flag != PGRES_POLLING_OK && + timeout > 0 && + (conn->whichhost != last_whichhost || + conn->addr_cur != last_addr_cur)) + { + finish_time = time(NULL) + timeout; + last_whichhost = conn->whichhost; + last_addr_cur = conn->addr_cur; + } + /* * Wait, if necessary. Note that the initial state (just after * PQconnectStart) is to wait for the socket to select for writing. @@ -1975,18 +1992,10 @@ connectDBComplete(PGconn *conn) if (ret == 1) /* connect_timeout elapsed */ { /* - * Attempt connection to the next host, ignoring any remaining - * addresses for the current host. + * Give up on current server/address, try the next one. */ - conn->try_next_addr = false; - conn->try_next_host = true; + conn->try_next_addr = true; conn->status = CONNECTION_NEEDED; - - /* - * Restart the connect_timeout timer for the new host. - */ - if (timeout > 0) - finish_time = time(NULL) + timeout; } /*