diff options
author | Daniel Stenberg <daniel@haxx.se> | 2014-09-02 09:29:50 +0200 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2014-09-02 10:17:47 +0200 |
commit | 3c8c873252fa486d1e57fa28b8b455bfdb487f77 (patch) | |
tree | f0971a644a3d2d3ae14b0f5c5d57e31a7c216c1c | |
parent | 4901ec232469deddcda21b6b70d2db1cae93a2bb (diff) |
multi: convert CURLM_STATE_CONNECT_PEND handling to a list
... instead of scanning through all handles, stash only the actual
handles that are in that state in the new ->pending list and scan that
list only. It should be mostly empty or very short. And only used for
pipelining.
This avoids a rather hefty slow-down especially notable if you add many
handles to the same multi handle. Regression introduced in commit
0f147887 (version 7.30.0).
Bug: http://curl.haxx.se/mail/lib-2014-07/0206.html
Reported-by: David Meyer
-rw-r--r-- | lib/multi.c | 27 | ||||
-rw-r--r-- | lib/multihandle.h | 5 |
2 files changed, 25 insertions, 7 deletions
diff --git a/lib/multi.c b/lib/multi.c index 557be06df..7947436c7 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -309,6 +309,10 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ if(!multi->msglist) goto error; + multi->pending = Curl_llist_alloc(multi_freeamsg); + if(!multi->pending) + goto error; + /* allocate a new easy handle to use when closing cached connections */ multi->closure_handle = curl_easy_init(); if(!multi->closure_handle) @@ -334,6 +338,7 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */ Curl_close(multi->closure_handle); multi->closure_handle = NULL; Curl_llist_destroy(multi->msglist, NULL); + Curl_llist_destroy(multi->pending, NULL); free(multi); return NULL; @@ -1046,7 +1051,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* There was no connection available. We will go to the pending state and wait for an available connection. */ multistate(data, CURLM_STATE_CONNECT_PEND); - data->result = CURLE_OK; + + /* add this handle to the list of connect-pending handles */ + if(!Curl_llist_insert_next(multi->pending, multi->pending->tail, data)) + data->result = CURLM_OUT_OF_MEMORY; + else + data->result = CURLE_OK; break; } @@ -1884,6 +1894,10 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle) Curl_llist_destroy(multi->msglist, NULL); multi->msglist = NULL; + /* remove the pending handles queue */ + Curl_llist_destroy(multi->pending, NULL); + multi->msglist = NULL; + /* remove all easy handles */ data = multi->easyp; while(data) { @@ -2776,16 +2790,17 @@ struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi) void Curl_multi_process_pending_handles(struct Curl_multi *multi) { - struct SessionHandle *data; + struct curl_llist_element *e; - data=multi->easyp; - while(data) { + for(e = multi->pending->head; e; e = e->next) { + struct SessionHandle *data = e->ptr; if(data->mstate == CURLM_STATE_CONNECT_PEND) { multistate(data, CURLM_STATE_CONNECT); + /* Remove this node from the list */ + Curl_llist_remove(multi->pending, e, NULL); /* Make sure that the handle will be processed soonish. */ - Curl_expire(data, 1); + Curl_expire_latest(data, 1); } - data = data->next; /* operate on next handle */ } } diff --git a/lib/multihandle.h b/lib/multihandle.h index 552aa9379..1a4b1d966 100644 --- a/lib/multihandle.h +++ b/lib/multihandle.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2014, 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 @@ -75,6 +75,9 @@ struct Curl_multi { struct curl_llist *msglist; /* a list of messages from completed transfers */ + struct curl_llist *pending; /* SessionHandles that are in the + CURLM_STATE_CONNECT_PEND state */ + /* callback function and user data pointer for the *socket() API */ curl_socket_callback socket_cb; void *socket_userp; |