dovecot-2.2: dsync: -l parameter locking is now done on the serv...

dovecot at dovecot.org dovecot at dovecot.org
Sat Feb 16 16:47:46 EET 2013


details:   http://hg.dovecot.org/dovecot-2.2/rev/6f024e0289da
changeset: 15782:6f024e0289da
user:      Timo Sirainen <tss at iki.fi>
date:      Sat Feb 16 16:47:40 2013 +0200
description:
dsync: -l parameter locking is now done on the server with "lower" hostname.
This allows running multi-master replication on two servers without two
dsyncs mixing up changes by running at the same time.

diffstat:

 src/doveadm/dsync/doveadm-dsync.c       |   75 +---------------
 src/doveadm/dsync/dsync-brain-private.h |    8 +
 src/doveadm/dsync/dsync-brain.c         |  135 ++++++++++++++++++++++++++++---
 src/doveadm/dsync/dsync-brain.h         |    2 +-
 src/doveadm/dsync/dsync-ibc-stream.c    |   22 ++++-
 src/doveadm/dsync/dsync-ibc.h           |    4 +
 6 files changed, 161 insertions(+), 85 deletions(-)

diffs (truncated from 501 to 300 lines):

diff -r 5a3586ffc644 -r 6f024e0289da src/doveadm/dsync/doveadm-dsync.c
--- a/src/doveadm/dsync/doveadm-dsync.c	Sat Feb 16 16:45:47 2013 +0200
+++ b/src/doveadm/dsync/doveadm-dsync.c	Sat Feb 16 16:47:40 2013 +0200
@@ -30,7 +30,6 @@
 #include <ctype.h>
 #include <sys/wait.h>
 
-#define DSYNC_LOCK_FILENAME ".dovecot-sync.lock"
 #define DSYNC_COMMON_GETOPT_ARGS "+adEfl:m:n:r:Rs:"
 #define DSYNC_REMOTE_CMD_EXIT_WAIT_SECS 30
 
@@ -165,14 +164,12 @@
 }
 
 static const char *const *
-get_ssh_cmd_args(struct dsync_cmd_context *ctx,
-		 const char *host, const char *login, const char *mail_user)
+get_ssh_cmd_args(const char *host, const char *login, const char *mail_user)
 {
 	static struct var_expand_table static_tab[] = {
 		{ 'u', NULL, "user" },
 		{ '\0', NULL, "login" },
 		{ '\0', NULL, "host" },
-		{ '\0', NULL, "lock_timeout" },
 		{ '\0', NULL, NULL }
 	};
 	struct var_expand_table *tab;
@@ -186,7 +183,6 @@
 	tab[0].value = mail_user;
 	tab[1].value = login;
 	tab[2].value = host;
-	tab[3].value = dec2str(ctx->lock_timeout);
 
 	t_array_init(&cmd_args, 8);
 	str = t_str_new(128);
@@ -255,7 +251,7 @@
 
 	/* we'll assume virtual users, so in user at host it really means not to
 	   give ssh a username, but to give dsync -u user parameter. */
-	*cmd_args_r = get_ssh_cmd_args(ctx, host, "", user);
+	*cmd_args_r = get_ssh_cmd_args(host, "", user);
 	return TRUE;
 }
 
@@ -371,8 +367,7 @@
 }
 
 static const char *const *
-parse_ssh_location(struct dsync_cmd_context *ctx,
-		   const char *location, const char *username)
+parse_ssh_location(const char *location, const char *username)
 {
 	const char *host, *login;
 
@@ -383,7 +378,7 @@
 		host = location;
 		login = "";
 	}
-	return get_ssh_cmd_args(ctx, host, login, username);
+	return get_ssh_cmd_args(host, login, username);
 }
 
 static struct dsync_ibc *
@@ -404,8 +399,9 @@
 }
 
 static int
-cmd_dsync_run_real(struct dsync_cmd_context *ctx, struct mail_user *user)
+cmd_dsync_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user)
 {
+	struct dsync_cmd_context *ctx = (struct dsync_cmd_context *)_ctx;
 	struct dsync_ibc *ibc, *ibc2 = NULL;
 	struct dsync_brain *brain;
 	struct mail_namespace *sync_ns = NULL;
@@ -445,6 +441,7 @@
 		brain_flags |= DSYNC_BRAIN_FLAG_DEBUG;
 	brain = dsync_brain_master_init(user, ibc, sync_ns, ctx->mailbox,
 					ctx->sync_type, brain_flags,
+					ctx->lock_timeout,
 					ctx->state_input == NULL ? "" :
 					ctx->state_input);
 
@@ -490,62 +487,6 @@
 	return ret;
 }
 
