dovecot-2.0-sslstream: dsync: If some uid/modseq changes couldn'...

dovecot at dovecot.org dovecot at dovecot.org
Sat Feb 13 02:56:35 EET 2010


details:   http://hg.dovecot.org/dovecot-2.0-sslstream/rev/9f2e8d230bd5
changeset: 10369:9f2e8d230bd5
user:      Timo Sirainen <tss at iki.fi>
date:      Wed Nov 18 19:58:37 2009 -0500
description:
dsync: If some uid/modseq changes couldn't be done, exit with different value.

diffstat:

9 files changed, 111 insertions(+), 27 deletions(-)
src/dsync/dsync-brain.c            |    6 ++
src/dsync/dsync-brain.h            |    2 
src/dsync/dsync-proxy-client.c     |   14 +++++-
src/dsync/dsync-proxy-server-cmd.c |   10 ++++
src/dsync/dsync-worker-local.c     |   76 +++++++++++++++++++++++++++---------
src/dsync/dsync-worker-private.h   |    1 
src/dsync/dsync-worker.c           |    5 ++
src/dsync/dsync-worker.h           |    3 +
src/dsync/dsync.c                  |   21 +++++++--

diffs (truncated from 305 to 300 lines):

diff -r 75d3d4374dda -r 9f2e8d230bd5 src/dsync/dsync-brain.c
--- a/src/dsync/dsync-brain.c	Wed Nov 18 19:58:07 2009 -0500
+++ b/src/dsync/dsync-brain.c	Wed Nov 18 19:58:37 2009 -0500
@@ -614,3 +614,9 @@ void dsync_brain_sync_all(struct dsync_b
 		i_assert(brain->state != old_state);
 	}
 }
