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