1
0
mirror of https://github.com/moparisthebest/curl synced 2024-11-14 21:45:13 -05:00

CURLOPT_MAXAGE_CONN: set the maximum allowed age for conn reuse

... and disconnect too old ones instead of trying to reuse.

Default max age is set to 118 seconds.

Ref: #3722
Closes #3782
This commit is contained in:
Daniel Stenberg 2019-04-14 23:20:01 +02:00
parent 060f870b85
commit e649432e72
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
10 changed files with 106 additions and 14 deletions

View File

@ -35,7 +35,6 @@
1.16 Try to URL encode given URL 1.16 Try to URL encode given URL
1.17 Add support for IRIs 1.17 Add support for IRIs
1.18 try next proxy if one doesn't work 1.18 try next proxy if one doesn't work
1.19 Timeout idle connections from the pool
1.20 SRV and URI DNS records 1.20 SRV and URI DNS records
1.21 Have the URL API offer IDN decoding 1.21 Have the URL API offer IDN decoding
1.22 CURLINFO_PAUSE_STATE 1.22 CURLINFO_PAUSE_STATE
@ -373,16 +372,6 @@
https://github.com/curl/curl/issues/896 https://github.com/curl/curl/issues/896
1.19 Timeout idle connections from the pool
libcurl currently keeps connections in its connection pool for an indefinite
period of time, until it either gets reused, gets noticed that it has been
closed by the server or gets pruned to make room for a new connection.
To reduce overhead (especially for when we add monitoring of the connections
in the pool), we should introduce a timeout so that connections that have
been idle for N seconds get closed.
1.20 SRV and URI DNS records 1.20 SRV and URI DNS records
Offer support for resolving SRV and URI DNS records for libcurl to know which Offer support for resolving SRV and URI DNS records for libcurl to know which

View File

@ -468,6 +468,8 @@ Maximum number of connections in the connection pool. See \fICURLOPT_MAXCONNECTS
Use a new connection. \fICURLOPT_FRESH_CONNECT(3)\fP Use a new connection. \fICURLOPT_FRESH_CONNECT(3)\fP
.IP CURLOPT_FORBID_REUSE .IP CURLOPT_FORBID_REUSE
Prevent subsequent connections from re-using this. See \fICURLOPT_FORBID_REUSE(3)\fP Prevent subsequent connections from re-using this. See \fICURLOPT_FORBID_REUSE(3)\fP
.IP CURLOPT_MAXAGE_CONN
Limit the age of connections for reuse. See \fICURLOPT_MAXAGE_CONN(3)\fP
.IP CURLOPT_CONNECTTIMEOUT .IP CURLOPT_CONNECTTIMEOUT
Timeout for the connection phase. See \fICURLOPT_CONNECTTIMEOUT(3)\fP Timeout for the connection phase. See \fICURLOPT_CONNECTTIMEOUT(3)\fP
.IP CURLOPT_CONNECTTIMEOUT_MS .IP CURLOPT_CONNECTTIMEOUT_MS

View File

@ -0,0 +1,65 @@
.\" **************************************************************************
.\" * _ _ ____ _
.\" * Project ___| | | | _ \| |
.\" * / __| | | | |_) | |
.\" * | (__| |_| | _ <| |___
.\" * \___|\___/|_| \_\_____|
.\" *
.\" * Copyright (C) 2019, 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.
.\" *
.\" **************************************************************************
.\"
.TH CURLOPT_MAXAGE_CONN 3 "18 Apr 2019" "libcurl 7.65.0" "curl_easy_setopt options"
.SH NAME
CURLOPT_MAXAGE_CONN \- max idle time allowed for reusing a connection
.SH SYNOPSIS
#include <curl/curl.h>
CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MAXAGE_CONN, long maxage);
.SH DESCRIPTION
Pass a long as parameter containing \fImaxage\fP - the maximum time in seconds
that you allow an existing connection to have to be considered for reuse for
this request.
The "connection cache" that holds previously used connections. When a new
request is to be done, it will consider any connection that matches for
reuse. The \fICURLOPT_MAXAGE_CONN(3)\fP limit prevents libcurl from trying
very old connections for reuse, since old connections have a high risk of not
working and thus trying them is a performance loss and sometimes service loss
due to the difficulties to figure out the situation. If a connection is found
in the cache that is older than this set \fImaxage\fP, it will instead be
closed.
.SH DEFAULT
Default maxage is 118 seconds.
.SH PROTOCOLS
All
.SH EXAMPLE
.nf
CURL *curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://example.com");
/* only allow 30 seconds idle time */
curl_easy_setopt(curl, CURLOPT_MAXAGE_CONN, 30L);
curl_easy_perform(curl);
}
.fi
.SH AVAILABILITY
Added in libcurl 7.65.0
.SH RETURN VALUE
Returns CURLE_OK.
.SH "SEE ALSO"
.BR CURLOPT_TIMEOUT "(3), " CURLOPT_FORBID_REUSE "(3), "
.BR CURLOPT_FRESH_CONNECT "(3), "

