mirror of
https://github.com/moparisthebest/curl
synced 2024-12-21 15:48:49 -05:00
share: add support for sharing the connection cache
This commit is contained in:
parent
e871ab56ed
commit
67c55a26d5
68
debug/shared-conn.c
Normal file
68
debug/shared-conn.c
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
|
*
|
||||||
|
* This software is licensed as described in the file COPYING, which
|
||||||
|
* you should have received as part of this distribution. The terms
|
||||||
|
* are also available at https://curl.haxx.se/docs/copyright.html.
|
||||||
|
*
|
||||||
|
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||||
|
* copies of the Software, and permit persons to whom the Software is
|
||||||
|
* furnished to do so, under the terms of the COPYING file.
|
||||||
|
*
|
||||||
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||||
|
* KIND, either express or implied.
|
||||||
|
*
|
||||||
|
***************************************************************************/
|
||||||
|
/* <DESC>
|
||||||
|
* Two HTTP GET using connection sharing with the share inteface
|
||||||
|
* </DESC>
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
CURL *curl;
|
||||||
|
CURLcode res;
|
||||||
|
CURLSH *share;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
share = curl_share_init();
|
||||||
|
curl_share_setopt(share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
|
||||||
|
|
||||||
|
/* Loop the transfer and cleanup the handle properly every lap. This will
|
||||||
|
still reuse connections since the pool is in the shared object! */
|
||||||
|
|
||||||
|
for(i = 0; i < 3; i++) {
|
||||||
|
curl = curl_easy_init();
|
||||||
|
if(curl) {
|
||||||
|
curl_easy_setopt(curl, CURLOPT_URL, "http://example.com");
|
||||||
|
/* example.com is redirected, so we tell libcurl to follow redirection */
|
||||||
|
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
|
|
||||||
|
/* use the connection pool in the share object */
|
||||||
|
curl_easy_setopt(curl, CURLOPT_SHARE, share);
|
||||||
|
|
||||||
|
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
|
||||||
|
|
||||||
|
/* Perform the request, res will get the return code */
|
||||||
|
res = curl_easy_perform(curl);
|
||||||
|
/* Check for errors */
|
||||||
|
if(res != CURLE_OK)
|
||||||
|
fprintf(stderr, "curl_easy_perform() failed: %s\n",
|
||||||
|
curl_easy_strerror(res));
|
||||||
|
|
||||||
|
/* always cleanup */
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
curl_share_cleanup(share);
|
||||||
|
return 0;
|
||||||
|
}
|
139
lib/conncache.c
139
lib/conncache.c
@ -31,11 +31,21 @@
|
|||||||
#include "multiif.h"
|
#include "multiif.h"
|
||||||
#include "sendf.h"
|
#include "sendf.h"
|
||||||
#include "conncache.h"
|
#include "conncache.h"
|
||||||
|
#include "share.h"
|
||||||
|
#include "sigpipe.h"
|
||||||
|
#include "connect.h"
|
||||||
|
|
||||||
/* The last 3 #include files should be in this order */
|
/* The last 3 #include files should be in this order */
|
||||||
#include "curl_printf.h"
|
#include "curl_printf.h"
|
||||||
#include "curl_memory.h"
|
#include "curl_memory.h"
|
||||||
#include "memdebug.h"
|
#include "memdebug.h"
|
||||||
|
|
||||||
|
#define CONN_LOCK(x) if((x)->share) \
|
||||||
|
Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE)
|
||||||
|
#define CONN_UNLOCK(x) if((x)->share) \
|
||||||
|
Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT)
|
||||||
|
|
||||||
|
|
||||||
static void conn_llist_dtor(void *user, void *element)
|
static void conn_llist_dtor(void *user, void *element)
|
||||||
{
|
{
|
||||||
struct connectdata *data = element;
|
struct connectdata *data = element;
|
||||||
@ -109,8 +119,23 @@ static void free_bundle_hash_entry(void *freethis)
|
|||||||
|
|
||||||
int Curl_conncache_init(struct conncache *connc, int size)
|
int Curl_conncache_init(struct conncache *connc, int size)
|
||||||
{
|
{
|
||||||
return Curl_hash_init(&connc->hash, size, Curl_hash_str,
|
int rc;
|
||||||
|
|
||||||
|
/* allocate a new easy handle to use when closing cached connections */
|
||||||
|
connc->closure_handle = curl_easy_init();
|
||||||
|
if(!connc->closure_handle)
|
||||||
|
return 1; /* bad */
|
||||||
|
|
||||||
|
rc = Curl_hash_init(&connc->hash, size, Curl_hash_str,
|
||||||
Curl_str_key_compare, free_bundle_hash_entry);
|
Curl_str_key_compare, free_bundle_hash_entry);
|
||||||
|
if(rc) {
|
||||||
|
Curl_close(connc->closure_handle);
|
||||||
|
connc->closure_handle = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
connc->closure_handle->state.conn_cache = connc;
|
||||||
|
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Curl_conncache_destroy(struct conncache *connc)
|
void Curl_conncache_destroy(struct conncache *connc)
|
||||||
@ -149,7 +174,9 @@ struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn,
|
|||||||
if(connc) {
|
if(connc) {
|
||||||
char key[128];
|
char key[128];
|
||||||
hashkey(conn, key, sizeof(key));
|
hashkey(conn, key, sizeof(key));
|
||||||
|
CONN_LOCK(conn->data);
|
||||||
bundle = Curl_hash_pick(&connc->hash, key, strlen(key));
|
bundle = Curl_hash_pick(&connc->hash, key, strlen(key));
|
||||||
|
CONN_UNLOCK(conn->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bundle;
|
return bundle;
|
||||||
@ -206,7 +233,9 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
|
|||||||
return result;
|
return result;
|
||||||
|
|
||||||
hashkey(conn, key, sizeof(key));
|
hashkey(conn, key, sizeof(key));
|
||||||
|
CONN_LOCK(data);
|
||||||
rc = conncache_add_bundle(data->state.conn_cache, key, new_bundle);
|
rc = conncache_add_bundle(data->state.conn_cache, key, new_bundle);
|
||||||
|
CONN_UNLOCK(data);
|
||||||
|
|
||||||
if(!rc) {
|
if(!rc) {
|
||||||
bundle_destroy(new_bundle);
|
bundle_destroy(new_bundle);
|
||||||
@ -215,12 +244,15 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
|
|||||||
bundle = new_bundle;
|
bundle = new_bundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CONN_LOCK(data);
|
||||||
result = bundle_add_conn(bundle, conn);
|
result = bundle_add_conn(bundle, conn);
|
||||||
if(result) {
|
if(result) {
|
||||||
if(new_bundle)
|
if(new_bundle)
|
||||||
conncache_remove_bundle(data->state.conn_cache, new_bundle);
|
conncache_remove_bundle(data->state.conn_cache, new_bundle);
|
||||||
|
CONN_UNLOCK(data);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
CONN_UNLOCK(data);
|
||||||
|
|
||||||
conn->connection_id = connc->next_connection_id++;
|
conn->connection_id = connc->next_connection_id++;
|
||||||
connc->num_connections++;
|
connc->num_connections++;
|
||||||
@ -240,11 +272,11 @@ void Curl_conncache_remove_conn(struct conncache *connc,
|
|||||||
/* The bundle pointer can be NULL, since this function can be called
|
/* The bundle pointer can be NULL, since this function can be called
|
||||||
due to a failed connection attempt, before being added to a bundle */
|
due to a failed connection attempt, before being added to a bundle */
|
||||||
if(bundle) {
|
if(bundle) {
|
||||||
|
CONN_LOCK(conn->data);
|
||||||
bundle_remove_conn(bundle, conn);
|
bundle_remove_conn(bundle, conn);
|
||||||
if(bundle->num_connections == 0) {
|
if(bundle->num_connections == 0)
|
||||||
conncache_remove_bundle(connc, bundle);
|
conncache_remove_bundle(connc, bundle);
|
||||||
}
|
CONN_UNLOCK(conn->data);
|
||||||
|
|
||||||
if(connc) {
|
if(connc) {
|
||||||
connc->num_connections--;
|
connc->num_connections--;
|
||||||
|
|
||||||
@ -261,7 +293,8 @@ void Curl_conncache_remove_conn(struct conncache *connc,
|
|||||||
|
|
||||||
Return 0 from func() to continue the loop, return 1 to abort it.
|
Return 0 from func() to continue the loop, return 1 to abort it.
|
||||||
*/
|
*/
|
||||||
void Curl_conncache_foreach(struct conncache *connc,
|
void Curl_conncache_foreach(struct Curl_easy *data,
|
||||||
|
struct conncache *connc,
|
||||||
void *param,
|
void *param,
|
||||||
int (*func)(struct connectdata *conn, void *param))
|
int (*func)(struct connectdata *conn, void *param))
|
||||||
{
|
{
|
||||||
@ -272,6 +305,7 @@ void Curl_conncache_foreach(struct conncache *connc,
|
|||||||
if(!connc)
|
if(!connc)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
CONN_LOCK(data);
|
||||||
Curl_hash_start_iterate(&connc->hash, &iter);
|
Curl_hash_start_iterate(&connc->hash, &iter);
|
||||||
|
|
||||||
he = Curl_hash_next_element(&iter);
|
he = Curl_hash_next_element(&iter);
|
||||||
@ -288,14 +322,21 @@ void Curl_conncache_foreach(struct conncache *connc,
|
|||||||
struct connectdata *conn = curr->ptr;
|
struct connectdata *conn = curr->ptr;
|
||||||
curr = curr->next;
|
curr = curr->next;
|
||||||
|
|
||||||
if(1 == func(conn, param))
|
if(1 == func(conn, param)) {
|
||||||
|
CONN_UNLOCK(data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
CONN_UNLOCK(data);
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the first connection found in the cache. Used when closing all
|
/* Return the first connection found in the cache. Used when closing all
|
||||||
connections */
|
connections.
|
||||||
|
|
||||||
|
NOTE: no locking is done here as this is presumably only done when cleaning
|
||||||
|
up a cache!
|
||||||
|
*/
|
||||||
struct connectdata *
|
struct connectdata *
|
||||||
Curl_conncache_find_first_connection(struct conncache *connc)
|
Curl_conncache_find_first_connection(struct conncache *connc)
|
||||||
{
|
{
|
||||||
@ -321,6 +362,90 @@ Curl_conncache_find_first_connection(struct conncache *connc)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function finds the connection in the connection
|
||||||
|
* cache that has been unused for the longest time.
|
||||||
|
*
|
||||||
|
* Returns the pointer to the oldest idle connection, or NULL if none was
|
||||||
|
* found.
|
||||||
|
*/
|
||||||
|
struct connectdata *
|
||||||
|
Curl_conncache_oldest_idle(struct Curl_easy *data)
|
||||||
|
{
|
||||||
|
struct conncache *bc = data->state.conn_cache;
|
||||||
|
struct curl_hash_iterator iter;
|
||||||
|
struct curl_llist_element *curr;
|
||||||
|
struct curl_hash_element *he;
|
||||||
|
timediff_t highscore =- 1;
|
||||||
|
timediff_t score;
|
||||||
|
struct curltime now;
|
||||||
|
struct connectdata *conn_candidate = NULL;
|
||||||
|
struct connectbundle *bundle;
|
||||||
|
|
||||||
|
now = Curl_now();
|
||||||
|
|
||||||
|
CONN_LOCK(data);
|
||||||
|
Curl_hash_start_iterate(&bc->hash, &iter);
|
||||||
|
|
||||||
|
he = Curl_hash_next_element(&iter);
|
||||||
|
while(he) {
|
||||||
|
struct connectdata *conn;
|
||||||
|
|
||||||
|
bundle = he->ptr;
|
||||||
|
|
||||||
|
curr = bundle->conn_list.head;
|
||||||
|
while(curr) {
|
||||||
|
conn = curr->ptr;
|
||||||
|
|
||||||
|
if(!conn->inuse) {
|
||||||
|
/* Set higher score for the age passed since the connection was used */
|
||||||
|
score = Curl_timediff(now, conn->now);
|
||||||
|
|
||||||
|
if(score > highscore) {
|
||||||
|
highscore = score;
|
||||||
|
conn_candidate = conn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
curr = curr->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
he = Curl_hash_next_element(&iter);
|
||||||
|
}
|
||||||
|
CONN_UNLOCK(data);
|
||||||
|
|
||||||
|
return conn_candidate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Curl_conncache_close_all_connections(struct conncache *connc)
|
||||||
|
{
|
||||||
|
struct connectdata *conn;
|
||||||
|
|
||||||
|
conn = Curl_conncache_find_first_connection(connc);
|
||||||
|
while(conn) {
|
||||||
|
SIGPIPE_VARIABLE(pipe_st);
|
||||||
|
conn->data = connc->closure_handle;
|
||||||
|
|
||||||
|
sigpipe_ignore(conn->data, &pipe_st);
|
||||||
|
conn->data->easy_conn = NULL; /* clear the easy handle's connection
|
||||||
|
pointer */
|
||||||
|
/* This will remove the connection from the cache */
|
||||||
|
connclose(conn, "kill all");
|
||||||
|
(void)Curl_disconnect(conn, FALSE);
|
||||||
|
sigpipe_restore(&pipe_st);
|
||||||
|
|
||||||
|
conn = Curl_conncache_find_first_connection(connc);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(connc->closure_handle) {
|
||||||
|
SIGPIPE_VARIABLE(pipe_st);
|
||||||
|
sigpipe_ignore(connc->closure_handle, &pipe_st);
|
||||||
|
|
||||||
|
Curl_hostcache_clean(connc->closure_handle,
|
||||||
|
connc->closure_handle->dns.hostcache);
|
||||||
|
Curl_close(connc->closure_handle);
|
||||||
|
sigpipe_restore(&pipe_st);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
/* Useful for debugging the connection cache */
|
/* Useful for debugging the connection cache */
|
||||||
|
@ -28,6 +28,8 @@ struct conncache {
|
|||||||
size_t num_connections;
|
size_t num_connections;
|
||||||
long next_connection_id;
|
long next_connection_id;
|
||||||
struct curltime last_cleanup;
|
struct curltime last_cleanup;
|
||||||
|
/* handle used for closing cached connections */
|
||||||
|
struct Curl_easy *closure_handle;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define BUNDLE_NO_MULTIUSE -1
|
#define BUNDLE_NO_MULTIUSE -1
|
||||||
@ -41,8 +43,8 @@ struct connectbundle {
|
|||||||
struct curl_llist conn_list; /* The connectdata members of the bundle */
|
struct curl_llist conn_list; /* The connectdata members of the bundle */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* returns 1 on error, 0 is fine */
|
||||||
int Curl_conncache_init(struct conncache *, int size);
|
int Curl_conncache_init(struct conncache *, int size);
|
||||||
|
|
||||||
void Curl_conncache_destroy(struct conncache *connc);
|
void Curl_conncache_destroy(struct conncache *connc);
|
||||||
|
|
||||||
/* return the correct bundle, to a host or a proxy */
|
/* return the correct bundle, to a host or a proxy */
|
||||||
@ -55,7 +57,8 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
|
|||||||
void Curl_conncache_remove_conn(struct conncache *connc,
|
void Curl_conncache_remove_conn(struct conncache *connc,
|
||||||
struct connectdata *conn);
|
struct connectdata *conn);
|
||||||
|
|
||||||
void Curl_conncache_foreach(struct conncache *connc,
|
void Curl_conncache_foreach(struct Curl_easy *data,
|
||||||
|
struct conncache *connc,
|
||||||
void *param,
|
void *param,
|
||||||
int (*func)(struct connectdata *conn,
|
int (*func)(struct connectdata *conn,
|
||||||
void *param));
|
void *param));
|
||||||
@ -63,6 +66,9 @@ void Curl_conncache_foreach(struct conncache *connc,
|
|||||||
struct connectdata *
|
struct connectdata *
|
||||||
Curl_conncache_find_first_connection(struct conncache *connc);
|
Curl_conncache_find_first_connection(struct conncache *connc);
|
||||||
|
|
||||||
|
struct connectdata *
|
||||||
|
Curl_conncache_oldest_idle(struct Curl_easy *data);
|
||||||
|
void Curl_conncache_close_all_connections(struct conncache *connc);
|
||||||
void Curl_conncache_print(struct conncache *connc);
|
void Curl_conncache_print(struct conncache *connc);
|
||||||
|
|
||||||
#endif /* HEADER_CURL_CONNCACHE_H */
|
#endif /* HEADER_CURL_CONNCACHE_H */
|
||||||
|
@ -1224,7 +1224,7 @@ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
|
|||||||
find.tofind = data->state.lastconnect;
|
find.tofind = data->state.lastconnect;
|
||||||
find.found = FALSE;
|
find.found = FALSE;
|
||||||
|
|
||||||
Curl_conncache_foreach(data->multi_easy?
|
Curl_conncache_foreach(data, data->multi_easy?
|
||||||
&data->multi_easy->conn_cache:
|
&data->multi_easy->conn_cache:
|
||||||
&data->multi->conn_cache, &find, conn_is_conn);
|
&data->multi->conn_cache, &find, conn_is_conn);
|
||||||
|
|
||||||
|
60
lib/multi.c
60
lib/multi.c
@ -326,14 +326,6 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
|
|||||||
Curl_llist_init(&multi->msglist, multi_freeamsg);
|
Curl_llist_init(&multi->msglist, multi_freeamsg);
|
||||||
Curl_llist_init(&multi->pending, multi_freeamsg);
|
Curl_llist_init(&multi->pending, multi_freeamsg);
|
||||||
|
|
||||||
/* allocate a new easy handle to use when closing cached connections */
|
|
||||||
multi->closure_handle = curl_easy_init();
|
|
||||||
if(!multi->closure_handle)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
multi->closure_handle->multi = multi;
|
|
||||||
multi->closure_handle->state.conn_cache = &multi->conn_cache;
|
|
||||||
|
|
||||||
multi->max_pipeline_length = 5;
|
multi->max_pipeline_length = 5;
|
||||||
|
|
||||||
/* -1 means it not set by user, use the default value */
|
/* -1 means it not set by user, use the default value */
|
||||||
@ -345,8 +337,6 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
|
|||||||
Curl_hash_destroy(&multi->sockhash);
|
Curl_hash_destroy(&multi->sockhash);
|
||||||
Curl_hash_destroy(&multi->hostcache);
|
Curl_hash_destroy(&multi->hostcache);
|
||||||
Curl_conncache_destroy(&multi->conn_cache);
|
Curl_conncache_destroy(&multi->conn_cache);
|
||||||
Curl_close(multi->closure_handle);
|
|
||||||
multi->closure_handle = NULL;
|
|
||||||
Curl_llist_destroy(&multi->msglist, NULL);
|
Curl_llist_destroy(&multi->msglist, NULL);
|
||||||
Curl_llist_destroy(&multi->pending, NULL);
|
Curl_llist_destroy(&multi->pending, NULL);
|
||||||
|
|
||||||
@ -407,7 +397,10 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
|
|||||||
data->dns.hostcachetype = HCACHE_MULTI;
|
data->dns.hostcachetype = HCACHE_MULTI;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Point to the multi's connection cache */
|
/* Point to the shared or multi handle connection cache */
|
||||||
|
if(data->share && (data->share->specifier & (1<< CURL_LOCK_DATA_CONNECT)))
|
||||||
|
data->state.conn_cache = &data->share->conn_cache;
|
||||||
|
else
|
||||||
data->state.conn_cache = &multi->conn_cache;
|
data->state.conn_cache = &multi->conn_cache;
|
||||||
|
|
||||||
/* This adds the new entry at the 'end' of the doubly-linked circular
|
/* This adds the new entry at the 'end' of the doubly-linked circular
|
||||||
@ -462,8 +455,8 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
|
|||||||
state somewhat we clone the timeouts from each added handle so that the
|
state somewhat we clone the timeouts from each added handle so that the
|
||||||
closure handle always has the same timeouts as the most recently added
|
closure handle always has the same timeouts as the most recently added
|
||||||
easy handle. */
|
easy handle. */
|
||||||
multi->closure_handle->set.timeout = data->set.timeout;
|
data->state.conn_cache->closure_handle->set.timeout = data->set.timeout;
|
||||||
multi->closure_handle->set.server_response_timeout =
|
data->state.conn_cache->closure_handle->set.server_response_timeout =
|
||||||
data->set.server_response_timeout;
|
data->set.server_response_timeout;
|
||||||
|
|
||||||
update_timer(multi);
|
update_timer(multi);
|
||||||
@ -504,7 +497,7 @@ ConnectionDone(struct Curl_easy *data, struct connectdata *conn)
|
|||||||
data->state.conn_cache->num_connections > maxconnects) {
|
data->state.conn_cache->num_connections > maxconnects) {
|
||||||
infof(data, "Connection cache is full, closing the oldest one.\n");
|
infof(data, "Connection cache is full, closing the oldest one.\n");
|
||||||
|
|
||||||
conn_candidate = Curl_oldest_idle_connection(data);
|
conn_candidate = Curl_conncache_oldest_idle(data);
|
||||||
|
|
||||||
if(conn_candidate) {
|
if(conn_candidate) {
|
||||||
/* Set the connection's owner correctly */
|
/* Set the connection's owner correctly */
|
||||||
@ -2201,36 +2194,12 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
|
|||||||
return returncode;
|
return returncode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void close_all_connections(struct Curl_multi *multi)
|
|
||||||
{
|
|
||||||
struct connectdata *conn;
|
|
||||||
|
|
||||||
conn = Curl_conncache_find_first_connection(&multi->conn_cache);
|
|
||||||
while(conn) {
|
|
||||||
SIGPIPE_VARIABLE(pipe_st);
|
|
||||||
conn->data = multi->closure_handle;
|
|
||||||
|
|
||||||
sigpipe_ignore(conn->data, &pipe_st);
|
|
||||||
conn->data->easy_conn = NULL; /* clear the easy handle's connection
|
|
||||||
pointer */
|
|
||||||
/* This will remove the connection from the cache */
|
|
||||||
connclose(conn, "kill all");
|
|
||||||
(void)Curl_disconnect(conn, FALSE);
|
|
||||||
sigpipe_restore(&pipe_st);
|
|
||||||
|
|
||||||
conn = Curl_conncache_find_first_connection(&multi->conn_cache);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
|
CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
|
||||||
{
|
{
|
||||||
struct Curl_easy *data;
|
struct Curl_easy *data;
|
||||||
struct Curl_easy *nextdata;
|
struct Curl_easy *nextdata;
|
||||||
|
|
||||||
if(GOOD_MULTI_HANDLE(multi)) {
|
if(GOOD_MULTI_HANDLE(multi)) {
|
||||||
bool restore_pipe = FALSE;
|
|
||||||
SIGPIPE_VARIABLE(pipe_st);
|
|
||||||
|
|
||||||
multi->type = 0; /* not good anymore */
|
multi->type = 0; /* not good anymore */
|
||||||
|
|
||||||
/* Firsrt remove all remaining easy handles */
|
/* Firsrt remove all remaining easy handles */
|
||||||
@ -2255,18 +2224,7 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Close all the connections in the connection cache */
|
/* Close all the connections in the connection cache */
|
||||||
close_all_connections(multi);
|
Curl_conncache_close_all_connections(&multi->conn_cache);
|
||||||
|
|
||||||
if(multi->closure_handle) {
|
|
||||||
sigpipe_ignore(multi->closure_handle, &pipe_st);
|
|
||||||
restore_pipe = TRUE;
|
|
||||||
|
|
||||||
multi->closure_handle->dns.hostcache = &multi->hostcache;
|
|
||||||
Curl_hostcache_clean(multi->closure_handle,
|
|
||||||
multi->closure_handle->dns.hostcache);
|
|
||||||
|
|
||||||
Curl_close(multi->closure_handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
Curl_hash_destroy(&multi->sockhash);
|
Curl_hash_destroy(&multi->sockhash);
|
||||||
Curl_conncache_destroy(&multi->conn_cache);
|
Curl_conncache_destroy(&multi->conn_cache);
|
||||||
@ -2280,8 +2238,6 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
|
|||||||
Curl_pipeline_set_server_blacklist(NULL, &multi->pipelining_server_bl);
|
Curl_pipeline_set_server_blacklist(NULL, &multi->pipelining_server_bl);
|
||||||
|
|
||||||
free(multi);
|
free(multi);
|
||||||
if(restore_pipe)
|
|
||||||
sigpipe_restore(&pipe_st);
|
|
||||||
|
|
||||||
return CURLM_OK;
|
return CURLM_OK;
|
||||||
}
|
}
|
||||||
|
@ -114,10 +114,6 @@ struct Curl_multi {
|
|||||||
/* Shared connection cache (bundles)*/
|
/* Shared connection cache (bundles)*/
|
||||||
struct conncache conn_cache;
|
struct conncache conn_cache;
|
||||||
|
|
||||||
/* This handle will be used for closing the cached connections in
|
|
||||||
curl_multi_cleanup() */
|
|
||||||
struct Curl_easy *closure_handle;
|
|
||||||
|
|
||||||
long maxconnects; /* if >0, a fixed limit of the maximum number of entries
|
long maxconnects; /* if >0, a fixed limit of the maximum number of entries
|
||||||
we're allowed to grow the connection cache to */
|
we're allowed to grow the connection cache to */
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -102,6 +102,8 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case CURL_LOCK_DATA_CONNECT: /* not supported (yet) */
|
case CURL_LOCK_DATA_CONNECT: /* not supported (yet) */
|
||||||
|
if(Curl_conncache_init(&share->conn_cache, 103))
|
||||||
|
return CURLSHE_NOMEM;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -186,6 +188,8 @@ curl_share_cleanup(struct Curl_share *share)
|
|||||||
return CURLSHE_IN_USE;
|
return CURLSHE_IN_USE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Curl_conncache_close_all_connections(&share->conn_cache);
|
||||||
|
Curl_conncache_destroy(&share->conn_cache);
|
||||||
Curl_hash_destroy(&share->hostcache);
|
Curl_hash_destroy(&share->hostcache);
|
||||||
|
|
||||||
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
|
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* 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 @@
|
|||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
#include "cookie.h"
|
#include "cookie.h"
|
||||||
#include "urldata.h"
|
#include "urldata.h"
|
||||||
|
#include "conncache.h"
|
||||||
|
|
||||||
/* SalfordC says "A structure member may not be volatile". Hence:
|
/* SalfordC says "A structure member may not be volatile". Hence:
|
||||||
*/
|
*/
|
||||||
@ -43,7 +44,7 @@ struct Curl_share {
|
|||||||
curl_lock_function lockfunc;
|
curl_lock_function lockfunc;
|
||||||
curl_unlock_function unlockfunc;
|
curl_unlock_function unlockfunc;
|
||||||
void *clientdata;
|
void *clientdata;
|
||||||
|
struct conncache conn_cache;
|
||||||
struct curl_hash hostcache;
|
struct curl_hash hostcache;
|
||||||
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
|
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
|
||||||
struct CookieInfo *cookies;
|
struct CookieInfo *cookies;
|
||||||
|
56
lib/url.c
56
lib/url.c
@ -3448,58 +3448,6 @@ static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This function finds the connection in the connection
|
|
||||||
* cache that has been unused for the longest time.
|
|
||||||
*
|
|
||||||
* Returns the pointer to the oldest idle connection, or NULL if none was
|
|
||||||
* found.
|
|
||||||
*/
|
|
||||||
struct connectdata *
|
|
||||||
Curl_oldest_idle_connection(struct Curl_easy *data)
|
|
||||||
{
|
|
||||||
struct conncache *bc = data->state.conn_cache;
|
|
||||||
struct curl_hash_iterator iter;
|
|
||||||
struct curl_llist_element *curr;
|
|
||||||
struct curl_hash_element *he;
|
|
||||||
timediff_t highscore =- 1;
|
|
||||||
timediff_t score;
|
|
||||||
struct curltime now;
|
|
||||||
struct connectdata *conn_candidate = NULL;
|
|
||||||
struct connectbundle *bundle;
|
|
||||||
|
|
||||||
now = Curl_now();
|
|
||||||
|
|
||||||
Curl_hash_start_iterate(&bc->hash, &iter);
|
|
||||||
|
|
||||||
he = Curl_hash_next_element(&iter);
|
|
||||||
while(he) {
|
|
||||||
struct connectdata *conn;
|
|
||||||
|
|
||||||
bundle = he->ptr;
|
|
||||||
|
|
||||||
curr = bundle->conn_list.head;
|
|
||||||
while(curr) {
|
|
||||||
conn = curr->ptr;
|
|
||||||
|
|
||||||
if(!conn->inuse) {
|
|
||||||
/* Set higher score for the age passed since the connection was used */
|
|
||||||
score = Curl_timediff(now, conn->now);
|
|
||||||
|
|
||||||
if(score > highscore) {
|
|
||||||
highscore = score;
|
|
||||||
conn_candidate = conn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
curr = curr->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
he = Curl_hash_next_element(&iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
return conn_candidate;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
proxy_info_matches(const struct proxy_info* data,
|
proxy_info_matches(const struct proxy_info* data,
|
||||||
const struct proxy_info* needle)
|
const struct proxy_info* needle)
|
||||||
@ -3619,7 +3567,7 @@ static void prune_dead_connections(struct Curl_easy *data)
|
|||||||
time_t elapsed = Curl_timediff(now, data->state.conn_cache->last_cleanup);
|
time_t elapsed = Curl_timediff(now, data->state.conn_cache->last_cleanup);
|
||||||
|
|
||||||
if(elapsed >= 1000L) {
|
if(elapsed >= 1000L) {
|
||||||
Curl_conncache_foreach(data->state.conn_cache, data,
|
Curl_conncache_foreach(data, data->state.conn_cache, data,
|
||||||
call_disconnect_if_dead);
|
call_disconnect_if_dead);
|
||||||
data->state.conn_cache->last_cleanup = now;
|
data->state.conn_cache->last_cleanup = now;
|
||||||
}
|
}
|
||||||
@ -6996,7 +6944,7 @@ static CURLcode create_conn(struct Curl_easy *data,
|
|||||||
struct connectdata *conn_candidate;
|
struct connectdata *conn_candidate;
|
||||||
|
|
||||||
/* The cache is full. Let's see if we can kill a connection. */
|
/* The cache is full. Let's see if we can kill a connection. */
|
||||||
conn_candidate = Curl_oldest_idle_connection(data);
|
conn_candidate = Curl_conncache_oldest_idle(data);
|
||||||
|
|
||||||
if(conn_candidate) {
|
if(conn_candidate) {
|
||||||
/* Set the connection's owner correctly, then kill it */
|
/* Set the connection's owner correctly, then kill it */
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* 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
|
||||||
@ -57,8 +57,6 @@ CURLcode Curl_addHandleToPipeline(struct Curl_easy *handle,
|
|||||||
struct curl_llist *pipeline);
|
struct curl_llist *pipeline);
|
||||||
int Curl_removeHandleFromPipeline(struct Curl_easy *handle,
|
int Curl_removeHandleFromPipeline(struct Curl_easy *handle,
|
||||||
struct curl_llist *pipeline);
|
struct curl_llist *pipeline);
|
||||||
struct connectdata *
|
|
||||||
Curl_oldest_idle_connection(struct Curl_easy *data);
|
|
||||||
/* remove the specified connection from all (possible) pipelines and related
|
/* remove the specified connection from all (possible) pipelines and related
|
||||||
queues */
|
queues */
|
||||||
void Curl_getoff_all_pipelines(struct Curl_easy *data,
|
void Curl_getoff_all_pipelines(struct Curl_easy *data,
|
||||||
|
Loading…
Reference in New Issue
Block a user