dovecot-2.2: dsync: Fixed unsubscribing from an already deleted ...

dovecot at dovecot.org dovecot at dovecot.org
Mon May 20 17:30:38 EEST 2013


details:   http://hg.dovecot.org/dovecot-2.2/rev/9878986a028d
changeset: 16380:9878986a028d
user:      Timo Sirainen <tss at iki.fi>
date:      Mon May 20 17:30:23 2013 +0300
description:
dsync: Fixed unsubscribing from an already deleted mailbox.

diffstat:

 src/doveadm/dsync/dsync-brain-mailbox-tree.c |  34 +++++++++---
 src/doveadm/dsync/dsync-ibc-stream.c         |  73 ++++++++++++++++-----------
 src/doveadm/dsync/dsync-mailbox-tree-fill.c  |  17 +++++-
 src/doveadm/dsync/dsync-mailbox-tree.c       |   2 +-
 src/doveadm/dsync/dsync-mailbox-tree.h       |  13 +++-
 5 files changed, 96 insertions(+), 43 deletions(-)

diffs (271 lines):

diff -r 4f76d60ba7dd -r 9878986a028d src/doveadm/dsync/dsync-brain-mailbox-tree.c
--- a/src/doveadm/dsync/dsync-brain-mailbox-tree.c	Mon May 20 02:25:26 2013 +0300
+++ b/src/doveadm/dsync/dsync-brain-mailbox-tree.c	Mon May 20 17:30:23 2013 +0300
@@ -371,11 +371,24 @@
 	if (node == NULL)
 		return;
 
-	if (!other_del->delete_mailbox &&
-	    other_del->timestamp <= node->last_renamed_or_created) {
-		/* we don't want to delete this directory, we already have a
-		   newer timestamp for it */
-		return;
+	switch (other_del->type) {
+	case DSYNC_MAILBOX_DELETE_TYPE_MAILBOX:
+		/* mailbox is always deleted */
+		break;
+	case DSYNC_MAILBOX_DELETE_TYPE_DIR:
+		if (other_del->timestamp <= node->last_renamed_or_created) {
+			/* we don't want to delete this directory, we already
+			   have a newer timestamp for it */
+			return;
+		}
+		break;
+	case DSYNC_MAILBOX_DELETE_TYPE_UNSUBSCRIBE:
+		if (other_del->timestamp <= node->last_subscription_change) {
+			/* we don't want to unsubscribe, since we already have
+			   a newer subscription timestamp */
+			return;
+		}
+		break;
 	}
 
 	/* make a node for it in the other mailbox tree */
@@ -384,20 +397,25 @@
 
 	if (!guid_128_is_empty(other_node->mailbox_guid) ||
 	    (other_node->existence == DSYNC_MAILBOX_NODE_EXISTS &&
-	     !other_del->delete_mailbox)) {
+	     other_del->type != DSYNC_MAILBOX_DELETE_TYPE_MAILBOX)) {
 		/* other side has already created a new mailbox or
 		   directory with this name, we can't delete it */
 		return;
 	}
 
 	/* ok, mark the other node deleted */
