From 129596c93692b21d6c6b1313b389774af24c2983 Mon Sep 17 00:00:00 2001 From: Stephan Bosch Date: Fri, 22 Nov 2013 22:08:20 +0200 Subject: [PATCH] http-client: Improved handing of delayed request errors. 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 | 59 ++++++++++++++++++++++++++---- src/lib-http/http-client-private.h | 7 +++- src/lib-http/http-client-request.c | 33 ++++------------- 3 files changed, 64 insertions(+), 35 deletions(-) diff --git a/src/lib-http/http-client-host.c b/src/lib-http/http-client-host.c index 1dbf2cd839..76ee246096 100644 --- a/src/lib-http/http-client-host.c +++ b/src/lib-http/http-client-host.c @@ -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); } } diff --git a/src/lib-http/http-client-private.h b/src/lib-http/http-client-private.h index 872cc18db0..d13d5886e6 100644 --- a/src/lib-http/http-client-private.h +++ b/src/lib-http/http-client-private.h @@ -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 * diff --git a/src/lib-http/http-client-request.c b/src/lib-http/http-client-request.c index d260a289cb..ee87e651ba 100644 --- a/src/lib-http/http-client-request.c +++ b/src/lib-http/http-client-request.c @@ -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); -- 2.47.3