+
+bool dsync_brain_has_unexpected_changes(struct dsync_brain *brain)
+{
+	return dsync_worker_has_unexpected_changes(brain->src_worker) ||
+		dsync_worker_has_unexpected_changes(brain->dest_worker);
+}
diff -r 75d3d4374dda -r 9f2e8d230bd5 src/dsync/dsync-brain.h
--- a/src/dsync/dsync-brain.h	Wed Nov 18 19:58:07 2009 -0500
+++ b/src/dsync/dsync-brain.h	Wed Nov 18 19:58:37 2009 -0500
@@ -17,4 +17,6 @@ void dsync_brain_sync(struct dsync_brain
 void dsync_brain_sync(struct dsync_brain *brain);
 void dsync_brain_sync_all(struct dsync_brain *brain);
 
+bool dsync_brain_has_unexpected_changes(struct dsync_brain *brain);
+
 #endif
diff -r 75d3d4374dda -r 9f2e8d230bd5 src/dsync/dsync-proxy-client.c
--- a/src/dsync/dsync-proxy-client.c	Wed Nov 18 19:58:07 2009 -0500
+++ b/src/dsync/dsync-proxy-client.c	Wed Nov 18 19:58:37 2009 -0500
@@ -196,10 +196,18 @@ proxy_client_worker_next_msg_get(struct 
 }
 
 static void
-proxy_client_worker_next_finish(const struct proxy_client_request *request,
+proxy_client_worker_next_finish(struct proxy_client_dsync_worker *worker,
+				const struct proxy_client_request *request,
 				const char *line)
 {
-	request->callback.finish(line[0] == '1', request->context);
+	bool success = TRUE;
+
+	if (strcmp(line, "changes") == 0)
+		worker->worker.unexpected_changes = TRUE;
+	else if (strcmp(line, "ok") != 0)
+		success = FALSE;
+		
+	request->callback.finish(success, request->context);
 }
 
 static bool
@@ -229,7 +237,7 @@ proxy_client_worker_next_reply(struct pr
 		break;
 	case PROXY_CLIENT_REQUEST_TYPE_FINISH:
 		worker->finished = TRUE;
-		proxy_client_worker_next_finish(&request, line);
+		proxy_client_worker_next_finish(worker, &request, line);
 		break;
 	}
 	return ret;
diff -r 75d3d4374dda -r 9f2e8d230bd5 src/dsync/dsync-proxy-server-cmd.c
--- a/src/dsync/dsync-proxy-server-cmd.c	Wed Nov 18 19:58:07 2009 -0500
+++ b/src/dsync/dsync-proxy-server-cmd.c	Wed Nov 18 19:58:37 2009 -0500
@@ -503,9 +503,17 @@ static void cmd_finish_callback(bool suc
 static void cmd_finish_callback(bool success, void *context)
 {
 	struct dsync_proxy_server *server = context;
+	const char *reply;
+
+	if (!success)
+		reply = "fail\n";
+	else if (dsync_worker_has_unexpected_changes(server->worker))
+		reply = "changes\n";
+	else
+		reply = "ok\n";
 
 	server->finished = TRUE;
-	o_stream_send_str(server->output, success ? "1\n" : "0\n");
+	o_stream_send_str(server->output, reply);
 }
 
 static int
diff -r 75d3d4374dda -r 9f2e8d230bd5 src/dsync/dsync-worker-local.c
--- a/src/dsync/dsync-worker-local.c	Wed Nov 18 19:58:07 2009 -0500
+++ b/src/dsync/dsync-worker-local.c	Wed Nov 18 19:58:37 2009 -0500
@@ -77,6 +77,8 @@ struct local_dsync_worker {
 	struct mailbox *selected_box;
 	struct mail *mail, *ext_mail;
 
+	ARRAY_TYPE(uint32_t) saved_uids;
+
 	mailbox_guid_t get_mailbox;
 	struct mail *get_mail;
 
@@ -133,6 +135,7 @@ dsync_worker_init_local(struct mail_user
 	worker->mailbox_hash =
 		hash_table_create(default_pool, pool, 0,
 				  mailbox_guid_hash, mailbox_guid_cmp);
+	i_array_init(&worker->saved_uids, 128);
 	return &worker->worker;
 }
 
@@ -150,6 +153,7 @@ static void local_worker_deinit(struct d
 		hash_table_destroy(&worker->mailbox_changes_hash);
 	if (worker->subscription_changes_hash != NULL)
 		hash_table_destroy(&worker->subscription_changes_hash);
+	array_free(&worker->saved_uids);
 	pool_unref(&worker->pool);
 }
 
@@ -1013,28 +1017,60 @@ local_worker_rename_mailbox(struct dsync
 	}
 }
 
+static bool
+has_expected_save_uids(struct local_dsync_worker *worker,
+		       const struct mail_transaction_commit_changes *changes)
+{
+	struct seq_range_iter iter;
+	const uint32_t *expected_uids;
+	uint32_t uid;
+	unsigned int i, n, expected_count;
+
+	expected_uids = array_get(&worker->saved_uids, &expected_count);
+	seq_range_array_iter_init(&iter, &changes->saved_uids); i = n = 0;
+	while (seq_range_array_iter_nth(&iter, n++, &uid)) {
+		if (i == expected_count || uid != expected_uids[i++])
+			return FALSE;
+	}
+	return i == expected_count;
+}
+
 static void local_worker_mailbox_close(struct local_dsync_worker *worker)
 {
 	struct mailbox_transaction_context *trans, *ext_trans;
+	struct mail_transaction_commit_changes changes;
 
 	i_assert(worker->save_input == NULL);
 
-	if (worker->selected_box != NULL) {
-		trans = worker->mail->transaction;
-		ext_trans = worker->ext_mail->transaction;
-		mail_free(&worker->mail);
-		mail_free(&worker->ext_mail);
-		if (mailbox_transaction_commit(&ext_trans) < 0)
-			dsync_worker_set_failure(&worker->worker);
-		if (mailbox_transaction_commit(&trans) < 0 ||
-		    mailbox_sync(worker->selected_box,
-				 MAILBOX_SYNC_FLAG_FULL_WRITE, 0, NULL) < 0)
-			dsync_worker_set_failure(&worker->worker);
-
-		mailbox_close(&worker->selected_box);
-	}
 	memset(&worker->selected_box_guid, 0,
 	       sizeof(worker->selected_box_guid));
+
+	if (worker->selected_box == NULL)
+		return;
+
+	trans = worker->mail->transaction;
+	ext_trans = worker->ext_mail->transaction;
+	mail_free(&worker->mail);
+	mail_free(&worker->ext_mail);
+
+	/* all saves and copies go to ext_trans */
+	if (mailbox_transaction_commit_get_changes(&ext_trans, &changes) < 0)
+		dsync_worker_set_failure(&worker->worker);
+	else {
+		if (changes.ignored_uid_changes != 0 ||
+		    changes.ignored_modseq_changes != 0 ||
+		    !has_expected_save_uids(worker, &changes))
+			worker->worker.unexpected_changes = TRUE;
+		pool_unref(&changes.pool);
+	}
+	array_clear(&worker->saved_uids);
+
+	if (mailbox_transaction_commit(&trans) < 0 ||
+	    mailbox_sync(worker->selected_box,
+			 MAILBOX_SYNC_FLAG_FULL_WRITE, 0, NULL) < 0)
+		dsync_worker_set_failure(&worker->worker);
+
+	mailbox_close(&worker->selected_box);
 }
 
 static void
@@ -1173,11 +1209,14 @@ static void local_worker_msg_expunge(str
 }
 
 static void
-local_worker_msg_save_set_metadata(struct mailbox *box,
+local_worker_msg_save_set_metadata(struct local_dsync_worker *worker,
+				   struct mailbox *box,
 				   struct mail_save_context *save_ctx,
 				   const struct dsync_message *msg)
 {
 	struct mail_keywords *keywords;
+
+	i_assert(msg->uid != 0);
 
 	if (msg->modseq > 1)
 		(void)mailbox_enable(box, MAILBOX_FEATURE_CONDSTORE);
@@ -1190,6 +1229,8 @@ local_worker_msg_save_set_metadata(struc
 	mailbox_save_set_uid(save_ctx, msg->uid);
 	mailbox_save_set_save_date(save_ctx, msg->save_date);
 	mailbox_save_set_min_modseq(save_ctx, msg->modseq);
+
+	array_append(&worker->saved_uids, &msg->uid, 1);
 }
 
 static void
@@ -1217,7 +1258,7 @@ local_worker_msg_copy(struct dsync_worke
 		ret = -1;
 	else {
 		save_ctx = mailbox_save_alloc(worker->ext_mail->transaction);
-		local_worker_msg_save_set_metadata(worker->mail->box,
+		local_worker_msg_save_set_metadata(worker, worker->mail->box,
 						   save_ctx, dest_msg);
 		ret = mailbox_copy(&save_ctx, src_mail);
 	}
@@ -1290,7 +1331,8 @@ local_worker_msg_save(struct dsync_worke
 
 	save_ctx = mailbox_save_alloc(worker->ext_mail->transaction);
 	mailbox_save_set_guid(save_ctx, msg->guid);
-	local_worker_msg_save_set_metadata(worker->mail->box, save_ctx, msg);
+	local_worker_msg_save_set_metadata(worker, worker->mail->box,
+					   save_ctx, msg);
 	mailbox_save_set_pop3_uidl(save_ctx, data->pop3_uidl);
 
 	mailbox_save_set_received_date(save_ctx, data->received_date, 0);
diff -r 75d3d4374dda -r 9f2e8d230bd5 src/dsync/dsync-worker-private.h
--- a/src/dsync/dsync-worker-private.h	Wed Nov 18 19:58:07 2009 -0500
+++ b/src/dsync/dsync-worker-private.h	Wed Nov 18 19:58:37 2009 -0500
@@ -76,6 +76,7 @@ struct dsync_worker {
 
 	unsigned int readonly:1;
 	unsigned int failed:1;
+	unsigned int unexpected_changes:1;
 };
 
 struct dsync_worker_mailbox_iter {
diff -r 75d3d4374dda -r 9f2e8d230bd5 src/dsync/dsync-worker.c
--- a/src/dsync/dsync-worker.c	Wed Nov 18 19:58:07 2009 -0500
+++ b/src/dsync/dsync-worker.c	Wed Nov 18 19:58:37 2009 -0500
@@ -242,3 +242,8 @@ bool dsync_worker_has_failed(struct dsyn
 {
 	return worker->failed;
 }
+
+bool dsync_worker_has_unexpected_changes(struct dsync_worker *worker)
+{
+	return worker->unexpected_changes;
+}
diff -r 75d3d4374dda -r 9f2e8d230bd5 src/dsync/dsync-worker.h
--- a/src/dsync/dsync-worker.h	Wed Nov 18 19:58:07 2009 -0500
+++ b/src/dsync/dsync-worker.h	Wed Nov 18 19:58:37 2009 -0500
@@ -147,5 +147,8 @@ void dsync_worker_finish(struct dsync_wo
 
 /* Returns TRUE if some commands have failed. */
 bool dsync_worker_has_failed(struct dsync_worker *worker);
+/* Returns TRUE if some UID or modseq changes didn't get assigned as
+   requested. */
+bool dsync_worker_has_unexpected_changes(struct dsync_worker *worker);
 
 #endif
diff -r 75d3d4374dda -r 9f2e8d230bd5 src/dsync/dsync.c
--- a/src/dsync/dsync.c	Wed Nov 18 19:58:07 2009 -0500
+++ b/src/dsync/dsync.c	Wed Nov 18 19:58:37 2009 -0500
@@ -84,7 +84,7 @@ int main(int argc, char *argv[])
 	struct dsync_worker *worker1, *worker2;
 	const char *error, *username, *mailbox = NULL, *mirror_cmd = NULL;
 	const char *convert_location = NULL;
-	bool dsync_server = FALSE, readonly = FALSE;
+	bool dsync_server = FALSE, readonly = FALSE, unexpected_changes = FALSE;
 	char alt_hierarchy_char = '_';
 	int c, ret, fd_in = STDIN_FILENO, fd_out = STDOUT_FILENO;
 
@@ -207,10 +207,13 @@ int main(int argc, char *argv[])
 		master_service_run(master_service, dsync_connected);
 	}
 
-	if (brain != NULL)
+	if (brain == NULL)
+		ret = 0;
+	else {
+		if (dsync_brain_has_unexpected_changes(brain))
+			unexpected_changes = TRUE;
 		ret = dsync_brain_deinit(&brain);
-	else
-		ret = 0;
+	}
 	if (server != NULL)
 		dsync_proxy_server_deinit(&server);
 
@@ -223,7 +226,13 @@ int main(int argc, char *argv[])
 		mail_user_unref(&mail_user2);
 	mail_storage_service_user_free(&service_user);
 
+	if (unexpected_changes &&
+	    (brain_flags & DSYNC_BRAIN_FLAG_VERBOSE) != 0) {
+		i_info("Mailbox changes caused a desync. "
+		       "You might want to run dsync again.");
+	}
+
 	mail_storage_service_deinit(&storage_service);


More information about the dovecot-cvs mailing list