-	if (other_del->delete_mailbox) {
+	if (other_del->type == DSYNC_MAILBOX_DELETE_TYPE_MAILBOX) {
 		memcpy(other_node->mailbox_guid, node->mailbox_guid,
 		       sizeof(other_node->mailbox_guid));
 	}
 	i_assert(other_node->ns == NULL || other_node->ns == node->ns);
 	other_node->ns = node->ns;
-	other_node->existence = DSYNC_MAILBOX_NODE_DELETED;
+	if (other_del->type != DSYNC_MAILBOX_DELETE_TYPE_UNSUBSCRIBE)
+		other_node->existence = DSYNC_MAILBOX_NODE_DELETED;
+	else {
+		other_node->last_subscription_change = other_del->timestamp;
+		other_node->subscribed = FALSE;
+	}
 
 	if (dsync_mailbox_tree_guid_hash_add(other_tree, other_node,
 					     &old_node) < 0)
diff -r 4f76d60ba7dd -r 9878986a028d src/doveadm/dsync/dsync-ibc-stream.c
--- a/src/doveadm/dsync/dsync-ibc-stream.c	Mon May 20 02:25:26 2013 +0300
+++ b/src/doveadm/dsync/dsync-ibc-stream.c	Mon May 20 17:30:23 2013 +0300
@@ -90,7 +90,7 @@
 	{ .name = "mailbox_delete",
 	  .chr = 'D',
 	  .required_keys = "hierarchy_sep",
-	  .optional_keys = "mailboxes dirs"
+	  .optional_keys = "mailboxes dirs unsubscribes"
 	},
 	{ .name = "mailbox",
 	  .chr = 'B',
@@ -936,6 +936,28 @@
 }
 
 static void
+dsync_ibc_stream_encode_delete(string_t *str,
+			       struct dsync_serializer_encoder *encoder,
+			       const struct dsync_mailbox_delete *deletes,
+			       unsigned int count, const char *key,
+			       enum dsync_mailbox_delete_type type)
+{
+	unsigned int i;
+
+	str_truncate(str, 0);
+	for (i = 0; i < count; i++) {
+		if (deletes[i].type == type) {
+			str_append(str, guid_128_to_string(deletes[i].guid));
+			str_printfa(str, " %ld ", (long)deletes[i].timestamp);
+		}
+	}
+	if (str_len(str) > 0) {
+		str_truncate(str, str_len(str)-1);
+		dsync_serializer_encode_add(encoder, key, str_c(str));
+	}
+}
+
+static void
 dsync_ibc_stream_send_mailbox_deletes(struct dsync_ibc *_ibc,
 				      const struct dsync_mailbox_delete *deletes,
 				      unsigned int count, char hierarchy_sep)
@@ -944,7 +966,6 @@
 	struct dsync_serializer_encoder *encoder;
 	string_t *str, *substr;
 	char sep[2];
-	unsigned int i;
 
 	str = t_str_new(128);
 	str_append_c(str, items[ITEM_MAILBOX_DELETE].chr);
@@ -954,29 +975,15 @@
 	dsync_serializer_encode_add(encoder, "hierarchy_sep", sep);
 
 	substr = t_str_new(128);
-	for (i = 0; i < count; i++) {
-		if (deletes[i].delete_mailbox) {
-			str_append(substr, guid_128_to_string(deletes[i].guid));
-			str_printfa(substr, " %ld ", (long)deletes[i].timestamp);
-		}
-	}
-	if (str_len(substr) > 0) {
-		str_truncate(substr, str_len(substr)-1);
-		dsync_serializer_encode_add(encoder, "mailboxes",
-					    str_c(substr));
-	}
-
-	str_truncate(substr, 0);
-	for (i = 0; i < count; i++) {
-		if (!deletes[i].delete_mailbox) {
-			str_append(substr, guid_128_to_string(deletes[i].guid));
-			str_printfa(substr, " %ld ", (long)deletes[i].timestamp);
-		}
-	}
-	if (str_len(substr) > 0) {
-		str_truncate(substr, str_len(substr)-1);
-		dsync_serializer_encode_add(encoder, "dirs", str_c(substr));
-	}
+	dsync_ibc_stream_encode_delete(substr, encoder, deletes, count,
+				       "mailboxes",
+				       DSYNC_MAILBOX_DELETE_TYPE_MAILBOX);
+	dsync_ibc_stream_encode_delete(substr, encoder, deletes, count,
+				       "dirs",
+				       DSYNC_MAILBOX_DELETE_TYPE_DIR);
+	dsync_ibc_stream_encode_delete(substr, encoder, deletes, count,
+				       "unsubscribes",
+				       DSYNC_MAILBOX_DELETE_TYPE_UNSUBSCRIBE);
 	dsync_serializer_encode_finish(&encoder, str);
 	dsync_ibc_stream_send_string(ibc, str);
 }
