dovecot-2.2: lib-http: Fixed hangs with urgent requests.

dovecot at dovecot.org dovecot at dovecot.org
Sun Mar 10 17:19:29 EET 2013


details:   http://hg.dovecot.org/dovecot-2.2/rev/d3e3edf8f7eb
changeset: 16005:d3e3edf8f7eb
user:      Timo Sirainen <tss at iki.fi>
date:      Sun Mar 10 17:19:14 2013 +0200
description:
lib-http: Fixed hangs with urgent requests.

diffstat:

 src/lib-http/http-client-connection.c |  24 ++++++++++++++++--------
 src/lib-http/http-client-peer.c       |  26 +++++++++++++++-----------
 2 files changed, 31 insertions(+), 19 deletions(-)

diffs (137 lines):

diff -r 5e63f628e3ca -r d3e3edf8f7eb src/lib-http/http-client-connection.c
--- a/src/lib-http/http-client-connection.c	Sun Mar 10 17:17:47 2013 +0200
+++ b/src/lib-http/http-client-connection.c	Sun Mar 10 17:19:14 2013 +0200
@@ -61,9 +61,13 @@
 
 bool http_client_connection_is_ready(struct http_client_connection *conn)
 {
+	unsigned int pending_count = array_count(&conn->request_wait_list);
+
+	if (conn->pending_request != NULL)
+		pending_count++;
 	return (conn->connected && !conn->output_locked &&
-		!conn->close_indicated &&	array_count(&conn->request_wait_list) <
-			conn->client->set.max_pipelined_requests);
+		!conn->close_indicated &&
+		pending_count < conn->client->set.max_pipelined_requests);
 }
 
 bool http_client_connection_is_idle(struct http_client_connection *conn)
@@ -224,6 +228,7 @@
 {
 	struct http_client_request *req = NULL;
 	const char *error;
+	bool have_pending_requests;
 
 	if (!http_client_connection_is_ready(conn)) {
 		http_client_connection_debug(conn, "Not ready for next request");
@@ -231,8 +236,9 @@
 	}
 
 	/* claim request, but no urgent request can be second in line */
-	req = http_client_peer_claim_request(conn->peer,
-		array_count(&conn->request_wait_list) > 0); 
+	have_pending_requests = array_count(&conn->request_wait_list) > 0 ||
+		conn->pending_request != NULL;
+	req = http_client_peer_claim_request(conn->peer, have_pending_requests);
 	if (req == NULL) {
 		http_client_connection_check_idle(conn);
 		return FALSE;	
@@ -324,10 +330,12 @@
 	http_client_connection_input(&conn->conn);
 }
 
-static void http_client_payload_destroyed(struct http_client_connection *conn)
+static void http_client_payload_destroyed(struct http_client_request *req)
 {
+	struct http_client_connection *conn = req->conn;
+
+	i_assert(conn->pending_request == req);
 	i_assert(conn->incoming_payload != NULL);
-	i_assert(conn->pending_request != NULL);
 	i_assert(conn->conn.io == NULL);
 
 	http_client_connection_debug(conn, "Response payload stream destroyed");
@@ -338,7 +346,7 @@
 
 	conn->incoming_payload = NULL;
 
-	http_client_request_finish(&conn->pending_request);
+	http_client_request_finish(&req);
 	conn->pending_request = NULL;
 
 	/* input stream may have pending input. make sure input handler
@@ -368,7 +376,7 @@
 			i_stream_create_limit(response->payload, (uoff_t)-1);
 		i_stream_set_destroy_callback(response->payload,
 					      http_client_payload_destroyed,
-					      conn);
+					      req);
 		/* the callback may add its own I/O, so we need to remove
 		   our one before calling it */
 		io_remove(&conn->conn.io);
diff -r 5e63f628e3ca -r d3e3edf8f7eb src/lib-http/http-client-peer.c
--- a/src/lib-http/http-client-peer.c	Sun Mar 10 17:17:47 2013 +0200
+++ b/src/lib-http/http-client-peer.c	Sun Mar 10 17:19:14 2013 +0200
@@ -133,14 +133,15 @@
 	unsigned int connecting = 0, closing = 0, min_waiting = UINT_MAX;
 	unsigned int num_urgent, new_connections;
 
-	/* at this point we already know that a request for this peer is pending
-	 */
-	(void)http_client_peer_requests_pending(peer, &num_urgent);
+	if (http_client_peer_requests_pending(peer, &num_urgent) == 0)
+		return FALSE;
 
 	/* find the least busy connection */
 	array_foreach(&peer->conns, conn_idx) {
 		if (http_client_connection_is_ready(*conn_idx)) {
 			unsigned int waiting = array_count(&(*conn_idx)->request_wait_list);
+			if ((*conn_idx)->pending_request != NULL)
+				waiting++;
 			if (waiting < min_waiting) {
 				min_waiting = waiting;
 				conn = *conn_idx;
@@ -315,8 +316,7 @@
 
 	if (!exists)
 		array_append(&peer->hosts, &host, 1);
-	if (exists || array_count(&peer->hosts) > 1)
-		(void)http_client_peer_next_request(peer);
+	http_client_peer_handle_requests(peer);
 }
 
 struct http_client_request *
@@ -340,9 +340,14 @@
 {
 	struct http_client_host *const *host;
 
+	i_assert(array_count(&peer->conns) > 0);
+
 	http_client_peer_debug(peer, "Failed to make connection");
 
 	if (array_count(&peer->conns) == 1) {
+		/* this was the only/last connection and connecting to it
+		   failed. a second connect will probably also fail, so just
+		   abort all requests. */
 		array_foreach(&peer->hosts, host) {
 			http_client_host_connection_failure(*host, &peer->addr);
 		}
@@ -359,12 +364,11 @@
 	http_client_peer_debug(peer, "Lost a connection (%d connections left)",
 		array_count(&peer->conns));
 
-	if (array_count(&peer->conns) == 0) {
-		if (!http_client_peer_next_request(peer)) {
-			if (http_client_peer_requests_pending(peer, &num_urgent) == 0)
-				http_client_peer_free(&peer);
-		}
-	}
+	/* if there are pending requests, create a new connection for them. */
+	http_client_peer_handle_requests(peer);
+	if (array_count(&peer->conns) == 0 &&
+	    http_client_peer_requests_pending(peer, &num_urgent) == 0)
+		http_client_peer_free(&peer);
 }
 
 unsigned int http_client_peer_idle_connections(struct http_client_peer *peer)


More information about the dovecot-cvs mailing list