conncache: guess maxconnects different
No binary (build failed)
—
(log yok)
| @@ -28,14 +28,19 @@ CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_MAXCONNECTS, long max); | |
| Pass a long indicating the **max**, the maximum amount of connections that | |
| libcurl may keep alive in its connection cache after use. By default libcurl | |
| - | enlarges the size for each added easy handle to make it fit 4 times the number |
| + | enlarges the size for each added easy handle to make it fit twice the number |
| of added easy handles. | |
| By setting this option, you prevent the cache size from growing beyond the | |
| limit set by you. | |
| - | When the cache is full, curl closes the oldest connection present in the cache |
| - | to prevent the number of connections from increasing. |
| + | When the cache is full on a set limit, curl closes the oldest connection |
| + | present in the cache to prevent the number of connections from increasing. |
| + | |
| + | When the cache is full on the default limit, curl closes the oldest connection |
| + | present in the cache only if it has not been used for at least a second. This |
| + | is done because the number of added transfer can vary greatly, depending on |
| + | how the application uses them. |
| This option is for the multi handle's use only, when using the easy interface | |
| you should instead use the CURLOPT_MAXCONNECTS(3) option. | |
| @@ -339,15 +339,16 @@ static struct connectdata *cpool_bundle_get_oldest_idle( | |
| } | |
| static struct connectdata *cpool_get_oldest_idle(struct cpool *cpool, | |
| - | const struct curltime *pnow) |
| + | const struct curltime *pnow, |
| + | timediff_t min_age_ms) |
| { | |
| struct Curl_hash_iterator iter; | |
| struct Curl_llist_node *curr; | |
| struct Curl_hash_element *he; | |
| - | struct connectdata *oldest_idle = NULL; |
| struct cpool_bundle *bundle; | |
| - | timediff_t highscore = -1; |
| - | timediff_t score; |
| + | struct connectdata *oldest_idle = NULL; |
| + | timediff_t oldest_idle_ms = -1; |
| + | timediff_t idle_ms; |
| Curl_hash_start_iterate(&cpool->dest2bundle, &iter); | |
| @@ -361,10 +362,9 @@ static struct connectdata *cpool_get_oldest_idle(struct cpool *cpool, | |
| conn = Curl_node_elem(curr); | |
| if(CONN_INUSE(conn) || conn->bits.close || conn->bits.connect_only) | |
| continue; | |
| - | /* Set higher score for the age passed since the connection was used */ |
| - | score = curlx_ptimediff_ms(pnow, &conn->lastused); |
| - | if(score > highscore) { |
| - | highscore = score; |
| + | idle_ms = curlx_ptimediff_ms(pnow, &conn->lastused); |
| + | if((idle_ms >= min_age_ms) && (idle_ms > oldest_idle_ms)) { |
| + | oldest_idle_ms = idle_ms; |
| oldest_idle = conn; | |
| } | |
| } | |
| @@ -451,7 +451,8 @@ static void cpool_evict_conn(struct cpool *cpool, | |
| } | |
| int Curl_cpool_check_limits(struct Curl_easy *data, | |
| - | struct connectdata *conn) |
| + | struct connectdata *conn, |
| + | const struct curltime *pnow) |
| { | |
| struct cpool *cpool = cpool_get_instance(data); | |
| struct cshutdn *cshutdn = Curl_cshutdn_get(data); | |
| @@ -494,8 +495,7 @@ int Curl_cpool_check_limits(struct Curl_easy *data, | |
| struct connectdata *oldest_idle = NULL; | |
| /* The bundle is full. Extract the oldest connection that may | |
| * be removed now, if there is one. */ | |
| - | oldest_idle = cpool_bundle_get_oldest_idle(bundle, |
| - | Curl_pgrs_now(data)); |
| + | oldest_idle = cpool_bundle_get_oldest_idle(bundle, pnow); |
| if(!oldest_idle) | |
| break; | |
| /* disconnect the old conn and continue */ | |
| @@ -527,7 +527,7 @@ int Curl_cpool_check_limits(struct Curl_easy *data, | |
| } | |
| else { | |
| struct connectdata *oldest_idle = | |
| - | cpool_get_oldest_idle(cpool, Curl_pgrs_now(data)); |
| + | cpool_get_oldest_idle(cpool, pnow, 0); |
| if(!oldest_idle) | |
| break; | |
| /* disconnect the old conn and continue */ | |
| @@ -646,18 +646,18 @@ bool Curl_cpool_conn_now_idle(struct Curl_easy *data, | |
| struct cpool *cpool = cpool_get_instance(data); | |
| struct Curl_easy *admin; | |
| bool kept = TRUE; | |
| + | timediff_t min_age_ms = 0; |
| if(!data || !data->multi) | |
| return kept; | |
| if(!data->multi->maxconnects) { | |
| - | /* Running transfers is a weak indicator of business. When many |
| - | * transfers are done at the same time (parallel h1), the number |
| - | * may drop quite low and we do not want to close connections |
| - | * just to have another wave of transfers arriving next. */ |
| - | uint32_t running = Curl_multi_xfers_running(data->multi); |
| - | running = CURLMAX(running, 128); |
| - | maxconnects = (running <= UINT_MAX / 4) ? running * 4 : UINT_MAX; |
| + | /* Attached transfers is a weak indicator of business. */ |
| + | uint32_t attached = Curl_multi_xfers_attached(data->multi); |
| + | maxconnects = (attached <= UINT_MAX / 2) ? attached * 2 : UINT_MAX; |
| + | /* We are guessing. So, only evict a "seemingly superfluous" connection |
| + | * when has not been used for this long, */ |
| + | min_age_ms = 1000; |
| } | |
| else { | |
| maxconnects = data->multi->maxconnects; | |
| @@ -676,7 +676,7 @@ bool Curl_cpool_conn_now_idle(struct Curl_easy *data, | |
| infof(data, "Connection pool is full, closing the oldest of %zu/%u", | |
| cpool->num_conn, maxconnects); | |
| - | oldest_idle = cpool_get_oldest_idle(cpool, Curl_pgrs_now(data)); |
| + | oldest_idle = cpool_get_oldest_idle(cpool, &conn->lastused, min_age_ms); |
| kept = (oldest_idle != conn); | |
| if(oldest_idle) { | |
| cpool_evict_conn(cpool, admin, oldest_idle); | |
| @@ -93,7 +93,8 @@ CURLcode Curl_cpool_add(struct Curl_easy *data, | |
| #define CPOOL_LIMIT_DEST 1 | |
| #define CPOOL_LIMIT_TOTAL 2 | |
| int Curl_cpool_check_limits(struct Curl_easy *data, | |
| - | struct connectdata *conn); |
| + | struct connectdata *conn, |
| + | const struct curltime *pnow); |
| /* Return of conn is suitable. If so, stops iteration. */ | |
| typedef bool Curl_cpool_conn_match_cb(struct connectdata *conn, | |
| @@ -2951,7 +2951,7 @@ static CURLMcode multi_perform(struct Curl_multi *multi, | |
| } | |
| if(running_handles) { | |
| - | unsigned int running = Curl_multi_xfers_running(multi); |
| + | uint32_t running = Curl_multi_xfers_running(multi); |
| *running_handles = (running < INT_MAX) ? (int)running : INT_MAX; | |
| } | |
| @@ -3309,7 +3309,7 @@ out: | |
| mresult = Curl_mntfy_dispatch_all(multi); | |
| if(running_handles) { | |
| - | unsigned int running = Curl_multi_xfers_running(multi); |
| + | uint32_t running = Curl_multi_xfers_running(multi); |
| *running_handles = (running < INT_MAX) ? (int)running : INT_MAX; | |
| } | |
| @@ -4153,14 +4153,25 @@ bool Curl_multi_knows_easy(struct Curl_multi *multi, struct Curl_easy *data) | |
| return Curl_uint32_tbl_get(&multi->xfers, data->mid) == data; | |
| } | |
| - | unsigned int Curl_multi_xfers_running(struct Curl_multi *multi) |
| + | uint32_t Curl_multi_xfers_running(struct Curl_multi *multi) |
| { | |
| - | DEBUGASSERT(multi); |
| - | if(!multi) |
| + | if(!multi) { |
| + | DEBUGASSERT(0); |
| return 0; | |
| + | } |
| return multi->xfers_alive; | |
| } | |
| + | uint32_t Curl_multi_xfers_attached(struct Curl_multi *multi) |
| + | { |
| + | if(!multi || !multi->admin) { |
| + | DEBUGASSERT(0); |
| + | return 0; |
| + | } |
| + | /* Discount the admin handle */ |
| + | return Curl_uint32_tbl_count(&multi->xfers) - 1; |
| + | } |
| + | |
| void Curl_multi_mark_dirty(struct Curl_easy *data) | |
| { | |
| if(data->multi && data->mid != UINT32_MAX) | |
| @@ -158,8 +158,12 @@ struct Curl_easy *Curl_multi_get_easy(struct Curl_multi *multi, | |
| /* TRUE if multi knows about data via its `mid` */ | |
| bool Curl_multi_knows_easy(struct Curl_multi *multi, struct Curl_easy *data); | |
| + | /* Get the # of transfers attached to the multi, without the internal |
| + | * admin handle. */ |
| + | uint32_t Curl_multi_xfers_attached(struct Curl_multi *multi); |
| + | |
| /* Get the # of transfers current in process/pending. */ | |
| - | unsigned int Curl_multi_xfers_running(struct Curl_multi *multi); |
| + | uint32_t Curl_multi_xfers_running(struct Curl_multi *multi); |
| /* Mark a transfer as dirty, e.g. to be rerun at earliest convenience. | |
| * A cheap operation, can be done many times repeatedly. */ | |
| @@ -2383,7 +2383,7 @@ static CURLcode url_find_or_create_conn(struct Curl_easy *data) | |
| goto out; | |
| } | |
| else { | |
| - | switch(Curl_cpool_check_limits(data, needle)) { |
| + | switch(Curl_cpool_check_limits(data, needle, &needle->created)) { |
| case CPOOL_LIMIT_DEST: | |
| infof(data, "No more connections allowed to host"); | |
| result = CURLE_NO_CONNECTION_AVAILABLE; | |