]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Tracking flag updates in saved search results was broken when expunging messages.
authorTimo Sirainen <tss@iki.fi>
Sun, 17 May 2009 21:12:19 +0000 (17:12 -0400)
committerTimo Sirainen <tss@iki.fi>
Sun, 17 May 2009 21:12:19 +0000 (17:12 -0400)
--HG--
branch : HEAD

src/lib-storage/index/index-search-result.c
src/lib-storage/index/index-search-result.h
src/lib-storage/index/index-sync-private.h
src/lib-storage/index/index-sync-search.c
src/lib-storage/index/index-sync.c

index 1b843486c5a4f753b46070a27e8e922ef74741b1..5385cc882af96f1e6ee3af896302ceabb93386b1 100644 (file)
 
 static void
 search_result_range_remove(struct mail_search_result *result,
-                          const ARRAY_TYPE(seq_range) *search_seqs_range,
-                          unsigned int *pos,
-                          uint32_t *next_seq, uint32_t last_seq)
+                          const ARRAY_TYPE(seq_range) *changed_uids_arr,
+                          unsigned int *idx,
+                          uint32_t *next_uid, uint32_t last_uid)
 {
-       struct index_mailbox *ibox = (struct index_mailbox *)result->box;
-       const struct seq_range *seqs;
+       const struct seq_range *uids;
        unsigned int i, count;
-       uint32_t seq, uid;
-
-       seq = *next_seq;
-       seqs = array_get(search_seqs_range, &count);
-       for (i = *pos; seqs[i].seq2 < last_seq;) {
-               i_assert(seqs[i].seq1 <= seq);
-               for (; seq <= seqs[i].seq2; seq++) {
-                       mail_index_lookup_uid(ibox->view, seq, &uid);
+       uint32_t uid;
+
+       /* remove full seq_ranges */
+       uid = *next_uid;
+       uids = array_get(changed_uids_arr, &count);
+       for (i = *idx; uids[i].seq2 < last_uid;) {
+               i_assert(uids[i].seq1 <= uid);
+               for (; uid <= uids[i].seq2; uid++)
                        mailbox_search_result_remove(result, uid);
-               }
                i++;
                i_assert(i < count);
-               seq = seqs[i].seq1;
+               uid = uids[i].seq1;
        }
 
-       i_assert(seqs[i].seq1 <= seq && seqs[i].seq2 >= last_seq);
-       for (; seq <= last_seq; seq++) {
-               mail_index_lookup_uid(ibox->view, seq, &uid);
+       /* remove the last seq_range */
+       i_assert(uids[i].seq1 <= uid && uids[i].seq2 >= last_uid);
+       for (; uid <= last_uid; uid++)
                mailbox_search_result_remove(result, uid);
-       }
-       if (seq > seqs[i].seq2) {
+
+       if (uid > uids[i].seq2) {
                /* finished this range */
                if (++i < count)
-                       seq = seqs[i].seq1;
+                       uid = uids[i].seq1;
                else {
                        /* this was the last searched message */
-                       seq = 0;
+                       uid = 0;
                }
        }
 
-       *next_seq = seq;
-       *pos = i;
+       *next_uid = uid;
+       *idx = i;
 }
 
 static int
 search_result_update_search(struct mail_search_result *result,
-                           const ARRAY_TYPE(seq_range) *search_seqs_range)
+                           const ARRAY_TYPE(seq_range) *changed_uids_arr)
 {
        struct mailbox_transaction_context *t;
        struct mail_search_context *search_ctx;
        struct mail *mail;
-       const struct seq_range *search_seqs;
-       unsigned int seqcount, seqpos;
-       uint32_t next_seq;
+       const struct seq_range *changed_uids;
+       unsigned int changed_count, changed_idx;
+       uint32_t next_uid;
        int ret;
 
-       search_seqs = array_get(search_seqs_range, &seqcount);
-       i_assert(seqcount > 0);
-       next_seq = search_seqs[0].seq1;
-       seqpos = 0;
+       changed_uids = array_get(changed_uids_arr, &changed_count);
+       i_assert(changed_count > 0);
+       next_uid = changed_uids[0].seq1;
+       changed_idx = 0;
 
        mail_search_args_init(result->search_args, result->box, FALSE, NULL);
 
@@ -78,23 +76,23 @@ search_result_update_search(struct mail_search_result *result,
 
        mail = mail_alloc(t, 0, NULL);
        while (mailbox_search_next(search_ctx, mail) > 0) {
-               i_assert(next_seq != 0);
+               i_assert(next_uid != 0);
 
-               if (next_seq != mail->seq) {
-                       /* some messages in search_seqs didn't match.
+               if (next_uid != mail->uid) {
+                       /* some messages in changed_uids didn't match.
                           make sure they don't exist in the search result. */
-                       search_result_range_remove(result, search_seqs_range,
-                                                  &seqpos, &next_seq,
-                                                  mail->seq-1);
-                       i_assert(next_seq == mail->seq);
+                       search_result_range_remove(result, changed_uids_arr,
+                                                  &changed_idx, &next_uid,
+                                                  mail->uid-1);
+                       i_assert(next_uid == mail->uid);
                }
-               if (search_seqs[seqpos].seq2 > next_seq) {
-                       next_seq++;
-               } else if (++seqpos < seqcount) {
-                       next_seq = search_seqs[seqpos].seq1;
+               if (changed_uids[changed_idx].seq2 > next_uid) {
+                       next_uid++;
+               } else if (++changed_idx < changed_count) {
+                       next_uid = changed_uids[changed_idx].seq1;
                } else {
                        /* this was the last searched message */
-                       next_seq = 0;
+                       next_uid = 0;
                }
                /* match - make sure it exists in search result */
                mailbox_search_result_add(result, mail->uid);
@@ -103,12 +101,12 @@ search_result_update_search(struct mail_search_result *result,
        ret = mailbox_search_deinit(&search_ctx);
        mail_search_args_deinit(result->search_args);
 
-       if (next_seq != 0 && ret == 0) {
+       if (next_uid != 0 && ret == 0) {
                /* last message(s) didn't match. make sure they don't exist
                   in the search result. */
-               search_result_range_remove(result, search_seqs_range, &seqpos,
-                                          &next_seq,
-                                          search_seqs[seqcount-1].seq2);
+               search_result_range_remove(result, changed_uids_arr,
+                                          &changed_idx, &next_uid,
+                                          changed_uids[changed_count-1].seq2);
        }
 
        if (mailbox_transaction_commit(&t) < 0)
@@ -117,22 +115,22 @@ search_result_update_search(struct mail_search_result *result,
 }
 
 int index_search_result_update_flags(struct mail_search_result *result,
-                                    const ARRAY_TYPE(seq_range) *changes)
+                                    const ARRAY_TYPE(seq_range) *uids)
 {
        struct mail_search_arg search_arg;
        int ret;
 
-       if (array_count(changes) == 0)
+       if (array_count(uids) == 0)
                return 0;
 
        /* add a temporary search parameter to limit the search only to
           the changed messages */
        memset(&search_arg, 0, sizeof(search_arg));
-       search_arg.type = SEARCH_SEQSET;
-       search_arg.value.seqset = *changes;
+       search_arg.type = SEARCH_UIDSET;
+       search_arg.value.seqset = *uids;
        search_arg.next = result->search_args->args;
        result->search_args->args = &search_arg;
-       ret = search_result_update_search(result, changes);
+       ret = search_result_update_search(result, uids);
        i_assert(result->search_args->args == &search_arg);
        result->search_args->args = search_arg.next;
        return ret;
index 63bceaa735dcd0eb5f0fec4c031ff5a6b1600068..a22d36879b94e7c9d82b29bd5205d00a04a8d3a2 100644 (file)
@@ -2,7 +2,7 @@
 #define INDEX_SEARCH_RESULT_H
 
 int index_search_result_update_flags(struct mail_search_result *result,
-                                    const ARRAY_TYPE(seq_range) *changes);
+                                    const ARRAY_TYPE(seq_range) *uids);
 int index_search_result_update_appends(struct mail_search_result *result,
                                       unsigned int old_messages_count);
 void index_search_results_update_expunges(struct mailbox *box,
index 9531453c52583d5674ac6d11e48f97759284916e..2d164983b5161bcddaea9d679e29ee57d75d208c 100644 (file)
@@ -11,13 +11,14 @@ struct index_mailbox_sync_context {
 
        ARRAY_TYPE(seq_range) flag_updates;
        ARRAY_TYPE(seq_range) hidden_updates;
-       ARRAY_TYPE(seq_range) *all_flag_updates, all_flag_updates_merge;
+       ARRAY_TYPE(seq_range) all_flag_update_uids;
        const ARRAY_TYPE(seq_range) *expunges;
        unsigned int flag_update_idx, hidden_update_idx, expunge_pos;
 
        bool failed;
 };
 
+void index_sync_search_results_uidify(struct index_mailbox_sync_context *ctx);
 void index_sync_search_results_update(struct index_mailbox_sync_context *ctx);
 void index_sync_search_results_expunge(struct index_mailbox_sync_context *ctx);
 
index 68515c22f70f9e55b69ea5356ddc2a57fdc0b972..c73905b069f066895784d27c123fa5485ac659ca 100644 (file)
@@ -9,39 +9,59 @@
 #include "index-sync-private.h"
 
 static bool
-search_result_merge_changes(struct index_mailbox_sync_context *ctx,
-                           const struct mail_search_result *result)
+search_result_want_flag_updates(const struct mail_search_result *result)
 {
-       unsigned int count;
-
        if (!result->args_have_flags && !result->args_have_keywords &&
            !result->args_have_modseq) {
                /* search result doesn't care about flag changes */
                return FALSE;
        }
-       if (ctx->all_flag_updates != NULL) {
-               /* already merged */
-               return TRUE;
-       }
+       return TRUE;
+}
 
-       if (array_count(&ctx->hidden_updates) == 0) {
-               ctx->all_flag_updates = &ctx->flag_updates;
-               return TRUE;
-       }
-       if (array_count(&ctx->flag_updates) == 0) {
-               ctx->all_flag_updates = &ctx->hidden_updates;
-               return TRUE;
+static void index_sync_uidify_array(struct index_mailbox_sync_context *ctx,
+                                   const ARRAY_TYPE(seq_range) *changes)
+{
+       const struct seq_range *seqs;
+       unsigned int i, count;
+       uint32_t seq, uid;
+
+       seqs = array_get(changes, &count);
+       for (i = 0; i < count; i++) {
+               for (seq = seqs[i].seq1; seq <= seqs[i].seq2; seq++) {
+                       mail_index_lookup_uid(ctx->ibox->view, seq, &uid);
+                       seq_range_array_add(&ctx->all_flag_update_uids, 0, uid);
+               }
        }
+}
+
+static void index_sync_uidify(struct index_mailbox_sync_context *ctx)
+{
+       unsigned int count;
 
-       /* both hidden and non-hidden changes. merge them */
        count = array_count(&ctx->flag_updates) +
                array_count(&ctx->hidden_updates);
+       i_array_init(&ctx->all_flag_update_uids, count*2);
 
-       ctx->all_flag_updates = &ctx->all_flag_updates_merge;
-       i_array_init(ctx->all_flag_updates, count);
-       seq_range_array_merge(ctx->all_flag_updates, &ctx->flag_updates);
-       seq_range_array_merge(ctx->all_flag_updates, &ctx->hidden_updates);
-       return TRUE;
+       index_sync_uidify_array(ctx, &ctx->flag_updates);
+       index_sync_uidify_array(ctx, &ctx->hidden_updates);
+}
+
+void index_sync_search_results_uidify(struct index_mailbox_sync_context *ctx)
+{
+       struct mail_search_result *const *results;
+       unsigned int i, count;
+
+       i_assert(!array_is_created(&ctx->all_flag_update_uids));
+
+       results = array_get(&ctx->ibox->box.search_results, &count);
+       for (i = 0; i < count; i++) {
+               if ((results[i]->flags & MAILBOX_SEARCH_RESULT_FLAG_UPDATE) != 0 &&
+                   search_result_want_flag_updates(results[i])) {
+                       index_sync_uidify(ctx);
+                       break;
+               }
+       }
 }
 
 static void
@@ -53,9 +73,9 @@ search_result_update(struct index_mailbox_sync_context *ctx,
                return;
        }
 
-       if (search_result_merge_changes(ctx, result)) {
+       if (search_result_want_flag_updates(result)) {
                (void)index_search_result_update_flags(result,
-                                                      ctx->all_flag_updates);
+                                               &ctx->all_flag_update_uids);
        }
        (void)index_search_result_update_appends(result, ctx->messages_count);
 }
index 8d965db694456aa05518d1f77a40167024052af2..8aa8bb91fea72a37605a8d7e8c75acadbff56b6e 100644 (file)
@@ -314,6 +314,9 @@ int index_mailbox_sync_deinit(struct mailbox_sync_context *_ctx,
           recent flags */
        while (index_mailbox_sync_next_expunge(ctx, &sync_rec) > 0) ;
 
+       /* convert sequences to uids before syncing view */
+       index_sync_search_results_uidify(ctx);
+
        if (ctx->sync_ctx != NULL) {
                if (mail_index_view_sync_commit(&ctx->sync_ctx,
                                                &delayed_expunges) < 0) {
@@ -349,8 +352,8 @@ int index_mailbox_sync_deinit(struct mailbox_sync_context *_ctx,
                array_free(&ctx->flag_updates);
        if (array_is_created(&ctx->hidden_updates))
                array_free(&ctx->hidden_updates);
-       if (array_is_created(&ctx->all_flag_updates_merge))
-               array_free(&ctx->all_flag_updates_merge);
+       if (array_is_created(&ctx->all_flag_update_uids))
+               array_free(&ctx->all_flag_update_uids);
        i_free(ctx);
        return ret;
 }