mirror of
https://github.com/moparisthebest/curl
synced 2024-12-21 23:58:49 -05:00
create_conn: prune dead connections
Bringing back the old functionality that was mistakenly removed when the connection cache was remade. When creating a new connection, all the existing ones are checked and those that are known to be dead get disconnected for real and removed from the connection cache. It helps the cache from holding on to very many stale connections and aids in keeping down the number of system sockets in wait states. Help-by: Jonatan Vela <jonatan.vela@ergon.ch> Bug: http://curl.haxx.se/mail/lib-2014-06/0189.html
This commit is contained in:
parent
cb1f18661a
commit
01368d395c
@ -202,6 +202,7 @@ void Curl_conncache_foreach(struct conncache *connc,
|
|||||||
struct connectdata *conn;
|
struct connectdata *conn;
|
||||||
|
|
||||||
bundle = he->ptr;
|
bundle = he->ptr;
|
||||||
|
he = Curl_hash_next_element(&iter);
|
||||||
|
|
||||||
curr = bundle->conn_list->head;
|
curr = bundle->conn_list->head;
|
||||||
while(curr) {
|
while(curr) {
|
||||||
@ -213,8 +214,6 @@ void Curl_conncache_foreach(struct conncache *connc,
|
|||||||
if(1 == func(conn, param))
|
if(1 == func(conn, param))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
he = Curl_hash_next_element(&iter);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012, 2013, Linus Nielsen Feltzing, <linus@haxx.se>
|
* Copyright (C) 2012 - 2014, Linus Nielsen Feltzing, <linus@haxx.se>
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@ -26,6 +26,7 @@ struct conncache {
|
|||||||
struct curl_hash *hash;
|
struct curl_hash *hash;
|
||||||
size_t num_connections;
|
size_t num_connections;
|
||||||
long next_connection_id;
|
long next_connection_id;
|
||||||
|
struct timeval last_cleanup;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct conncache *Curl_conncache_init(int size);
|
struct conncache *Curl_conncache_init(int size);
|
||||||
|
90
lib/url.c
90
lib/url.c
@ -2912,6 +2912,69 @@ find_oldest_idle_connection_in_bundle(struct SessionHandle *data,
|
|||||||
return conn_candidate;
|
return conn_candidate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function checks if given connection is dead and disconnects if so.
|
||||||
|
* (That also removes it from the connection cache.)
|
||||||
|
*
|
||||||
|
* Returns TRUE if the connection actually was dead and disconnected.
|
||||||
|
*/
|
||||||
|
static bool disconnect_if_dead(struct connectdata *conn,
|
||||||
|
struct SessionHandle *data)
|
||||||
|
{
|
||||||
|
size_t pipeLen = conn->send_pipe->size + conn->recv_pipe->size;
|
||||||
|
if(!pipeLen && !conn->inuse) {
|
||||||
|
/* The check for a dead socket makes sense only if there are no
|
||||||
|
handles in pipeline and the connection isn't already marked in
|
||||||
|
use */
|
||||||
|
bool dead;
|
||||||
|
if(conn->handler->protocol & CURLPROTO_RTSP)
|
||||||
|
/* RTSP is a special case due to RTP interleaving */
|
||||||
|
dead = Curl_rtsp_connisdead(conn);
|
||||||
|
else
|
||||||
|
dead = SocketIsDead(conn->sock[FIRSTSOCKET]);
|
||||||
|
|
||||||
|
if(dead) {
|
||||||
|
conn->data = data;
|
||||||
|
infof(data, "Connection %ld seems to be dead!\n", conn->connection_id);
|
||||||
|
|
||||||
|
/* disconnect resources */
|
||||||
|
Curl_disconnect(conn, /* dead_connection */TRUE);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Wrapper to use disconnect_if_dead() function in Curl_conncache_foreach()
|
||||||
|
*
|
||||||
|
* Returns always 0.
|
||||||
|
*/
|
||||||
|
static int call_disconnect_if_dead(struct connectdata *conn,
|
||||||
|
void *param)
|
||||||
|
{
|
||||||
|
struct SessionHandle* data = (struct SessionHandle*)param;
|
||||||
|
disconnect_if_dead(conn, data);
|
||||||
|
return 0; /* continue iteration */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function scans the connection cache for half-open/dead connections,
|
||||||
|
* closes and removes them.
|
||||||
|
* The cleanup is done at most once per second.
|
||||||
|
*/
|
||||||
|
static void prune_dead_connections(struct SessionHandle *data)
|
||||||
|
{
|
||||||
|
struct timeval now = Curl_tvnow();
|
||||||
|
long elapsed = Curl_tvdiff(now, data->state.conn_cache->last_cleanup);
|
||||||
|
|
||||||
|
if(elapsed >= 1000L) {
|
||||||
|
Curl_conncache_foreach(data->state.conn_cache, data,
|
||||||
|
call_disconnect_if_dead);
|
||||||
|
data->state.conn_cache->last_cleanup = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Given one filled in connection struct (named needle), this function should
|
* Given one filled in connection struct (named needle), this function should
|
||||||
* detect if there already is one that has all the significant details
|
* detect if there already is one that has all the significant details
|
||||||
@ -2976,30 +3039,11 @@ ConnectionExists(struct SessionHandle *data,
|
|||||||
check = curr->ptr;
|
check = curr->ptr;
|
||||||
curr = curr->next;
|
curr = curr->next;
|
||||||
|
|
||||||
|
if(disconnect_if_dead(check, data))
|
||||||
|
continue;
|
||||||
|
|
||||||
pipeLen = check->send_pipe->size + check->recv_pipe->size;
|
pipeLen = check->send_pipe->size + check->recv_pipe->size;
|
||||||
|
|
||||||
if(!pipeLen && !check->inuse) {
|
|
||||||
/* The check for a dead socket makes sense only if there are no
|
|
||||||
handles in pipeline and the connection isn't already marked in
|
|
||||||
use */
|
|
||||||
bool dead;
|
|
||||||
if(check->handler->protocol & CURLPROTO_RTSP)
|
|
||||||
/* RTSP is a special case due to RTP interleaving */
|
|
||||||
dead = Curl_rtsp_connisdead(check);
|
|
||||||
else
|
|
||||||
dead = SocketIsDead(check->sock[FIRSTSOCKET]);
|
|
||||||
|
|
||||||
if(dead) {
|
|
||||||
check->data = data;
|
|
||||||
infof(data, "Connection %ld seems to be dead!\n",
|
|
||||||
check->connection_id);
|
|
||||||
|
|
||||||
/* disconnect resources */
|
|
||||||
Curl_disconnect(check, /* dead_connection */ TRUE);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(canPipeline) {
|
if(canPipeline) {
|
||||||
/* Make sure the pipe has only GET requests */
|
/* Make sure the pipe has only GET requests */
|
||||||
struct SessionHandle* sh = gethandleathead(check->send_pipe);
|
struct SessionHandle* sh = gethandleathead(check->send_pipe);
|
||||||
@ -5460,6 +5504,8 @@ static CURLcode create_conn(struct SessionHandle *data,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prune_dead_connections(data);
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
* Check the current list of connections to see if we can
|
* Check the current list of connections to see if we can
|
||||||
* re-use an already existing one or if we have to create a
|
* re-use an already existing one or if we have to create a
|
||||||
|
Loading…
Reference in New Issue
Block a user