dovecot-1.2: CONDSTORE: STORE UNCHANGEDSINCE conflicts are now c...

dovecot at dovecot.org dovecot at dovecot.org
Sat Jun 21 07:44:03 EEST 2008


details:   http://hg.dovecot.org/dovecot-1.2/rev/e04513064165
changeset: 7913:e04513064165
user:      Timo Sirainen <tss at iki.fi>
date:      Sat Jun 21 07:43:54 2008 +0300
description:
CONDSTORE: STORE UNCHANGEDSINCE conflicts are now checked atomically.

diffstat:

15 files changed, 246 insertions(+), 50 deletions(-)
src/imap/cmd-store.c                            |   51 ++++--
src/lib-index/mail-index-transaction-private.h  |    7 
src/lib-index/mail-index-transaction.c          |  179 +++++++++++++++++++----
src/lib-index/mail-index.h                      |    6 
src/lib-index/mail-transaction-log-append.c     |   19 +-
src/lib-storage/index/cydir/cydir-storage.c     |    1 
src/lib-storage/index/dbox/dbox-storage.c       |    1 
src/lib-storage/index/index-storage.h           |    3 
src/lib-storage/index/index-transaction.c       |   10 +
src/lib-storage/index/maildir/maildir-storage.c |    1 
src/lib-storage/index/mbox/mbox-storage.c       |    1 
src/lib-storage/index/raw/raw-storage.c         |    1 
src/lib-storage/mail-storage-private.h          |    3 
src/lib-storage/mail-storage.c                  |    7 
src/lib-storage/mail-storage.h                  |    6 

diffs (truncated from 579 to 300 lines):

