Centralize libpq's low-level code for dropping a connection.

Create an internal function pqDropConnection that does the physical socket
close and cleans up closely-associated state.  This removes a bunch of ad
hoc, not always consistent closure code.  The ulterior motive is to have a
single place to wait for a spawned child backend to exit, but this seems
like good cleanup even if that never happens.

I went back and forth on whether to include "conn->status = CONNECTION_BAD"
in pqDropConnection's actions, but for the moment decided not to.  Only a
minority of the call sites actually want that, and in any case it's
arguable that conn->status is slightly higher-level state, and thus not
part of this function's purview.
This commit is contained in:
Tom Lane 2012-09-07 16:02:23 -04:00
parent dda589c96b
commit 210eb9b743
4 changed files with 38 additions and 67 deletions

View File

@ -344,6 +344,28 @@ static void default_threadlock(int acquire);
pgthreadlock_t pg_g_threadlock = default_threadlock; pgthreadlock_t pg_g_threadlock = default_threadlock;
/*
* pqDropConnection
*
* Close any physical connection to the server, and reset associated
* state inside the connection object. We don't release state that
* would be needed to reconnect, though.
*/
void
pqDropConnection(PGconn *conn)
{
/* Drop any SSL state */
pqsecure_close(conn);
/* Close the socket itself */
if (conn->sock >= 0)
closesocket(conn->sock);
conn->sock = -1;
/* Discard any unread/unsent data */
conn->inStart = conn->inCursor = conn->inEnd = 0;
conn->outCount = 0;
}
/* /*
* Connecting to a Database * Connecting to a Database
* *
@ -1416,12 +1438,7 @@ connectDBStart(PGconn *conn)
return 1; return 1;
connect_errReturn: connect_errReturn:
if (conn->sock >= 0) pqDropConnection(conn);
{
pqsecure_close(conn);
closesocket(conn->sock);
conn->sock = -1;
}
conn->status = CONNECTION_BAD; conn->status = CONNECTION_BAD;
return 0; return 0;
} }
@ -1644,8 +1661,7 @@ keep_going: /* We will come back to here until there is
{ {
if (!connectNoDelay(conn)) if (!connectNoDelay(conn))
{ {
closesocket(conn->sock); pqDropConnection(conn);
conn->sock = -1;
conn->addr_cur = addr_cur->ai_next; conn->addr_cur = addr_cur->ai_next;
continue; continue;
} }
@ -1655,8 +1671,7 @@ keep_going: /* We will come back to here until there is
appendPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not set socket to non-blocking mode: %s\n"), libpq_gettext("could not set socket to non-blocking mode: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
closesocket(conn->sock); pqDropConnection(conn);
conn->sock = -1;
conn->addr_cur = addr_cur->ai_next; conn->addr_cur = addr_cur->ai_next;
continue; continue;
} }
@ -1667,8 +1682,7 @@ keep_going: /* We will come back to here until there is
appendPQExpBuffer(&conn->errorMessage, appendPQExpBuffer(&conn->errorMessage,
libpq_gettext("could not set socket to close-on-exec mode: %s\n"), libpq_gettext("could not set socket to close-on-exec mode: %s\n"),
SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));
closesocket(conn->sock); pqDropConnection(conn);
conn->sock = -1;
conn->addr_cur = addr_cur->ai_next; conn->addr_cur = addr_cur->ai_next;
continue; continue;
} }
@ -1715,8 +1729,7 @@ keep_going: /* We will come back to here until there is
if (err) if (err)
{ {
closesocket(conn->sock); pqDropConnection(conn);
conn->sock = -1;
conn->addr_cur = addr_cur->ai_next; conn->addr_cur = addr_cur->ai_next;
continue; continue;
} }
@ -1802,11 +1815,7 @@ keep_going: /* We will come back to here until there is
* failure and keep going if there are more addresses. * failure and keep going if there are more addresses.
*/ */
connectFailureMessage(conn, SOCK_ERRNO); connectFailureMessage(conn, SOCK_ERRNO);
if (conn->sock >= 0) pqDropConnection(conn);
{
closesocket(conn->sock);
conn->sock = -1;
}
/* /*
* Try the next address, if any. * Try the next address, if any.
@ -1851,6 +1860,7 @@ keep_going: /* We will come back to here until there is
* error message. * error message.
*/ */
connectFailureMessage(conn, optval); connectFailureMessage(conn, optval);
pqDropConnection(conn);
/* /*
* If more addresses remain, keep trying, just as in the * If more addresses remain, keep trying, just as in the
@ -1858,11 +1868,6 @@ keep_going: /* We will come back to here until there is
*/ */
if (conn->addr_cur->ai_next != NULL) if (conn->addr_cur->ai_next != NULL)
{ {
if (conn->sock >= 0)
{
closesocket(conn->sock);
conn->sock = -1;
}
conn->addr_cur = conn->addr_cur->ai_next; conn->addr_cur = conn->addr_cur->ai_next;
conn->status = CONNECTION_NEEDED; conn->status = CONNECTION_NEEDED;
goto keep_going; goto keep_going;
@ -2137,12 +2142,8 @@ keep_going: /* We will come back to here until there is
/* only retry once */ /* only retry once */
conn->allow_ssl_try = false; conn->allow_ssl_try = false;
/* Must drop the old connection */ /* Must drop the old connection */
closesocket(conn->sock); pqDropConnection(conn);
conn->sock = -1;
conn->status = CONNECTION_NEEDED; conn->status = CONNECTION_NEEDED;
/* Discard any unread/unsent data */
conn->inStart = conn->inCursor = conn->inEnd = 0;
conn->outCount = 0;
goto keep_going; goto keep_going;
} }
} }
@ -2252,13 +2253,8 @@ keep_going: /* We will come back to here until there is
{ {
conn->pversion = PG_PROTOCOL(2, 0); conn->pversion = PG_PROTOCOL(2, 0);
/* Must drop the old connection */ /* Must drop the old connection */
pqsecure_close(conn); pqDropConnection(conn);
closesocket(conn->sock);
conn->sock = -1;
conn->status = CONNECTION_NEEDED; conn->status = CONNECTION_NEEDED;
/* Discard any unread/unsent data */
conn->inStart = conn->inCursor = conn->inEnd = 0;
conn->outCount = 0;
goto keep_going; goto keep_going;
} }
@ -2323,12 +2319,8 @@ keep_going: /* We will come back to here until there is
/* only retry once */ /* only retry once */
conn->wait_ssl_try = false; conn->wait_ssl_try = false;
/* Must drop the old connection */ /* Must drop the old connection */
closesocket(conn->sock); pqDropConnection(conn);
conn->sock = -1;
conn->status = CONNECTION_NEEDED; conn->status = CONNECTION_NEEDED;
/* Discard any unread/unsent data */
conn->inStart = conn->inCursor = conn->inEnd = 0;
conn->outCount = 0;
goto keep_going; goto keep_going;
} }
@ -2343,13 +2335,8 @@ keep_going: /* We will come back to here until there is
/* only retry once */ /* only retry once */
conn->allow_ssl_try = false; conn->allow_ssl_try = false;
/* Must drop the old connection */ /* Must drop the old connection */
pqsecure_close(conn); pqDropConnection(conn);
closesocket(conn->sock);
conn->sock = -1;
conn->status = CONNECTION_NEEDED; conn->status = CONNECTION_NEEDED;
/* Discard any unread/unsent data */
conn->inStart = conn->inCursor = conn->inEnd = 0;
conn->outCount = 0;
goto keep_going; goto keep_going;
} }
#endif #endif
@ -2509,13 +2496,8 @@ keep_going: /* We will come back to here until there is
PQclear(res); PQclear(res);
conn->send_appname = false; conn->send_appname = false;
/* Must drop the old connection */ /* Must drop the old connection */
pqsecure_close(conn); pqDropConnection(conn);
closesocket(conn->sock);
conn->sock = -1;
conn->status = CONNECTION_NEEDED; conn->status = CONNECTION_NEEDED;
/* Discard any unread/unsent data */
conn->inStart = conn->inCursor = conn->inEnd = 0;
conn->outCount = 0;
goto keep_going; goto keep_going;
} }
} }
@ -2909,12 +2891,7 @@ closePGconn(PGconn *conn)
/* /*
* Close the connection, reset all transient state, flush I/O buffers. * Close the connection, reset all transient state, flush I/O buffers.
*/ */
if (conn->sock >= 0) pqDropConnection(conn);
{
pqsecure_close(conn);
closesocket(conn->sock);
}
conn->sock = -1;
conn->status = CONNECTION_BAD; /* Well, not really _bad_ - just conn->status = CONNECTION_BAD; /* Well, not really _bad_ - just
* absent */ * absent */
conn->asyncStatus = PGASYNC_IDLE; conn->asyncStatus = PGASYNC_IDLE;
@ -2943,8 +2920,6 @@ closePGconn(PGconn *conn)
if (conn->lobjfuncs) if (conn->lobjfuncs)
free(conn->lobjfuncs); free(conn->lobjfuncs);
conn->lobjfuncs = NULL; conn->lobjfuncs = NULL;
conn->inStart = conn->inCursor = conn->inEnd = 0;
conn->outCount = 0;
#ifdef ENABLE_GSS #ifdef ENABLE_GSS
{ {
OM_uint32 min_s; OM_uint32 min_s;

View File

@ -780,11 +780,8 @@ retry4:
* has been set already. * has been set already.
*/ */
definitelyFailed: definitelyFailed:
pqDropConnection(conn);
conn->status = CONNECTION_BAD; /* No more connection to backend */ conn->status = CONNECTION_BAD; /* No more connection to backend */
pqsecure_close(conn);
closesocket(conn->sock);
conn->sock = -1;
return -1; return -1;
} }

View File

@ -430,9 +430,7 @@ handleSyncLoss(PGconn *conn, char id, int msgLength)
pqSaveErrorResult(conn); pqSaveErrorResult(conn);
conn->asyncStatus = PGASYNC_READY; /* drop out of GetResult wait loop */ conn->asyncStatus = PGASYNC_READY; /* drop out of GetResult wait loop */
pqsecure_close(conn); pqDropConnection(conn);
closesocket(conn->sock);
conn->sock = -1;
conn->status = CONNECTION_BAD; /* No more connection to backend */ conn->status = CONNECTION_BAD; /* No more connection to backend */
} }

View File

@ -488,6 +488,7 @@ extern char *const pgresStatus[];
/* === in fe-connect.c === */ /* === in fe-connect.c === */
extern void pqDropConnection(PGconn *conn);
extern int pqPacketSend(PGconn *conn, char pack_type, extern int pqPacketSend(PGconn *conn, char pack_type,
const void *buf, size_t buf_len); const void *buf, size_t buf_len);
extern bool pqGetHomeDirectory(char *buf, int bufsize); extern bool pqGetHomeDirectory(char *buf, int bufsize);