@@ -984,7 +991,7 @@
 ARRAY_DEFINE_TYPE(dsync_mailbox_delete, struct dsync_mailbox_delete);
 static int
 decode_mailbox_deletes(ARRAY_TYPE(dsync_mailbox_delete) *deletes,
-		       const char *value, bool delete_mailbox)
+		       const char *value, enum dsync_mailbox_delete_type type)
 {
 	struct dsync_mailbox_delete *del;
 	const char *const *tmp;
@@ -993,7 +1000,7 @@
 	tmp = t_strsplit(value, " ");
 	for (i = 0; tmp[i] != NULL; i += 2) {
 		del = array_append_space(deletes);
-		del->delete_mailbox = delete_mailbox;
+		del->type = type;
 		if (guid_128_from_string(tmp[i], del->guid) < 0)
 			return -1;
 		if (tmp[i+1] == NULL ||
@@ -1029,12 +1036,20 @@
 	*hierarchy_sep_r = value[0];
 
 	if (dsync_deserializer_decode_try(decoder, "mailboxes", &value) &&
-	    decode_mailbox_deletes(&deletes, value, TRUE) < 0) {
+	    decode_mailbox_deletes(&deletes, value,
+				   DSYNC_MAILBOX_DELETE_TYPE_MAILBOX) < 0) {
 		dsync_ibc_input_error(ibc, decoder, "Invalid mailboxes");
 		return DSYNC_IBC_RECV_RET_TRYAGAIN;
 	}
 	if (dsync_deserializer_decode_try(decoder, "dirs", &value) &&
-	    decode_mailbox_deletes(&deletes, value, FALSE) < 0) {
+	    decode_mailbox_deletes(&deletes, value,
+				   DSYNC_MAILBOX_DELETE_TYPE_DIR) < 0) {
+		dsync_ibc_input_error(ibc, decoder, "Invalid dirs");
+		return DSYNC_IBC_RECV_RET_TRYAGAIN;
+	}
+	if (dsync_deserializer_decode_try(decoder, "unsubscribes", &value) &&
+	    decode_mailbox_deletes(&deletes, value,
+				   DSYNC_MAILBOX_DELETE_TYPE_UNSUBSCRIBE) < 0) {
 		dsync_ibc_input_error(ibc, decoder, "Invalid dirs");
 		return DSYNC_IBC_RECV_RET_TRYAGAIN;
 	}
diff -r 4f76d60ba7dd -r 9878986a028d src/doveadm/dsync/dsync-mailbox-tree-fill.c
--- a/src/doveadm/dsync/dsync-mailbox-tree-fill.c	Mon May 20 02:25:26 2013 +0300
+++ b/src/doveadm/dsync/dsync-mailbox-tree-fill.c	Mon May 20 17:30:23 2013 +0300
@@ -163,7 +163,7 @@
 				break;
 			}
 			del = array_append_space(&tree->deletes);
-			del->delete_mailbox = TRUE;
+			del->type = DSYNC_MAILBOX_DELETE_TYPE_MAILBOX;
 			del->timestamp = timestamp;
 			memcpy(del->guid, rec->mailbox_guid, sizeof(del->guid));
 			break;
@@ -177,6 +177,7 @@
 			   dsync side, it can match this deletion to the
 			   name. */
 			del = array_append_space(&tree->deletes);
+			del->type = DSYNC_MAILBOX_DELETE_TYPE_DIR;
 			del->timestamp = timestamp;
 			memcpy(del->guid, rec->mailbox_guid, sizeof(del->guid));
 			break;
@@ -195,10 +196,22 @@
 				node->last_renamed_or_created = timestamp;
 			break;
 		case MAILBOX_LOG_RECORD_SUBSCRIBE:
-		case MAILBOX_LOG_RECORD_UNSUBSCRIBE:
 			if (node != NULL)
 				node->last_subscription_change = timestamp;
 			break;
+		case MAILBOX_LOG_RECORD_UNSUBSCRIBE:
+			if (node != NULL) {
+				node->last_subscription_change = timestamp;
+				break;
+			}
+			/* The mailbox is already deleted, but it may still
+			   exist on the other side (even the subscription
+			   alone). */
+			del = array_append_space(&tree->deletes);
+			del->type = DSYNC_MAILBOX_DELETE_TYPE_UNSUBSCRIBE;
+			del->timestamp = timestamp;
+			memcpy(del->guid, rec->mailbox_guid, sizeof(del->guid));
+			break;
 		}
 	}
 	if (mailbox_log_iter_deinit(&iter) < 0) {
diff -r 4f76d60ba7dd -r 9878986a028d src/doveadm/dsync/dsync-mailbox-tree.c
--- a/src/doveadm/dsync/dsync-mailbox-tree.c	Mon May 20 02:25:26 2013 +0300
+++ b/src/doveadm/dsync/dsync-mailbox-tree.c	Mon May 20 17:30:23 2013 +0300
@@ -359,7 +359,7 @@
 	i_assert(hash_table_is_created(tree->guid_hash));
 	i_assert(tree->remote_sep != '\0');
 
-	if (del->delete_mailbox) {
+	if (del->type == DSYNC_MAILBOX_DELETE_TYPE_MAILBOX) {
 		/* find node by GUID */
 		return hash_table_lookup(tree->guid_hash, guid_p);
 	}
diff -r 4f76d60ba7dd -r 9878986a028d src/doveadm/dsync/dsync-mailbox-tree.h
--- a/src/doveadm/dsync/dsync-mailbox-tree.h	Mon May 20 02:25:26 2013 +0300
+++ b/src/doveadm/dsync/dsync-mailbox-tree.h	Mon May 20 17:30:23 2013 +0300
@@ -63,10 +63,17 @@
 #define dsync_mailbox_node_is_dir(node) \
 	guid_128_is_empty((node)->mailbox_guid)
 
+enum dsync_mailbox_delete_type {
+	/* Delete mailbox by given GUID */
+	DSYNC_MAILBOX_DELETE_TYPE_MAILBOX = 1,
+	/* Delete mailbox directory by given SHA1 name */
+	DSYNC_MAILBOX_DELETE_TYPE_DIR,
+	/* Unsubscribe mailbox by given SHA1 name */
+	DSYNC_MAILBOX_DELETE_TYPE_UNSUBSCRIBE,
+};
+
 struct dsync_mailbox_delete {
-	/* true: guid = mailbox GUID
-	   false: guid = sha1 of directory name */
-	bool delete_mailbox;
+	enum dsync_mailbox_delete_type type;
 	guid_128_t guid;
 	time_t timestamp;
 };


More information about the dovecot-cvs mailing list