diff -r 81806d402514 -r e04513064165 src/imap/cmd-store.c
--- a/src/imap/cmd-store.c	Fri Jun 20 10:41:44 2008 +0300
+++ b/src/imap/cmd-store.c	Sat Jun 21 07:43:54 2008 +0300
@@ -122,7 +122,7 @@ bool cmd_store(struct client_command_con
         struct mailbox_transaction_context *t;
 	struct mail *mail;
 	struct imap_store_context ctx;
-	ARRAY_TYPE(seq_range) modified_set = ARRAY_INIT;
+	ARRAY_TYPE(seq_range) modified_set, uids;
 	enum mailbox_transaction_flags flags = 0;
 	enum imap_sync_flags imap_sync_flags = 0;
 	const char *reply, *tagged_reply;
@@ -161,21 +161,30 @@ bool cmd_store(struct client_command_con
 
 	if (ctx.silent)
 		flags |= MAILBOX_TRANSACTION_FLAG_HIDE;
-	if (ctx.max_modseq < (uint64_t)-1)
+	if (ctx.max_modseq < (uint64_t)-1) {
+		/* update modseqs so we can check them early */
 		flags |= MAILBOX_TRANSACTION_FLAG_REFRESH;
+	}
 
 	t = mailbox_transaction_begin(client->mailbox, flags);
 	search_ctx = mailbox_search_init(t, search_args, NULL);
 	mail_search_args_unref(&search_args);
 
-	/* FIXME: UNCHANGEDSINCE should be atomic, but this requires support
-	   from mail-storage API. So for now we fake it. */
+	i_array_init(&modified_set, 64);
+	if (ctx.max_modseq < (uint32_t)-1) {
+		/* STORE UNCHANGEDSINCE is being used */
+		mailbox_transaction_set_max_modseq(t, ctx.max_modseq,
+						   &modified_set);
+	}
+
 	mail = mail_alloc(t, MAIL_FETCH_FLAGS, NULL);
 	while (mailbox_search_next(search_ctx, mail) > 0) {
 		if (ctx.max_modseq < (uint64_t)-1) {
+			/* check early so there's less work for transaction
+			   commit if something has to be cancelled */
 			if (mail_get_modseq(mail) > ctx.max_modseq) {
-				seq_range_array_add(&modified_set, 64,
-					cmd->uid ? mail->uid : mail->seq);
+				seq_range_array_add(&modified_set, 0,
+						    mail->seq);
 				continue;
 			}
 		}
@@ -187,17 +196,6 @@ bool cmd_store(struct client_command_con
 		}
 	}
 	mail_free(&mail);
-
-	if (!array_is_created(&modified_set))
-		tagged_reply = "OK Store completed.";
-	else {
-		str = str_new(cmd->pool, 256);
-		str_append(str, "OK [MODIFIED ");
-		imap_write_seq_range(str, &modified_set);
-		array_free(&modified_set);
-		str_append(str, "] Conditional store failed.");
-		tagged_reply = str_c(str);
-	}
 
 	if (ctx.keywords != NULL)
 		mailbox_keywords_free(client->mailbox, &ctx.keywords);
@@ -208,10 +206,29 @@ bool cmd_store(struct client_command_con
 	 else
 		ret = mailbox_transaction_commit(&t);
 	if (ret < 0) {
+		array_free(&modified_set);
 		client_send_storage_error(cmd,
 			mailbox_get_storage(client->mailbox));
 		return TRUE;
 	}
+
+	if (array_count(&modified_set) == 0)
+		tagged_reply = "OK Store completed.";
+	else {
+		if (cmd->uid) {
+			i_array_init(&uids, array_count(&modified_set)*2);
+			mailbox_get_uid_range(client->mailbox, &modified_set,
+					      &uids);
+			array_free(&modified_set);
+			modified_set = uids;
+		}
+		str = str_new(cmd->pool, 256);
+		str_append(str, "OK [MODIFIED ");
+		imap_write_seq_range(str, &modified_set);
+		str_append(str, "] Conditional store failed.");
+		tagged_reply = str_c(str);
+	}
+	array_free(&modified_set);
 
 	/* With UID STORE we have to return UID for the flags as well.
 	   Unfortunately we don't have the ability to separate those
diff -r 81806d402514 -r e04513064165 src/lib-index/mail-index-transaction-private.h
--- a/src/lib-index/mail-index-transaction-private.h	Fri Jun 20 10:41:44 2008 +0300
+++ b/src/lib-index/mail-index-transaction-private.h	Sat Jun 21 07:43:54 2008 +0300
@@ -37,6 +37,8 @@ struct mail_index_transaction {
 	   mail_index_transaction_reset() to reset it. */
         ARRAY_DEFINE(appends, struct mail_index_record);
 	uint32_t first_new_seq, last_new_seq;
+	/* lowest/highest sequence that updates flags/keywords */
+	uint32_t min_flagupdate_seq, max_flagupdate_seq;
 
 	ARRAY_TYPE(seq_range) expunges;
 	ARRAY_DEFINE(updates, struct mail_transaction_flag_update);
@@ -58,6 +60,9 @@ struct mail_index_transaction {
 	ARRAY_DEFINE(keyword_updates,
 		     struct mail_index_transaction_keyword_update);
 	ARRAY_TYPE(seq_range) keyword_resets;
+
+	uint64_t max_modseq;
+	ARRAY_TYPE(seq_range) *conflict_seqs;
 
         struct mail_cache_transaction_ctx *cache_trans_ctx;
 
@@ -92,6 +97,8 @@ void mail_index_transaction_unref(struct
 
 void mail_index_transaction_sort_appends(struct mail_index_transaction *t);
 uint32_t mail_index_transaction_get_next_uid(struct mail_index_transaction *t);
+void mail_index_transaction_convert_to_uids(struct mail_index_transaction *t);
+void mail_index_transaction_check_conflicts(struct mail_index_transaction *t);
 
 bool mail_index_seq_array_lookup(const ARRAY_TYPE(seq_array) *array,
 				 uint32_t seq, unsigned int *idx_r);
diff -r 81806d402514 -r e04513064165 src/lib-index/mail-index-transaction.c
--- a/src/lib-index/mail-index-transaction.c	Fri Jun 20 10:41:44 2008 +0300
+++ b/src/lib-index/mail-index-transaction.c	Sat Jun 21 07:43:54 2008 +0300
@@ -10,6 +10,7 @@
 #include "bsearch-insert-pos.h"
 #include "seq-range-array.h"
 #include "mail-index-view-private.h"
+#include "mail-index-modseq.h"
 #include "mail-transaction-log.h"
 #include "mail-cache-private.h"
 #include "mail-index-transaction-private.h"
@@ -83,6 +84,8 @@ void mail_index_transaction_reset(struct
 	t->first_new_seq = mail_index_view_get_messages_count(t->view)+1;
 	t->last_new_seq = 0;
 	t->last_update_idx = 0;
+	t->min_flagupdate_seq = 0;
+	t->max_flagupdate_seq = 0;
 
 	memset(t->pre_hdr_mask, 0, sizeof(t->pre_hdr_mask));
 	memset(t->post_hdr_mask, 0, sizeof(t->post_hdr_mask));
@@ -300,8 +303,7 @@ static void keyword_updates_convert_to_u
 	}
 }
 
-static int
-mail_index_transaction_convert_to_uids(struct mail_index_transaction *t)
+void mail_index_transaction_convert_to_uids(struct mail_index_transaction *t)
 {
 	ARRAY_TYPE(seq_array) *updates;
 	unsigned int i, count;
@@ -317,7 +319,6 @@ mail_index_transaction_convert_to_uids(s
 	mail_index_convert_to_uid_ranges(t, &t->expunges);
 	mail_index_convert_to_uid_ranges(t, (void *)&t->updates);
 	mail_index_convert_to_uid_ranges(t, &t->keyword_resets);
-	return 0;
 }
 
 struct uid_map {
@@ -584,12 +585,7 @@ static int mail_index_transaction_commit
 		mail_index_update_day_headers(t);
 	}
 
-	if (mail_index_transaction_convert_to_uids(t) < 0)
-		ret = -1;
-	else {
-		ret = mail_transaction_log_append(t, log_file_seq_r,
-						  log_file_offset_r);
-	}
+	ret = mail_transaction_log_append(t, log_file_seq_r, log_file_offset_r);
 
 	if (ret == 0 && !t->view->index->syncing) {
 		/* if we're committing a normal transaction, we want to
@@ -772,6 +768,20 @@ void mail_index_expunge(struct mail_inde
 	}
 }
 
+static void update_minmax_flagupdate_seq(struct mail_index_transaction *t,
+					 uint32_t seq1, uint32_t seq2)
+{
+	if (t->min_flagupdate_seq == 0) {
+		t->min_flagupdate_seq = seq1;
+		t->max_flagupdate_seq = seq2;
+	} else {
+		if (t->min_flagupdate_seq > seq1)
+			t->min_flagupdate_seq = seq1;
+		if (t->max_flagupdate_seq < seq2)
+			t->max_flagupdate_seq = seq2;
+	}
+}
+
 static bool
 mail_transaction_update_want_add(struct mail_index_transaction *t,
 				 const struct mail_transaction_flag_update *u)
@@ -792,17 +802,15 @@ mail_transaction_update_want_add(struct 
 	return FALSE;
 }
 
-static void
-mail_index_insert_flag_update(struct mail_index_transaction *t,
-			      struct mail_transaction_flag_update u,
-			      uint32_t left_idx, uint32_t right_idx)
-{
-	struct mail_transaction_flag_update *updates, tmp_update;
-	unsigned int count;
-	uint32_t idx, move;
-
-	updates = array_get_modifiable(&t->updates, &count);
-
+static uint32_t
+mail_index_find_update_insert_pos(struct mail_index_transaction *t,
+				  unsigned int left_idx, unsigned int right_idx,
+				  uint32_t seq)
+{
+	const struct mail_transaction_flag_update *updates;
+	unsigned int idx, count;
+
+	updates = array_get(&t->updates, &count);
 	i_assert(left_idx <= right_idx && right_idx <= count);
 
 	/* find the first update with either overlapping range,
@@ -811,15 +819,28 @@ mail_index_insert_flag_update(struct mai
 	while (left_idx < right_idx) {
 		idx = (left_idx + right_idx) / 2;
 
-		if (updates[idx].uid2 < u.uid1)
+		if (updates[idx].uid2 < seq)
 			left_idx = idx+1;
-		else if (updates[idx].uid1 > u.uid1)
+		else if (updates[idx].uid1 > seq)
 			right_idx = idx;
 		else
 			break;
 	}
-	if (idx < count && updates[idx].uid2 < u.uid1)
+	if (idx < count && updates[idx].uid2 < seq)
 		idx++;
+	return idx;
+}
+
+static void
+mail_index_insert_flag_update(struct mail_index_transaction *t,
+			      struct mail_transaction_flag_update u,
+			      unsigned int idx)
+{
+	struct mail_transaction_flag_update *updates, tmp_update;
+	unsigned int count;
+	uint32_t move;
+
+	updates = array_get_modifiable(&t->updates, &count);
 
 	/* overlapping ranges, split/merge them */
 	i_assert(idx == 0 || updates[idx-1].uid2 < u.uid1);
@@ -930,8 +951,9 @@ void mail_index_update_flags_range(struc
 {
 	struct mail_index_record *rec;
 	struct mail_transaction_flag_update u, *last_update;
-	unsigned int first_idx, count;
-
+	unsigned int idx, first_idx, count;
+
+	update_minmax_flagupdate_seq(t, seq1, seq2);
 	if (seq2 >= t->first_new_seq) {
 		/* updates for appended messages, modify them directly */
 		uint32_t seq;
@@ -1013,7 +1035,9 @@ void mail_index_update_flags_range(struc
 			first_idx = 0;
 			count = t->last_update_idx + 1;
 		}
-		mail_index_insert_flag_update(t, u, first_idx, count);
+		idx = mail_index_find_update_insert_pos(t, first_idx, count,
+							u.uid1);
+		mail_index_insert_flag_update(t, u, idx);
 	}
 }
 
@@ -1415,6 +1439,8 @@ void mail_index_update_keywords(struct m
 		  seq <= t->last_new_seq));
 	i_assert(keywords->count > 0 || modify_type == MODIFY_REPLACE);
 	i_assert(keywords->index == t->view->index);
+
+	update_minmax_flagupdate_seq(t, seq, seq);
 
 	if (!array_is_created(&t->keyword_updates) && keywords->count > 0) {
 		uint32_t max_idx = keywords->idx[keywords->count-1];
@@ -1486,6 +1512,107 @@ void mail_index_reset(struct mail_index_
 	t->reset = TRUE;
 }
 
+void mail_index_transaction_set_max_modseq(struct mail_index_transaction *t,
+					   uint64_t max_modseq,
+					   ARRAY_TYPE(seq_range) *seqs)
+{
+	i_assert(array_is_created(seqs));


More information about the dovecot-cvs mailing list