dovecot-2.0: director: Lots of fixes. It should be pretty stable...

dovecot at dovecot.org dovecot at dovecot.org
Thu Jun 24 22:29:34 EEST 2010


details:   http://hg.dovecot.org/dovecot-2.0/rev/a07aa85f68c9
changeset: 11629:a07aa85f68c9
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Jun 24 20:29:27 2010 +0100
description:
director: Lots of fixes. It should be pretty stable now.

diffstat:

 src/director/auth-connection.c     |   18 +-
 src/director/auth-connection.h     |    2 +-
 src/director/director-connection.c |  375 +++++++++++++++++++++++++++++++----------
 src/director/director-connection.h |   12 +-
 src/director/director-host.h       |   11 +-
 src/director/director-request.c    |   32 ++-
 src/director/director-test.c       |   42 ++++-
 src/director/director-test.sh      |   11 +-
 src/director/director.c            |  166 +++++++++++++++++-
 src/director/director.h            |   23 +-
 src/director/doveadm-connection.c  |   14 +-
 src/director/main.c                |    4 +-
 12 files changed, 563 insertions(+), 147 deletions(-)

diffs (truncated from 1420 to 300 lines):

diff -r 7885030184ab -r a07aa85f68c9 src/director/auth-connection.c
--- a/src/director/auth-connection.c	Thu Jun 24 16:27:20 2010 +0100
+++ b/src/director/auth-connection.c	Thu Jun 24 20:29:27 2010 +0100
@@ -27,6 +27,8 @@
 
 static struct auth_connection *auth_connections;
 
+static void auth_connection_disconnected(struct auth_connection **conn);
+
 static void auth_connection_input(struct auth_connection *conn)
 {
 	char *line;
@@ -36,13 +38,13 @@
 		return;
 	case -1:
 		/* disconnected */
-		auth_connection_deinit(&conn);
+		auth_connection_disconnected(&conn);
 		return;
 	case -2:
 		/* buffer full */
 		i_error("BUG: Auth server sent us more than %d bytes",
 			(int)AUTH_CLIENT_MAX_LINE_LENGTH);
-		auth_connection_deinit(&conn);
+		auth_connection_disconnected(&conn);
 		return;
 	}
 
@@ -103,12 +105,20 @@
 
 		if (close(conn->fd) < 0)
 			i_error("close(auth connection) failed: %m");
-		conn->callback(NULL, conn->context);
 	}
 	i_free(conn->path);
 	i_free(conn);
 }
 
+static void auth_connection_disconnected(struct auth_connection **_conn)
+{
+	struct auth_connection *conn = *_conn;
+
+	*_conn = NULL;
+	/* notify callback. it should deinit this connection */
+	conn->callback(NULL, conn->context);
+}
+
 void auth_connection_send(struct auth_connection *conn,
 			  const void *data, size_t size)
 {
@@ -122,6 +132,6 @@
 	while (auth_connections != NULL) {
 		struct auth_connection *conn = auth_connections;
 
-		auth_connection_deinit(&conn);
+		auth_connection_disconnected(&conn);
 	}
 }
diff -r 7885030184ab -r a07aa85f68c9 src/director/auth-connection.h
--- a/src/director/auth-connection.h	Thu Jun 24 16:27:20 2010 +0100
+++ b/src/director/auth-connection.h	Thu Jun 24 20:29:27 2010 +0100
@@ -2,7 +2,7 @@
 #define AUTH_CONNECTION_H
 
 /* Called for each input line. This is also called with line=NULL if
-   connection gets disonnected. */
+   connection gets disconnected. */
 typedef void auth_input_callback(const char *line, void *context);
 
 struct auth_connection *auth_connection_init(const char *path);
diff -r 7885030184ab -r a07aa85f68c9 src/director/director-connection.c
--- a/src/director/director-connection.c	Thu Jun 24 16:27:20 2010 +0100
+++ b/src/director/director-connection.c	Thu Jun 24 20:29:27 2010 +0100
@@ -7,6 +7,7 @@
 #include "istream.h"
 #include "ostream.h"
 #include "str.h"
