dovecot-2.2: lib-dict: Hide internal ioloop from async commit ca...

dovecot at dovecot.org dovecot at dovecot.org
Wed Aug 20 10:47:32 UTC 2014


details:   http://hg.dovecot.org/dovecot-2.2/rev/a7a5e0737d53
changeset: 17733:a7a5e0737d53
user:      Timo Sirainen <tss at iki.fi>
date:      Wed Aug 20 12:47:10 2014 +0200
description:
lib-dict: Hide internal ioloop from async commit callbacks. (Redis & memcached fix)

diffstat:

 src/lib-dict/dict-memcached-ascii.c |  35 ++++++++++++++++++++++++---------
 src/lib-dict/dict-redis.c           |  38 +++++++++++++++++++++++++-----------
 2 files changed, 51 insertions(+), 22 deletions(-)

diffs (191 lines):

diff -r 4f6a812817c4 -r a7a5e0737d53 src/lib-dict/dict-memcached-ascii.c
--- a/src/lib-dict/dict-memcached-ascii.c	Wed Aug 20 12:36:37 2014 +0200
+++ b/src/lib-dict/dict-memcached-ascii.c	Wed Aug 20 12:47:10 2014 +0200
@@ -56,7 +56,7 @@
 	unsigned int port;
 	unsigned int timeout_msecs;
 
-	struct ioloop *ioloop;
+	struct ioloop *ioloop, *prev_ioloop;
 	struct timeout *to;
 	struct memcached_ascii_connection conn;
 
@@ -66,6 +66,23 @@
 
 static struct connection_list *memcached_ascii_connections;
 