-static int dsync_lock(struct mail_user *user, unsigned int lock_timeout,
-		      const char **path_r, struct file_lock **lock_r)
-{
-	const char *home, *path;
-	int ret, fd;
-
-	if ((ret = mail_user_get_home(user, &home)) < 0) {
-		i_error("Couldn't look up user's home dir");
-		return -1;
-	}
-	if (ret == 0) {
-		i_error("User has no home directory");
-		return -1;
-	}
-
-	path = t_strconcat(home, "/"DSYNC_LOCK_FILENAME, NULL);
-	fd = creat(path, 0600);
-	if (fd == -1) {
-		i_error("Couldn't create lock %s: %m", path);
-		return -1;
-	}
-
-	if (file_wait_lock(fd, path, F_WRLCK, FILE_LOCK_METHOD_FCNTL,
-			   lock_timeout, lock_r) <= 0) {
-		i_error("Couldn't lock %s: %m", path);
-		(void)close(fd);
-		return -1;
-	}
-	*path_r = path;
-	return fd;
-}
-
-static int
-cmd_dsync_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user)
-{
-	struct dsync_cmd_context *ctx = (struct dsync_cmd_context *)_ctx;
-	const char *lock_path;
-	struct file_lock *lock;
-	int lock_fd, ret;
-
-	if (!ctx->lock)
-		return cmd_dsync_run_real(ctx, user);
-
-	lock_fd = dsync_lock(user, ctx->lock_timeout, &lock_path, &lock);
-	if (lock_fd == -1) {
-		_ctx->exit_code = EX_TEMPFAIL;
-		return -1;
-	} else {
-		ret = cmd_dsync_run_real(ctx, user);
-		file_lock_free(&lock);
-		if (close(lock_fd) < 0)
-			i_error("close(%s) failed: %m", lock_path);
-		return ret;
-	}
-}
-
 static int cmd_dsync_prerun(struct doveadm_mail_cmd_context *_ctx,
 			    struct mail_storage_service_user *service_user,
 			    const char **error_r)
@@ -599,7 +540,7 @@
 			ctx->remote_name = NULL;
 		}
 		remote_cmd_args = ctx->remote_name == NULL ? NULL :
-			parse_ssh_location(ctx, ctx->remote_name,
+			parse_ssh_location(ctx->remote_name,
 					   _ctx->cur_username);
 	}
 
diff -r 5a3586ffc644 -r 6f024e0289da src/doveadm/dsync/dsync-brain-private.h
--- a/src/doveadm/dsync/dsync-brain-private.h	Sat Feb 16 16:45:47 2013 +0200
+++ b/src/doveadm/dsync/dsync-brain-private.h	Sat Feb 16 16:47:40 2013 +0200
@@ -6,9 +6,12 @@
 #include "dsync-mailbox.h"
 #include "dsync-mailbox-state.h"
 