View File

@ -189,6 +189,7 @@ man_MANS = \
CURLOPT_MAIL_AUTH.3 \ CURLOPT_MAIL_AUTH.3 \
CURLOPT_MAIL_FROM.3 \ CURLOPT_MAIL_FROM.3 \
CURLOPT_MAIL_RCPT.3 \ CURLOPT_MAIL_RCPT.3 \
CURLOPT_MAXAGE_CONN.3 \
CURLOPT_MAXCONNECTS.3 \ CURLOPT_MAXCONNECTS.3 \
CURLOPT_MAXFILESIZE.3 \ CURLOPT_MAXFILESIZE.3 \
CURLOPT_MAXFILESIZE_LARGE.3 \ CURLOPT_MAXFILESIZE_LARGE.3 \

View File

@ -463,6 +463,7 @@ CURLOPT_LOW_SPEED_TIME 7.1
CURLOPT_MAIL_AUTH 7.25.0 CURLOPT_MAIL_AUTH 7.25.0
CURLOPT_MAIL_FROM 7.20.0 CURLOPT_MAIL_FROM 7.20.0
CURLOPT_MAIL_RCPT 7.20.0 CURLOPT_MAIL_RCPT 7.20.0
CURLOPT_MAXAGE_CONN 7.65.0
CURLOPT_MAXCONNECTS 7.7 CURLOPT_MAXCONNECTS 7.7
CURLOPT_MAXFILESIZE 7.10.8 CURLOPT_MAXFILESIZE 7.10.8
CURLOPT_MAXFILESIZE_LARGE 7.11.0 CURLOPT_MAXFILESIZE_LARGE 7.11.0

View File

@ -1918,6 +1918,9 @@ typedef enum {
/* alt-svc cache file name to possibly read from/write to */ /* alt-svc cache file name to possibly read from/write to */
CINIT(ALTSVC, STRINGPOINT, 287), CINIT(ALTSVC, STRINGPOINT, 287),
/* maximum age of a connection to consider it for reuse (in seconds) */
CINIT(MAXAGE_CONN, LONG, 288),
CURLOPT_LASTENTRY /* the last unused */ CURLOPT_LASTENTRY /* the last unused */
} CURLoption; } CURLoption;

View File