+static void
+memcached_ascii_callback(struct memcached_ascii_dict *dict,
+			 const struct memcached_ascii_dict_reply *reply, int ret)
+{
+	if (reply->callback != NULL) {
+		if (dict->prev_ioloop != NULL) {
+			/* Don't let callback see that we've created our
+			   internal ioloop in case it wants to add some ios
+			   or timeouts. */
+			current_ioloop = dict->prev_ioloop;
+		}
+		reply->callback(ret, reply->context);
+		if (dict->prev_ioloop != NULL)
+			current_ioloop = dict->ioloop;
+	}
+}
+
 static void memcached_ascii_conn_destroy(struct connection *_conn)
 {
 	struct memcached_ascii_connection *conn =
@@ -76,10 +93,8 @@
 	if (conn->dict->ioloop != NULL)
 		io_loop_stop(conn->dict->ioloop);
 
-	array_foreach(&conn->dict->replies, reply) {
-		if (reply->callback != NULL)
-			reply->callback(-1, reply->context);
-	}
+	array_foreach(&conn->dict->replies, reply)
+		memcached_ascii_callback(conn->dict, reply, -1);
 	array_clear(&conn->dict->replies);
 	array_clear(&conn->dict->input_states);
 	conn->reply_bytes_left = 0;
@@ -186,8 +201,7 @@
 	i_assert(count > 0);
 	i_assert(replies[0].reply_count > 0);
 	if (--replies[0].reply_count == 0) {
-		if (replies[0].callback != NULL)
-			replies[0].callback(1, replies[0].context);
+		memcached_ascii_callback(dict, &replies[0], 1);
 		array_delete(&dict->replies, 0, 1);
 	}
 	return 1;
@@ -217,15 +231,16 @@
 
 static int memcached_ascii_input_wait(struct memcached_ascii_dict *dict)
 {
-	struct ioloop *old_ioloop = current_ioloop;
-
+	dict->prev_ioloop = current_ioloop;
 	io_loop_set_current(dict->ioloop);
 	if (dict->to != NULL)
 		dict->to = io_loop_move_timeout(&dict->to);
 	connection_switch_ioloop(&dict->conn.conn);
 	io_loop_run(dict->ioloop);
 
-	io_loop_set_current(old_ioloop);
+	io_loop_set_current(dict->prev_ioloop);
+	dict->prev_ioloop = NULL;
+
 	if (dict->to != NULL)
 		dict->to = io_loop_move_timeout(&dict->to);
 	connection_switch_ioloop(&dict->conn.conn);
diff -r 4f6a812817c4 -r a7a5e0737d53 src/lib-dict/dict-redis.c
--- a/src/lib-dict/dict-redis.c	Wed Aug 20 12:36:37 2014 +0200
+++ b/src/lib-dict/dict-redis.c	Wed Aug 20 12:47:10 2014 +0200
@@ -48,7 +48,7 @@
 	unsigned int port;
 	unsigned int timeout_msecs;
 
-	struct ioloop *ioloop;
+	struct ioloop *ioloop, *prev_ioloop;
 	struct redis_connection conn;
 
 	ARRAY(enum redis_input_state) input_states;
@@ -77,6 +77,22 @@
 	array_delete(&dict->input_states, 0, 1);
 }
 
+static void redis_callback(struct redis_dict *dict,
+			   const struct redis_dict_reply *reply, int ret)
+{
+	if (reply->callback != NULL) {
+		if (dict->prev_ioloop != NULL) {
+			/* Don't let callback see that we've created our
+			   internal ioloop in case it wants to add some ios
+			   or timeouts. */
+			current_ioloop = dict->prev_ioloop;
+		}
+		reply->callback(ret, reply->context);
+		if (dict->prev_ioloop != NULL)
+			current_ioloop = dict->ioloop;
+	}
+}
+
 static void redis_conn_destroy(struct connection *_conn)
 {
 	struct redis_connection *conn = (struct redis_connection *)_conn;
@@ -85,10 +101,8 @@
 	conn->dict->connected = FALSE;
 	connection_disconnect(_conn);
 
-	array_foreach(&conn->dict->replies, reply) {
-		if (reply->callback != NULL)
-			reply->callback(-1, reply->context);
-	}
+	array_foreach(&conn->dict->replies, reply)
+		redis_callback(conn->dict, reply, -1);
 	array_clear(&conn->dict->replies);
 	array_clear(&conn->dict->input_states);
 
@@ -98,10 +112,9 @@
 
 static void redis_wait(struct redis_dict *dict)
 {
-	struct ioloop *prev_ioloop = current_ioloop;
-
 	i_assert(dict->ioloop == NULL);
 
+	dict->prev_ioloop = current_ioloop;
 	dict->ioloop = io_loop_create();
 	connection_switch_ioloop(&dict->conn.conn);
 
@@ -109,10 +122,11 @@
 		io_loop_run(dict->ioloop);
 	} while (array_count(&dict->input_states) > 0);
 
-	io_loop_set_current(prev_ioloop);
+	io_loop_set_current(dict->prev_ioloop);
 	connection_switch_ioloop(&dict->conn.conn);
 	io_loop_set_current(dict->ioloop);
 	io_loop_destroy(&dict->ioloop);
+	dict->prev_ioloop = NULL;
 }
 
 static int redis_input_get(struct redis_connection *conn)
@@ -216,8 +230,7 @@
 		reply = array_idx_modifiable(&dict->replies, 0);
 		i_assert(reply->reply_count > 0);
 		if (--reply->reply_count == 0) {
-			if (reply->callback != NULL)
-				reply->callback(1, reply->context);
+			redis_callback(dict, reply, 1);
 			array_delete(&dict->replies, 0, 1);
 			/* if we're running in a dict-ioloop, we're handling a
 			   synchronous commit and need to stop now */
@@ -426,7 +439,6 @@
 {
 	struct timeout *to;
 	const char *cmd;
-	struct ioloop *prev_ioloop = current_ioloop;
 
 	key = redis_dict_get_full_key(dict, key);
 
@@ -435,6 +447,7 @@
 
 	i_assert(dict->ioloop == NULL);
 
+	dict->prev_ioloop = current_ioloop;
 	dict->ioloop = io_loop_create();
 	connection_switch_ioloop(&dict->conn.conn);
 
@@ -464,10 +477,11 @@
 		timeout_remove(&to);
 	}
 
-	io_loop_set_current(prev_ioloop);
+	io_loop_set_current(dict->prev_ioloop);
 	connection_switch_ioloop(&dict->conn.conn);
 	io_loop_set_current(dict->ioloop);
 	io_loop_destroy(&dict->ioloop);
+	dict->prev_ioloop = NULL;
 
 	if (!dict->conn.value_received) {
 		/* we failed in some way. make sure we disconnect since the


More information about the dovecot-cvs mailing list