+#define DSYNC_LOCK_FILENAME ".dovecot-sync.lock"
+
 struct dsync_mailbox_tree_sync_change;
 
 enum dsync_state {
+	DSYNC_STATE_MASTER_RECV_HANDSHAKE,
 	DSYNC_STATE_SLAVE_RECV_HANDSHAKE,
 	/* if sync_type=STATE, the master brain knows the saved "last common
 	   mailbox state". this state is sent to the slave. */
@@ -49,6 +52,11 @@
 	char *sync_box;
 	enum dsync_brain_sync_type sync_type;
 
+	unsigned int lock_timeout;
+	int lock_fd;
+	const char *lock_path;
+	struct file_lock *lock;
+
 	char hierarchy_sep;
 	struct dsync_mailbox_tree *local_mailbox_tree;
 	struct dsync_mailbox_tree *remote_mailbox_tree;
diff -r 5a3586ffc644 -r 6f024e0289da src/doveadm/dsync/dsync-brain.c
--- a/src/doveadm/dsync/dsync-brain.c	Sat Feb 16 16:45:47 2013 +0200
+++ b/src/doveadm/dsync/dsync-brain.c	Sat Feb 16 16:47:40 2013 +0200
@@ -3,11 +3,14 @@
 #include "lib.h"
 #include "array.h"
 #include "hash.h"
+#include "hostpid.h"
 #include "mail-namespace.h"
 #include "dsync-mailbox-tree.h"
 #include "dsync-ibc.h"
 #include "dsync-brain-private.h"
 
+#include <sys/stat.h>
+
 static const char *dsync_state_names[DSYNC_STATE_DONE+1] = {
 	"recv_handshake",
 	"send_last_common",
@@ -61,6 +64,7 @@
 	brain->user = user;
 	brain->ibc = ibc;
 	brain->sync_type = DSYNC_BRAIN_SYNC_TYPE_UNKNOWN;
+	brain->lock_fd = -1;
 	hash_table_create(&brain->mailbox_states, pool, 0,
 			  guid_128_hash, guid_128_cmp);
 	p_array_init(&brain->remote_mailbox_states, pool, 64);
@@ -83,7 +87,7 @@
 dsync_brain_master_init(struct mail_user *user, struct dsync_ibc *ibc,
 			struct mail_namespace *sync_ns, const char *sync_box,
 			enum dsync_brain_sync_type sync_type,
-			enum dsync_brain_flags flags,
+			enum dsync_brain_flags flags, unsigned int lock_timeout,
 			const char *state)
 {
 	struct dsync_ibc_settings ibc_set;
@@ -98,29 +102,26 @@
 	if (sync_ns != NULL)
 		brain->sync_ns = sync_ns;
 	brain->sync_box = p_strdup(brain->pool, sync_box);
+	brain->lock_timeout = lock_timeout;
 	brain->master_brain = TRUE;
 	dsync_brain_set_flags(brain, flags);
 
-	brain->state = DSYNC_STATE_SEND_MAILBOX_TREE;
-	if (sync_type == DSYNC_BRAIN_SYNC_TYPE_STATE) {
-		if (dsync_mailbox_states_import(brain->mailbox_states,
-						brain->pool, state,
-						&error) < 0) {
-			hash_table_clear(brain->mailbox_states, FALSE);
-			i_error("Saved sync state is invalid, "
-				"falling back to full sync: %s", error);
-			brain->sync_type = sync_type =
-				DSYNC_BRAIN_SYNC_TYPE_FULL;
-		} else {
-			brain->state = DSYNC_STATE_MASTER_SEND_LAST_COMMON;
-		}
+	if (sync_type == DSYNC_BRAIN_SYNC_TYPE_STATE &&
+	    dsync_mailbox_states_import(brain->mailbox_states,
+					brain->pool, state, &error) < 0) {
+		hash_table_clear(brain->mailbox_states, FALSE);
+		i_error("Saved sync state is invalid, "
+			"falling back to full sync: %s", error);
+		brain->sync_type = sync_type = DSYNC_BRAIN_SYNC_TYPE_FULL;
 	}
 	dsync_brain_mailbox_trees_init(brain);
 
 	memset(&ibc_set, 0, sizeof(ibc_set));
+	ibc_set.hostname = my_hostname;
 	ibc_set.sync_ns_prefix = sync_ns == NULL ? NULL : sync_ns->prefix;
 	ibc_set.sync_box = sync_box;
 	ibc_set.sync_type = sync_type;
+	ibc_set.lock_timeout = lock_timeout;
 	/* reverse the backup direction for the slave */
 	ibc_set.brain_flags = flags & ~(DSYNC_BRAIN_FLAG_BACKUP_SEND |
 					DSYNC_BRAIN_FLAG_BACKUP_RECV);
@@ -131,17 +132,23 @@
 	dsync_ibc_send_handshake(ibc, &ibc_set);
 
 	dsync_ibc_set_io_callback(ibc, dsync_brain_run_io, brain);
+	brain->state = DSYNC_STATE_MASTER_RECV_HANDSHAKE;
 	return brain;
 }
 
 struct dsync_brain *
 dsync_brain_slave_init(struct mail_user *user, struct dsync_ibc *ibc)
 {
+	struct dsync_ibc_settings ibc_set;
 	struct dsync_brain *brain;
 
 	brain = dsync_brain_common_init(user, ibc);
 	brain->state = DSYNC_STATE_SLAVE_RECV_HANDSHAKE;
 
+	memset(&ibc_set, 0, sizeof(ibc_set));
+	ibc_set.hostname = my_hostname;
+	dsync_ibc_send_handshake(ibc, &ibc_set);
+
 	dsync_ibc_set_io_callback(ibc, dsync_brain_run_io, brain);
 	return brain;
 }
@@ -166,11 +173,102 @@
 		hash_table_iterate_deinit(&brain->mailbox_states_iter);
 	hash_table_destroy(&brain->mailbox_states);
 
+	if (brain->lock_fd != -1) {
+		/* unlink the lock file before it gets unlocked */
+		if (unlink(brain->lock_path) < 0)
+			i_error("unlink(%s) failed: %m", brain->lock_path);
+		file_lock_free(&brain->lock);
+		i_close_fd(&brain->lock_fd);
+	}
+
 	ret = brain->failed ? -1 : 0;
 	pool_unref(&brain->pool);
 	return ret;
 }
 
+static int
+dsync_brain_lock(struct dsync_brain *brain, const char *remote_hostname)


More information about the dovecot-cvs mailing list