Commit 3c8c8732 authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

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
parent 4901ec23
Loading
Loading
Loading
Loading
+21 −6
Original line number Diff line number Diff line
@@ -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,6 +1051,11 @@ 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);

        /* 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 */
  }
}

+4 −1
Original line number Diff line number Diff line
@@ -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;