]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-http: client: peer: Notify all peers in a peer pool about a successful connection.
authorStephan Bosch <stephan.bosch@dovecot.fi>
Thu, 6 Sep 2018 13:22:30 +0000 (15:22 +0200)
committerVille Savolainen <ville.savolainen@dovecot.fi>
Fri, 7 Sep 2018 06:18:56 +0000 (09:18 +0300)
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.

src/lib-http/http-client-peer.c
src/lib-http/http-client-private.h

index 94339abcb317efeab44ed8e5b0e2fac559c6c083..180a9006b188cdbbbb87a774430a87ef55bcd582 100644 (file)
@@ -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. */
index eee47cb9fe2c2781edff34c02dff5adbc16b2355..130807698cc1bfd8252e31b794956e4446bf620f 100644 (file)
@@ -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 */