+#include "llist.h"
 #include "master-service.h"
 #include "mail-host.h"
 #include "director.h"
@@ -25,14 +26,20 @@
 #define MAX_INBUF_SIZE 1024
 #define MAX_OUTBUF_SIZE (1024*1024*10)
 #define OUTBUF_FLUSH_THRESHOLD (1024*128)
+/* Max idling time while connecting/handshaking before disconnecting */
+#define DIRECTOR_CONNECTION_INIT_TIMEOUT_MSECS (2*1000)
 /* How long to wait for PONG after PING request */
 #define DIRECTOR_CONNECTION_PING_TIMEOUT_MSECS (2*1000)
 /* How long to wait to send PING when connection is idle */
 #define DIRECTOR_CONNECTION_PING_INTERVAL_MSECS (15*1000)
+/* How long to wait before sending PING while waiting for SYNC reply */
+#define DIRECTOR_CONNECTION_SYNC_TIMEOUT_MSECS 1000
 
 struct director_connection {
+	struct director_connection *prev, *next;
+
 	struct director *dir;
-	const char *name;
+	char *name;
 
 	/* for incoming connections the director host isn't known until
 	   ME-line is received */
@@ -54,9 +61,11 @@
 	unsigned int ignore_host_events:1;
 	unsigned int handshake_sending_hosts:1;
 	unsigned int ping_waiting:1;
+	unsigned int sync_ping:1;
 };
 
 static void director_connection_ping(struct director_connection *conn);
+static void director_connection_disconnected(struct director_connection **conn);
 
 static bool
 director_args_parse_ip_port(struct director_connection *conn,
@@ -102,7 +111,12 @@
 	if (!conn->in)
 		return TRUE;
 
+	i_free(conn->name);
+	conn->name = i_strdup_printf("%s/left", host->name);
 	conn->host = host;
+	/* make sure we don't keep old sequence values across restarts */
+	host->last_seq = 0;
+
 	connect_str = t_strdup_printf("CONNECT\t%s\t%u\n",
 				      net_ip2addr(&host->ip), host->port);
 	/* make sure this is the correct incoming connection */
@@ -135,6 +149,8 @@
 		   one, but before that tell it to connect to the new one.
 		   that message might not reach it, so also send the same
 		   message to right side. */
+		i_warning("Replacing director connection %s with %s",
+			  dir->left->host->name, host->name);
 		director_connection_send(dir->left, connect_str);
 		(void)o_stream_flush(dir->left->output);
 		director_connection_deinit(&dir->left);
@@ -227,6 +243,33 @@
 	return TRUE;
 }
 
+static bool
+director_cmd_user(struct director_connection *conn, const char *const *args)
+{
+	unsigned int username_hash;
+	struct ip_addr ip;
+	struct mail_host *host;
+	struct user *user;
+
+	if (str_array_length(args) != 2 ||
+	    str_to_uint(args[0], &username_hash) < 0 ||
+	    net_addr2ip(args[1], &ip) < 0) {
+		i_error("director(%s): Invalid USER args", conn->name);
+		return FALSE;
+	}
+
+	host = mail_host_lookup(conn->dir->mail_hosts, &ip);
+	if (host == NULL) {
+		/* we probably just removed this host. */
+		return TRUE;
+	}
+
+	if (director_user_refresh(conn->dir, username_hash,
+				  host, ioloop_time, &user))
+		director_update_user(conn->dir, conn->host, user);
+	return TRUE;
+}
+
 static bool director_cmd_director(struct director_connection *conn,
 				  const char *const *args)
 {
@@ -269,7 +312,7 @@
 		hosts = mail_hosts_get(conn->dir->mail_hosts);
 		while (array_count(hosts) > 0) {
 			hostp = array_idx(hosts, 0);
-			director_remove_host(conn->dir, conn->host, *hostp);
+			director_remove_host(conn->dir, NULL, NULL, *hostp);
 		}
 	} else if (!remote_ring_completed && conn->dir->ring_handshaked) {
 		/* ignore whatever remote sends */
@@ -279,8 +322,46 @@
 	return TRUE;
 }
 
