]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
http-client: Improved handing of delayed request errors.
authorStephan Bosch <stephan@rename-it.nl>
Fri, 22 Nov 2013 20:08:20 +0000 (22:08 +0200)
committerStephan Bosch <stephan@rename-it.nl>
Fri, 22 Nov 2013 20:08:20 +0000 (22:08 +0200)
Originally each request would have its own zero timeout, but now only one
timeout is put in the host object.

src/lib-http/http-client-host.c
src/lib-http/http-client-private.h
src/lib-http/http-client-request.c

index 1dbf2cd839c1a34c8c197c5d24e6e63905fa801d..76ee246096df4a2156ae2ad94dbeea8d0dc45b27 100644 (file)
@@ -205,7 +205,7 @@ void http_client_host_free(struct http_client_host **_host)
 {
        struct http_client_host *host = *_host;
        struct http_client_queue *const *queue_idx;
-       struct http_client_request *req, *const *reqp;
+       struct http_client_request *req, *const *req_idx;
        const char *hostname = host->name;
 
        http_client_host_debug(host, "Host destroy");
@@ -223,30 +223,73 @@ void http_client_host_free(struct http_client_host **_host)
        array_free(&host->queues);
 
        while (array_count(&host->delayed_failing_requests) > 0) {
-               reqp = array_idx(&host->delayed_failing_requests, 0);
-               req = *reqp;
+               req_idx = array_idx(&host->delayed_failing_requests, 0);
+               req = *req_idx;
 
                i_assert(req->refcount == 1);
-               http_client_request_unref(&req);
+               http_client_request_error_delayed(&req);
        }
        array_free(&host->delayed_failing_requests);
 
+       if (host->to_failing_requests != NULL)
+               timeout_remove(&host->to_failing_requests);
+
        i_free(host->ips);
        i_free(host->name);
        i_free(host);
 }
 
