conncache: conn upkeep/alive: move and enhance
No binary (build failed)
—
(log yok)
| @@ -450,9 +450,9 @@ static CURLcode cf_cntrl_all(struct connectdata *conn, | |
| int event, int arg1, void *arg2) | |
| { | |
| CURLcode result = CURLE_OK; | |
| - | size_t i; |
| + | int i; |
| - | for(i = 0; i < CURL_ARRAYSIZE(conn->cfilter); ++i) { |
| + | for(i = 0; i < (int)CURL_ARRAYSIZE(conn->cfilter); ++i) { |
| result = Curl_conn_cf_cntrl(conn->cfilter[i], data, ignore_result, | |
| event, arg1, arg2); | |
| if(!ignore_result && result) | |
| @@ -753,7 +753,7 @@ CURLcode Curl_conn_adjust_pollset(struct Curl_easy *data, | |
| * connect or shutdown does not add poll events for the other. Check | |
| * against the transfer's own interest, before any chain added sockets | |
| * of its own. */ | |
| - | for(i = 0; (i < 2) && !result; ++i) { |
| + | for(i = 0; (i < (int)CURL_ARRAYSIZE(conn->cfilter)) && !result; ++i) { |
| if(conn->cfilter[i] && | |
| (want_io || !Curl_conn_is_connected(conn, i) || | |
| Curl_shutdown_started(conn, i))) | |
| @@ -978,15 +978,17 @@ bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn, | |
| } | |
| CURLcode Curl_conn_keep_alive(struct Curl_easy *data, | |
| - | struct connectdata *conn, |
| - | int sockindex) |
| + | struct connectdata *conn) |
| { | |
| - | struct Curl_cfilter *cf; |
| + | CURLcode result = CURLE_OK; |
| + | int i; |
| - | if(!CONN_SOCK_IDX_VALID(sockindex)) |
| - | return CURLE_BAD_FUNCTION_ARGUMENT; |
| - | cf = conn->cfilter[sockindex]; |
| - | return cf ? cf->cft->keep_alive(cf, data) : CURLE_OK; |
| + | for(i = 0; (i < (int)CURL_ARRAYSIZE(conn->cfilter)) && !result; ++i) { |
| + | struct Curl_cfilter *cf = conn->cfilter[i]; |
| + | if(cf) |
| + | result = cf->cft->keep_alive(cf, data); |
| + | } |
| + | return result; |
| } | |
| size_t Curl_conn_get_max_concurrent(struct Curl_easy *data, | |
| @@ -558,11 +558,10 @@ bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn, | |
| bool *input_pending); | |
| /** | |
| - | * Try to upkeep the connection filters at sockindex. |
| + | * Try to upkeep the connection filters. |
| */ | |
| CURLcode Curl_conn_keep_alive(struct Curl_easy *data, | |
| - | struct connectdata *conn, |
| - | int sockindex); |
| + | struct connectdata *conn); |
| /** | |
| * Get the remote hostname and port that the connection is currently | |
| @@ -715,7 +715,7 @@ static int cpool_reap_dead_cb(struct Curl_easy *data, | |
| if(!terminate) { | |
| reaper->checked++; | |
| - | terminate = Curl_conn_seems_dead(conn, data, &reaper->now); |
| + | terminate = Curl_cpool_conn_seems_dead(conn, data, &reaper->now); |
| } | |
| if(terminate) { | |
| /* stop the iteration here, pass back the connection that was pruned */ | |
| @@ -761,7 +761,21 @@ static int conn_upkeep(struct Curl_easy *data, | |
| void *param) | |
| { | |
| (void)param; | |
| - | Curl_conn_upkeep(data, conn); |
| + | if(curlx_ptimediff_ms(Curl_pgrs_now(data), &conn->keepalive) >= |
| + | data->set.upkeep_interval_ms) { |
| + | CURLcode result; |
| + | |
| + | /* briefly attach for action */ |
| + | Curl_attach_connection(data, conn); |
| + | result = Curl_conn_keep_alive(data, conn); |
| + | conn->keepalive = *Curl_pgrs_now(data); |
| + | Curl_detach_connection(data); |
| + | |
| + | if(result && !CONN_INUSE(conn)) { |
| + | Curl_conn_terminate(data, conn, FALSE); |
| + | return 1; |
| + | } |
| + | } |
| return 0; /* continue iteration */ | |
| } | |
| @@ -773,7 +787,8 @@ CURLcode Curl_cpool_upkeep(struct Curl_easy *data) | |
| return CURLE_OK; | |
| CPOOL_LOCK(cpool, data); | |
| - | cpool_foreach(data, cpool, NULL, conn_upkeep); |
| + | while(cpool_foreach(data, cpool, NULL, conn_upkeep)) |
| + | ; |
| CPOOL_UNLOCK(cpool, data); | |
| return CURLE_OK; | |
| } | |
| @@ -858,6 +873,84 @@ void Curl_cpool_nw_changed(struct Curl_easy *data) | |
| } | |
| } | |
| + | /* A connection has to have been idle for less than 'conn_max_idle_ms' |
| + | (the success rate is too low after this), or created less than |
| + | 'conn_max_age_ms' ago, to be subject for reuse. */ |
| + | static bool cpool_conn_maxage(struct Curl_easy *data, |
| + | struct connectdata *conn, |
| + | const struct curltime *pnow) |
| + | { |
| + | timediff_t age_ms; |
| + | |
| + | if(data->set.conn_max_idle_ms) { |
| + | age_ms = curlx_ptimediff_ms(pnow, &conn->lastused); |
| + | if(age_ms > data->set.conn_max_idle_ms) { |
| + | infof(data, "Too old connection (%" FMT_TIMEDIFF_T |
| + | " ms idle, max idle is %" FMT_TIMEDIFF_T " ms), disconnect it", |
| + | age_ms, data->set.conn_max_idle_ms); |
| + | return TRUE; |
| + | } |
| + | } |
| + | |
| + | if(data->set.conn_max_age_ms) { |
| + | age_ms = curlx_ptimediff_ms(pnow, &conn->created); |
| + | if(age_ms > data->set.conn_max_age_ms) { |
| + | infof(data, |
| + | "Too old connection (created %" FMT_TIMEDIFF_T |
| + | " ms ago, max lifetime is %" FMT_TIMEDIFF_T " ms), disconnect it", |
| + | age_ms, data->set.conn_max_age_ms); |
| + | return TRUE; |
| + | } |
| + | } |
| + | |
| + | return FALSE; |
| + | } |
| + | |
| + | /* |
| + | * Return TRUE iff the given connection is considered dead. |
| + | */ |
| + | bool Curl_cpool_conn_seems_dead(struct connectdata *conn, |
| + | struct Curl_easy *data, |
| + | const struct curltime *pnow) |
| + | { |
| + | bool input_pending = FALSE; |
| + | bool dead = FALSE; |
| + | |
| + | DEBUGASSERT(!data->conn); |
| + | /* The check only makes sense only if the connection is not in use */ |
| + | if(CONN_INUSE(conn)) |
| + | return FALSE; |
| + | else if(cpool_conn_maxage(data, conn, pnow)) /* too old? */ |
| + | return TRUE; |
| + | else if(curlx_ptimediff_ms(pnow, &conn->lastchecked) < 1000) |
| + | return FALSE; |
| + | else if(conn->scheme->run->connection_is_dead) { |
| + | Curl_attach_connection(data, conn); |
| + | dead = conn->scheme->run->connection_is_dead(data, conn); |
| + | Curl_detach_connection(data); |
| + | } |
| + | else { |
| + | Curl_attach_connection(data, conn); |
| + | dead = !Curl_conn_is_alive(data, conn, &input_pending); |
| + | Curl_detach_connection(data); |
| + | } |
| + | |
| + | if(input_pending) { |
| + | /* For reuse, we want a "clean" connection state. This includes |
| + | * that we expect - in general - no waiting input data. Input |
| + | * waiting might be a TLS Notify Close, for example. We reject |
| + | * that. |
| + | * For protocols where data from other end may arrive at |
| + | * any time (HTTP/2 PING for example), the protocol handler needs |
| + | * to install its own `connection_check` callback. |
| + | */ |
| + | DEBUGF(infof(data, "connection has input pending, not reusable")); |
| + | dead = TRUE; |
| + | } |
| + | |
| + | return dead; |
| + | } |
| + | |
| #if 0 | |
| /* Useful for debugging the connection pool */ | |
| void Curl_cpool_print(struct cpool *cpool) | |
| @@ -156,4 +156,11 @@ void Curl_cpool_do_locked(struct Curl_easy *data, | |
| /* Close all unused connections, prevent reuse of existing ones. */ | |
| void Curl_cpool_nw_changed(struct Curl_easy *data); | |
| + | /** |
| + | * Return TRUE iff the given connection is considered dead. |
| + | */ |
| + | bool Curl_cpool_conn_seems_dead(struct connectdata *conn, |
| + | struct Curl_easy *data, |
| + | const struct curltime *pnow); |
| + | |
| #endif /* HEADER_CURL_CONNCACHE_H */ | |
| @@ -564,115 +564,6 @@ static bool proxy_info_matches(const struct proxy_info *data, | |
| } | |
| #endif | |
| - | /* A connection has to have been idle for less than 'conn_max_idle_ms' |
| - | (the success rate is too low after this), or created less than |
| - | 'conn_max_age_ms' ago, to be subject for reuse. */ |
| - | static bool conn_maxage(struct Curl_easy *data, |
| - | struct connectdata *conn, |
| - | struct curltime now) |
| - | { |
| - | timediff_t age_ms; |
| - | |
| - | if(data->set.conn_max_idle_ms) { |
| - | age_ms = curlx_ptimediff_ms(&now, &conn->lastused); |
| - | if(age_ms > data->set.conn_max_idle_ms) { |
| - | infof(data, "Too old connection (%" FMT_TIMEDIFF_T |
| - | " ms idle, max idle is %" FMT_TIMEDIFF_T " ms), disconnect it", |
| - | age_ms, data->set.conn_max_idle_ms); |
| - | return TRUE; |
| - | } |
| - | } |
| - | |
| - | if(data->set.conn_max_age_ms) { |
| - | age_ms = curlx_ptimediff_ms(&now, &conn->created); |
| - | if(age_ms > data->set.conn_max_age_ms) { |
| - | infof(data, |
| - | "Too old connection (created %" FMT_TIMEDIFF_T |
| - | " ms ago, max lifetime is %" FMT_TIMEDIFF_T " ms), disconnect it", |
| - | age_ms, data->set.conn_max_age_ms); |
| - | return TRUE; |
| - | } |
| - | } |
| - | |
| - | return FALSE; |
| - | } |
| - | |
| - | /* |
| - | * Return TRUE iff the given connection is considered dead. |
| - | */ |
| - | bool Curl_conn_seems_dead(struct connectdata *conn, |
| - | struct Curl_easy *data, |
| - | const struct curltime *pnow) |
| - | { |
| - | DEBUGASSERT(!data->conn); |
| - | if(!CONN_INUSE(conn)) { |
| - | /* The check for a dead socket makes sense only if the connection is not in |
| - | use */ |
| - | bool dead; |
| - | |
| - | if(conn_maxage(data, conn, *pnow)) { |
| - | /* avoid check if already too old */ |
| - | dead = TRUE; |
| - | } |
| - | else if(curlx_ptimediff_ms(pnow, &conn->lastchecked) < 1000) |
| - | dead = FALSE; |
| - | else if(conn->scheme->run->connection_is_dead) { |
| - | /* The protocol has a special method for checking the state of the |
| - | connection. Use it to check if the connection is dead. */ |
| - | /* briefly attach the connection for the check */ |
| - | Curl_attach_connection(data, conn); |
| - | dead = conn->scheme->run->connection_is_dead(data, conn); |
| - | Curl_detach_connection(data); |
| - | conn->lastchecked = *pnow; |
| - | } |
| - | else { |
| - | bool input_pending = FALSE; |
| - | |
| - | Curl_attach_connection(data, conn); |
| - | dead = !Curl_conn_is_alive(data, conn, &input_pending); |
| - | if(input_pending) { |
| - | /* For reuse, we want a "clean" connection state. This includes |
| - | * that we expect - in general - no waiting input data. Input |
| - | * waiting might be a TLS Notify Close, for example. We reject |
| - | * that. |
| - | * For protocols where data from other end may arrive at |
| - | * any time (HTTP/2 PING for example), the protocol handler needs |
| - | * to install its own `connection_check` callback. |
| - | */ |
| - | DEBUGF(infof(data, "connection has input pending, not reusable")); |
| - | dead = TRUE; |
| - | } |
| - | Curl_detach_connection(data); |
| - | conn->lastchecked = *pnow; |
| - | } |
| - | |
| - | if(dead) { |
| - | /* remove connection from cpool */ |
| - | infof(data, "Connection %" FMT_OFF_T " seems to be dead", |
| - | conn->connection_id); |
| - | return TRUE; |
| - | } |
| - | } |
| - | return FALSE; |
| - | } |
| - | |
| - | CURLcode Curl_conn_upkeep(struct Curl_easy *data, |
| - | struct connectdata *conn) |
| - | { |
| - | CURLcode result = CURLE_OK; |
| - | if(curlx_ptimediff_ms(Curl_pgrs_now(data), &conn->keepalive) <= |
| - | data->set.upkeep_interval_ms) |
| - | return result; |
| - | |
| - | /* briefly attach for action */ |
| - | Curl_attach_connection(data, conn); |
| - | result = Curl_conn_keep_alive(data, conn, FIRSTSOCKET); |
| - | Curl_detach_connection(data); |
| - | |
| - | conn->keepalive = *Curl_pgrs_now(data); |
| - | return result; |
| - | } |
| - | |
| #ifdef USE_SSH | |
| static bool ssh_config_matches(struct connectdata *one, | |
| struct connectdata *two) | |
| @@ -1172,8 +1063,10 @@ static bool url_match_conn(struct connectdata *conn, void *userdata) | |
| if(!url_match_multiplex_limits(conn, m)) | |
| return FALSE; | |
| - | if(!CONN_INUSE(conn) && Curl_conn_seems_dead(conn, m->data, &m->now)) { |
| + | if(Curl_cpool_conn_seems_dead(conn, m->data, &m->now)) { |
| /* remove and disconnect. */ | |
| + | infof(m->data, "Connection %" FMT_OFF_T " seems to be dead, terminating", |
| + | conn->connection_id); |
| Curl_conn_terminate(m->data, conn, FALSE); | |
| return FALSE; | |
| } | |
| @@ -71,23 +71,8 @@ void *Curl_conn_meta_get(struct connectdata *conn, const char *key); | |
| #define CURL_DEFAULT_HTTPS_PROXY_PORT 443 /* default https proxy port unless | |
| specified */ | |
| - | /** |
| - | * Return TRUE iff the given connection is considered dead. |
| - | */ |
| - | bool Curl_conn_seems_dead(struct connectdata *conn, |
| - | struct Curl_easy *data, |
| - | const struct curltime *pnow); |
| - | |
| - | /** |
| - | * Perform upkeep operations on the connection. |
| - | */ |
| - | CURLcode Curl_conn_upkeep(struct Curl_easy *data, |
| - | struct connectdata *conn); |
| - | |
| - | /** |
| - | * Always eval all arguments, return the first |
| - | * result != (CURLE_OK | CURLE_AGAIN) or `r1`. |
| - | */ |
| + | /* Always eval all arguments, return the first |
| + | * result != (CURLE_OK | CURLE_AGAIN) or `r1`. */ |
| CURLcode Curl_1st_fatal(CURLcode r1, CURLcode r2); | |
| #if defined(USE_HTTP2) || defined(USE_HTTP3) | |