+static int
+director_cmd_is_seen(struct director_connection *conn,
+		     const char *const **_args,
+		     struct director_host **host_r)
+{
+	const char *const *args = *_args;
+	struct ip_addr ip;
+	unsigned int port, seq;
+	struct director_host *host;
+
+	if (str_array_length(args) < 3 ||
+	    net_addr2ip(args[0], &ip) < 0 ||
+	    str_to_uint(args[1], &port) < 0 ||
+	    str_to_uint(args[2], &seq) < 0) {
+		i_error("director(%s): Command is missing parameters",
+			conn->name);
+		return -1;
+	}
+	*_args = args + 3;
+
+	host = director_host_lookup(conn->dir, &ip, port);
+	if (host == NULL) {
+		/* director is already gone, but we can't be sure if this
+		   command was sent everywhere. re-send it as if it was from
+		   ourself. */
+		*host_r = NULL;
+	} else {
+		if (seq <= host->last_seq) {
+			/* already seen this */
+			return 1;
+		}
+		*host_r = host;
+		host->last_seq = seq;
+	}
+	return 0;
+}
+
 static bool
-director_cmd_host(struct director_connection *conn, const char *const *args)
+director_cmd_host_int(struct director_connection *conn, const char *const *args,
+		      struct director_host *dir_host)
 {
 	struct mail_host *host;
 	struct ip_addr ip;
@@ -311,17 +392,40 @@
 	if (update) {
 		mail_host_set_vhost_count(conn->dir->mail_hosts,
 					  host, vhost_count);
-		director_update_host(conn->dir, conn->host, host);
+		director_update_host(conn->dir, conn->host, dir_host, host);
 	}
 	return TRUE;
 }
 
 static bool
+director_cmd_host_handshake(struct director_connection *conn,
+			    const char *const *args)
+{
+	return director_cmd_host_int(conn, args, NULL);
+}
+
+static bool
+director_cmd_host(struct director_connection *conn, const char *const *args)
+{
+	struct director_host *dir_host;
+	int ret;
+
+	if ((ret = director_cmd_is_seen(conn, &args, &dir_host)) != 0)
+		return ret > 0;
+	return director_cmd_host_int(conn, args, dir_host);
+}
+
+static bool
 director_cmd_host_remove(struct director_connection *conn,
 			 const char *const *args)
 {
+	struct director_host *dir_host;
 	struct mail_host *host;
 	struct ip_addr ip;
+	int ret;
+
+	if ((ret = director_cmd_is_seen(conn, &args, &dir_host)) != 0)
+		return ret > 0;
 
 	if (str_array_length(args) != 1 ||
 	    net_addr2ip(args[0], &ip) < 0) {
@@ -331,7 +435,7 @@
 
 	host = mail_host_lookup(conn->dir->mail_hosts, &ip);
 	if (host != NULL)
-		director_remove_host(conn->dir, conn->host, host);
+		director_remove_host(conn->dir, conn->host, dir_host, host);
 	return TRUE;
 }
 
@@ -339,18 +443,25 @@
 director_cmd_host_flush(struct director_connection *conn,
 			 const char *const *args)
 {
+	struct director_host *dir_host;
 	struct mail_host *host;
 	struct ip_addr ip;
+	unsigned int seq;
+	int ret;
 
-	if (str_array_length(args) != 1 ||
-	    net_addr2ip(args[0], &ip) < 0) {
+	if ((ret = director_cmd_is_seen(conn, &args, &dir_host)) != 0)
+		return ret > 0;
+
+	if (str_array_length(args) != 2 ||
+	    net_addr2ip(args[0], &ip) < 0 ||
+	    str_to_uint(args[1], &seq) < 0) {
 		i_error("director(%s): Invalid HOST-FLUSH args", conn->name);
 		return FALSE;
 	}


More information about the dovecot-cvs mailing list