@ -434,6 +434,7 @@ bool Curl_conncache_return_conn(struct connectdata *conn)
struct connectdata *conn_candidate = NULL; struct connectdata *conn_candidate = NULL;
conn->data = NULL; /* no owner anymore */ conn->data = NULL; /* no owner anymore */
conn->lastused = Curl_now(); /* it was used up until now */
if(maxconnects > 0 && if(maxconnects > 0 &&
Curl_conncache_size(data) > maxconnects) { Curl_conncache_size(data) > maxconnects) {
infof(data, "Connection cache is full, closing the oldest one.\n"); infof(data, "Connection cache is full, closing the oldest one.\n");
@ -479,7 +480,7 @@ Curl_conncache_extract_bundle(struct Curl_easy *data,
if(!CONN_INUSE(conn) && !conn->data) { if(!CONN_INUSE(conn) && !conn->data) {
/* Set higher score for the age passed since the connection was used */ /* Set higher score for the age passed since the connection was used */
score = Curl_timediff(now, conn->now); score = Curl_timediff(now, conn->lastused);
if(score > highscore) { if(score > highscore) {
highscore = score; highscore = score;
@ -537,7 +538,7 @@ Curl_conncache_extract_oldest(struct Curl_easy *data)
if(!CONN_INUSE(conn) && !conn->data) { if(!CONN_INUSE(conn) && !conn->data) {
/* Set higher score for the age passed since the connection was used */ /* Set higher score for the age passed since the connection was used */
score = Curl_timediff(now, conn->now); score = Curl_timediff(now, conn->lastused);
if(score > highscore) { if(score > highscore) {
highscore = score; highscore = score;

View File

@ -2645,6 +2645,12 @@ static CURLcode vsetopt(struct Curl_easy *data, CURLoption option,
return CURLE_BAD_FUNCTION_ARGUMENT; return CURLE_BAD_FUNCTION_ARGUMENT;
data->set.upkeep_interval_ms = arg; data->set.upkeep_interval_ms = arg;
break; break;
case CURLOPT_MAXAGE_CONN:
arg = va_arg(param, long);
if(arg < 0)
return CURLE_BAD_FUNCTION_ARGUMENT;
data->set.maxage_conn = arg;
break;
case CURLOPT_TRAILERFUNCTION: case CURLOPT_TRAILERFUNCTION:
#ifndef CURL_DISABLE_HTTP #ifndef CURL_DISABLE_HTTP
data->set.trailer_callback = va_arg(param, curl_trailer_callback); data->set.trailer_callback = va_arg(param, curl_trailer_callback);

View File

@ -541,6 +541,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
set->fnmatch = ZERO_NULL; set->fnmatch = ZERO_NULL;
set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT; set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT;
set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */ set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
set->maxage_conn = 118;
set->http09_allowed = TRUE; set->http09_allowed = TRUE;
set->httpversion = set->httpversion =
#ifdef USE_NGHTTP2 #ifdef USE_NGHTTP2
@ -958,6 +959,25 @@ static void prune_dead_connections(struct Curl_easy *data)
} }
} }
/* A connection has to have been idle for a shorter time than 'maxage_conn' to
be subject for reuse. The success rate is just too low after this. */
static bool conn_maxage(struct Curl_easy *data,
struct connectdata *conn,
struct curltime now)
{
if(!conn->data) {
timediff_t idletime = Curl_timediff(now, conn->lastused);
idletime /= 1000; /* integer seconds is fine */
if(idletime/1000 > data->set.maxage_conn) {
infof(data, "Too old connection (%ld seconds), disconnect it\n",
idletime);
return TRUE;
}
}
return FALSE;
}
/* /*
* Given one filled in connection struct (named needle), this function should * Given one filled in connection struct (named needle), this function should
* detect if there already is one that has all the significant details * detect if there already is one that has all the significant details
@ -981,6 +1001,7 @@ ConnectionExists(struct Curl_easy *data,
bool foundPendingCandidate = FALSE; bool foundPendingCandidate = FALSE;
bool canmultiplex = IsMultiplexingPossible(data, needle); bool canmultiplex = IsMultiplexingPossible(data, needle);
struct connectbundle *bundle; struct connectbundle *bundle;
struct curltime now = Curl_now();
#ifdef USE_NTLM #ifdef USE_NTLM
bool wantNTLMhttp = ((data->state.authhost.want & bool wantNTLMhttp = ((data->state.authhost.want &
@ -1044,7 +1065,7 @@ ConnectionExists(struct Curl_easy *data,
/* connect-only connections will not be reused */ /* connect-only connections will not be reused */
continue; continue;
if(extract_if_dead(check, data)) { if(conn_maxage(data, check, now) || extract_if_dead(check, data)) {
/* disconnect it */ /* disconnect it */
(void)Curl_disconnect(data, check, /* dead_connection */TRUE); (void)Curl_disconnect(data, check, /* dead_connection */TRUE);
continue; continue;

View File

@ -866,6 +866,7 @@ struct connectdata {
struct curltime now; /* "current" time */ struct curltime now; /* "current" time */
struct curltime created; /* creation time */ struct curltime created; /* creation time */
struct curltime lastused; /* when returned to the connection cache */
curl_socket_t sock[2]; /* two sockets, the second is used for the data curl_socket_t sock[2]; /* two sockets, the second is used for the data
transfer when doing FTP */ transfer when doing FTP */
curl_socket_t tempsock[2]; /* temporary sockets for happy eyeballs */ curl_socket_t tempsock[2]; /* temporary sockets for happy eyeballs */
@ -1553,6 +1554,8 @@ struct UserDefined {
long accepttimeout; /* in milliseconds, 0 means no timeout */ long accepttimeout; /* in milliseconds, 0 means no timeout */
long happy_eyeballs_timeout; /* in milliseconds, 0 is a valid value */ long happy_eyeballs_timeout; /* in milliseconds, 0 is a valid value */
long server_response_timeout; /* in milliseconds, 0 means no timeout */ long server_response_timeout; /* in milliseconds, 0 means no timeout */
long maxage_conn; /* in seconds, max idle time to allow a connection that
is to be reused */
long tftp_blksize; /* in bytes, 0 means use default */ long tftp_blksize; /* in bytes, 0 means use default */
curl_off_t filesize; /* size of file to upload, -1 means unknown */ curl_off_t filesize; /* size of file to upload, -1 means unknown */
long low_speed_limit; /* bytes/second */ long low_speed_limit; /* bytes/second */