+static void
+http_client_host_handle_request_errors(struct http_client_host *host)
+{              
+       timeout_remove(&host->to_failing_requests);
+
+       while (array_count(&host->delayed_failing_requests) > 0) {
+               struct http_client_request *const *req_idx =
+                       array_idx(&host->delayed_failing_requests, 0);
+               struct http_client_request *req = *req_idx;
+
+               i_assert(req->refcount == 1);
+               http_client_request_error_delayed(&req);
+       }
+       array_clear(&host->delayed_failing_requests);
+}
+
+void http_client_host_delay_request_error(struct http_client_host *host,
+       struct http_client_request *req)
+{
+       if (host->to_failing_requests == NULL) {
+               host->to_failing_requests = timeout_add_short(0,
+                       http_client_host_handle_request_errors, host);
+       }
+       array_append(&host->delayed_failing_requests, &req, 1);
+}
+
+void http_client_host_remove_request_error(struct http_client_host *host,
+       struct http_client_request *req)
+{
+       struct http_client_request *const *reqs;
+       unsigned int i, count;
+
+       reqs = array_get(&host->delayed_failing_requests, &count);
+       for (i = 0; i < count; i++) {
+               if (reqs[i] == req) {
+                       array_delete(&host->delayed_failing_requests, i, 1);
+                       return;
+               }
+       }
+}
+
 void http_client_host_switch_ioloop(struct http_client_host *host)
 {
        struct http_client_queue *const *queue_idx;
-       struct http_client_request *const *req_idx;
 
        if (host->dns_lookup != NULL)
                dns_lookup_switch_ioloop(host->dns_lookup);
        array_foreach(&host->queues, queue_idx)
                http_client_queue_switch_ioloop(*queue_idx);
-       array_foreach(&host->delayed_failing_requests, req_idx) {
-               (*req_idx)->to_delayed_error =
-                       io_loop_move_timeout(&(*req_idx)->to_delayed_error);
+       if (host->to_failing_requests != NULL) {
+               host->to_failing_requests =
+                       io_loop_move_timeout(&host->to_failing_requests);
        }
 }
index 872cc18db08b8b50a5f395f262ddfe812138ab56..d13d5886e6b7d7c82a5c2678e0c7d753215ad14e 100644 (file)
@@ -75,7 +75,6 @@ struct http_client_request {
 
        unsigned int delayed_error_status;
        const char *delayed_error;
-       struct timeout *to_delayed_error;
 
        http_client_request_callback_t *callback;
        void *context;
@@ -200,6 +199,7 @@ struct http_client_host {
 
        /* list of requests in this host that are waiting for ioloop */
        ARRAY(struct http_client_request *) delayed_failing_requests;
+       struct timeout *to_failing_requests;
 
        /* requests are managed on a per-port basis */
        ARRAY_TYPE(http_client_queue) queues;
@@ -247,6 +247,7 @@ void http_client_request_retry_response(struct http_client_request *req,
        struct http_response *response);
 void http_client_request_send_error(struct http_client_request *req,
                               unsigned int status, const char *error);
+void http_client_request_error_delayed(struct http_client_request **_req);
 void http_client_request_error(struct http_client_request *req,
        unsigned int status, const char *error);
 void http_client_request_redirect(struct http_client_request *req,
@@ -330,6 +331,10 @@ http_client_host_get(struct http_client *client,
 void http_client_host_free(struct http_client_host **_host);
 void http_client_host_submit_request(struct http_client_host *host,
        struct http_client_request *req);
+void http_client_host_delay_request_error(struct http_client_host *host,
+       struct http_client_request *req);
+void http_client_host_remove_request_error(struct http_client_host *host,
+       struct http_client_request *req);
 void http_client_host_switch_ioloop(struct http_client_host *host);
 
 static inline const char *
index d260a289cbbeabcb5c67e40a32e67d6dec4f4eb4..ee87e651bac1b9aed497909623982a6ac84173c4 100644 (file)
@@ -50,7 +50,6 @@ http_client_request_debug(struct http_client_request *req,
 /*
  * Request
  */
-static void http_client_request_remove_delayed(struct http_client_request *req);
 
 static struct http_client_request *
 http_client_request_new(struct http_client *client, const char *method, 
@@ -166,8 +165,8 @@ void http_client_request_unref(struct http_client_request **_req)
        if (client->pending_requests == 0 && client->ioloop != NULL)
                io_loop_stop(client->ioloop);
 
-       if (req->to_delayed_error != NULL)
-               http_client_request_remove_delayed(req);
+       if (req->delayed_error != NULL)
+               http_client_host_remove_request_error(req->host, req);
        if (req->payload_input != NULL)
                i_stream_unref(&req->payload_input);
        if (req->payload_output != NULL)
@@ -718,30 +717,14 @@ http_client_request_send_error(struct http_client_request *req,
        }
 }
 
-static void http_client_request_remove_delayed(struct http_client_request *req)
+void http_client_request_error_delayed(struct http_client_request **_req)
 {
-       struct http_client_request *const *reqs;
-       unsigned int i, count;
+       struct http_client_request *req = *_req;
 
+       i_assert(req->delayed_error != NULL && req->delayed_error_status != 0);
        http_client_request_send_error(req, req->delayed_error_status,
                                       req->delayed_error);
-
-       timeout_remove(&req->to_delayed_error);
-
-       reqs = array_get(&req->host->delayed_failing_requests, &count);
-       for (i = 0; i < count; i++) {
-               if (reqs[i] == req) {
-                       array_delete(&req->host->delayed_failing_requests, i, 1);
-                       return;
-               }
-       }
-       i_unreached();
-}
-
-static void http_client_request_error_delayed(struct http_client_request *req)
-{
-       http_client_request_remove_delayed(req);
-       http_client_request_unref(&req);
+       http_client_request_unref(_req);
 }
 
 void http_client_request_error(struct http_client_request *req,
@@ -754,9 +737,7 @@ void http_client_request_error(struct http_client_request *req,
                i_assert(req->delayed_error == NULL);
                req->delayed_error = p_strdup(req->pool, error);
                req->delayed_error_status = status;
-               req->to_delayed_error = timeout_add_short(0,
-                       http_client_request_error_delayed, req);
-               array_append(&req->host->delayed_failing_requests, &req, 1);
+               http_client_host_delay_request_error(req->host, req);
        } else {
                http_client_request_send_error(req, status, error);
                http_client_request_unref(&req);