From: Stephan Bosch Date: Thu, 6 Sep 2018 13:22:30 +0000 (+0200) Subject: lib-http: client: peer: Notify all peers in a peer pool about a successful connection. X-Git-Tag: 2.3.9~1423 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2d27dbc246444f442293e0d526e313b3c66cb401;p=thirdparty%2Fdovecot%2Fcore.git lib-http: client: peer: Notify all peers in a peer pool about a successful connection. This allows peers for which the last connection attempt failed (which was not the last pending attempt in the pool) to try again. This solves a problem that could potentially cause a hang with multiple parallel clients creating serveral new connections at once. --- diff --git a/src/lib-http/http-client-peer.c b/src/lib-http/http-client-peer.c index 94339abcb3..180a9006b1 100644 --- a/src/lib-http/http-client-peer.c +++ b/src/lib-http/http-client-peer.c @@ -24,6 +24,8 @@ static void http_client_peer_shared_connection_failure( struct http_client_peer_shared *pshared); static void +http_client_peer_connection_succeeded_pool(struct http_client_peer *peer); +static void http_client_peer_connection_failed_pool(struct http_client_peer *peer, const char *reason); @@ -219,6 +221,25 @@ http_client_peer_pool_connection_success( array_count(&ppool->conns)); http_client_peer_shared_connection_success(ppool->peer); + + if (array_count(&ppool->pending_conns) > 0) { + /* if there are other connections attempting to connect, wait + for them before notifying other peer objects about the + success (which may be premature). */ + } else { + struct http_client_peer *peer; + + /* this was the only/last connection and connecting to it + succeeded. notify all interested peers in this pool about the + success */ + peer = ppool->peer->peers_list; + while (peer != NULL) { + struct http_client_peer *peer_next = peer->shared_next; + if (peer->ppool == ppool) + http_client_peer_connection_succeeded_pool(peer); + peer = peer_next; + } + } } static void @@ -1207,6 +1228,25 @@ void http_client_peer_connection_failure(struct http_client_peer *peer, array_count(&peer->conns)); http_client_peer_pool_connection_failure(ppool, reason); + + peer->connect_failed = TRUE; +} + +static void +http_client_peer_connection_succeeded_pool(struct http_client_peer *peer) +{ + if (!peer->connect_failed) + return; + peer->connect_failed = FALSE; + + e_debug(peer->event, + "A connection succeeded within our peer pool, " + "so this peer can retry connecting as well if needed " + "(%u connections exist)", array_count(&peer->conns)); + + /* if there are pending requests for this peer, try creating a new + connection for them. if not, this peer will wind itself down. */ + http_client_peer_trigger_request_handler(peer); } static void @@ -1219,6 +1259,8 @@ http_client_peer_connection_failed_pool(struct http_client_peer *peer, "Failed to establish any connection within our peer pool: %s ", reason); + peer->connect_failed = TRUE; + /* failed to make any connection. a second connect will probably also fail, so just try another IP for the hosts(s) or abort all requests if this was the only/last option. */ diff --git a/src/lib-http/http-client-private.h b/src/lib-http/http-client-private.h index eee47cb9fe..130807698c 100644 --- a/src/lib-http/http-client-private.h +++ b/src/lib-http/http-client-private.h @@ -278,6 +278,7 @@ struct http_client_peer { /* zero time-out for consolidating request handling */ struct timeout *to_req_handling; + bool connect_failed:1; /* last connection attempt failed */ bool connect_backoff:1; /* peer is waiting for backoff timout*/ bool disconnected:1; /* peer is already disconnected */ bool handling_requests:1;/* currently running request handler */