]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
mail index transactions: More code cleanups and unit tests.
authorTimo Sirainen <tss@iki.fi>
Tue, 14 Jul 2009 21:55:27 +0000 (17:55 -0400)
committerTimo Sirainen <tss@iki.fi>
Tue, 14 Jul 2009 21:55:27 +0000 (17:55 -0400)
--HG--
branch : HEAD

src/lib-index/Makefile.am
src/lib-index/mail-index-transaction-finish.c
src/lib-index/mail-index-transaction-private.h
src/lib-index/mail-index-transaction-update.c
src/lib-index/test-mail-index-transaction-finish.c [new file with mode: 0644]
src/lib-index/test-mail-index-transaction-update.c

index 1db1294d9a551b0e1c11940a2569f1b74eb71a65..f96d496a09c24a3d4946800e39766bd34723350b 100644 (file)
@@ -61,6 +61,7 @@ headers = \
         mailbox-list-index-private.h
 
 test_programs = \
+       test-mail-index-transaction-finish \
        test-mail-index-transaction-update \
        test-mail-transaction-log-append \
        test-mail-transaction-log-view
@@ -72,6 +73,10 @@ test_libs = \
        ../lib-test/libtest.la \
        ../lib/liblib.la
 
+test_mail_index_transaction_finish_SOURCES = test-mail-index-transaction-finish.c
+test_mail_index_transaction_finish_LDADD = mail-index-transaction-finish.lo $(test_libs)
+test_mail_index_transaction_finish_DEPENDENCIES = mail-index-transaction-finish.lo $(test_libs)
+
 test_mail_index_transaction_update_SOURCES = test-mail-index-transaction-update.c
 test_mail_index_transaction_update_LDADD = mail-index-transaction-update.lo $(test_libs)
 test_mail_index_transaction_update_DEPENDENCIES = mail-index-transaction-update.lo $(test_libs)
index 3f428101c51a5e4f66dc552a006555739508bf8b..a6d96bdb7fbc6ba8be178038289e9a7323c8f41a 100644 (file)
@@ -140,76 +140,11 @@ mail_index_transaction_finish_flag_updates(struct mail_index_transaction *t)
                array_free(&t->updates);
 }
 
-static bool
-mail_index_update_cancel_array(ARRAY_TYPE(seq_range) *array, uint32_t seq)
-{
-       if (array_is_created(array)) {
-               if (seq_range_array_remove(array, seq)) {
-                       if (array_count(array) == 0)
-                               array_free(array);
-                       return TRUE;
-               }
-       }
-       return FALSE;
-}
-
-static bool
-mail_index_update_cancel(struct mail_index_transaction *t, uint32_t seq)
-{
-       struct mail_index_transaction_keyword_update *kw;
-       struct mail_transaction_flag_update *updates, tmp_update;
-       unsigned int i, count;
-       bool ret, have_kw_changes = FALSE;
-
-       ret = mail_index_update_cancel_array(&t->keyword_resets, seq);
-       if (array_is_created(&t->keyword_updates)) {
-               kw = array_get_modifiable(&t->keyword_updates, &count);
-               for (i = 0; i < count; i++) {
-                       if (mail_index_update_cancel_array(&kw[i].add_seq, seq))
-                               ret = TRUE;
-                       if (mail_index_update_cancel_array(&kw[i].remove_seq,
-                                                          seq))
-                               ret = TRUE;
-                       if (array_is_created(&kw[i].add_seq) ||
-                           array_is_created(&kw[i].remove_seq))
-                               have_kw_changes = TRUE;
-               }
-               if (!have_kw_changes)
-                       array_free(&t->keyword_updates);
-       }
-
-       if (!array_is_created(&t->updates))
-               return ret;
-
-       updates = array_get_modifiable(&t->updates, &count);
-       i = mail_index_transaction_get_flag_update_pos(t, 0, count, seq);
-       if (i < count && updates[i].uid1 <= seq && updates[i].uid2 >= seq) {
-               /* exists */
-               ret = TRUE;
-               if (updates[i].uid1 == seq && updates[i].uid2 == seq) {
-                       if (count > 1)
-                               array_delete(&t->updates, i, 1);
-                       else
-                               array_free(&t->updates);
-               } else if (updates[i].uid1 == seq)
-                       updates[i].uid1++;
-               else if (updates[i].uid2 == seq)
-                       updates[i].uid2--;
-               else {
-                       /* need to split it in two */
-                       tmp_update = updates[i];
-                       tmp_update.uid1 = seq+1;
-                       updates[i].uid2 = seq-1;
-                       array_insert(&t->updates, i + 1, &tmp_update, 1);
-               }
-       }
-       return ret;
-}
-
 static void
 mail_index_transaction_check_conflicts(struct mail_index_transaction *t)
 {
        uint32_t seq;
+       bool ret1, ret2;
 
        i_assert(t->max_modseq != 0);
        i_assert(t->conflict_seqs != NULL);
@@ -225,7 +160,9 @@ mail_index_transaction_check_conflicts(struct mail_index_transaction *t)
 
        for (seq = t->min_flagupdate_seq; seq <= t->max_flagupdate_seq; seq++) {
                if (mail_index_modseq_lookup(t->view, seq) > t->max_modseq) {
-                       if (mail_index_update_cancel(t, seq))
+                       ret1 = mail_index_cancel_flag_updates(t, seq);
+                       ret2 = mail_index_cancel_keyword_updates(t, seq);
+                       if (ret1 || ret2)
                                seq_range_array_add(t->conflict_seqs, 0, seq);
                }
        }
index a9fe061ced055f1be19f3af7495758706a6d0ed7..93fb2c9c8f310ff6f6c3d2fcd187eafa55c02c6f 100644 (file)
@@ -116,6 +116,11 @@ mail_index_transaction_get_flag_update_pos(struct mail_index_transaction *t,
                                           unsigned int right_idx,
                                           uint32_t seq);
 
+bool mail_index_cancel_flag_updates(struct mail_index_transaction *t,
+                                   uint32_t seq);
+bool mail_index_cancel_keyword_updates(struct mail_index_transaction *t,
+                                      uint32_t seq);
+
 int mail_index_transaction_finish(struct mail_index_transaction *t);
 void mail_index_transaction_export(struct mail_index_transaction *t,
                                   struct mail_transaction_log_append_ctx *append_ctx);
index 64dc0fe96ce4c8f60b8064054146a7ccde551b2c..a33133be19d7a4316808a79ff78c787ff85fd129 100644 (file)
@@ -1013,6 +1013,83 @@ void mail_index_update_keywords(struct mail_index_transaction *t, uint32_t seq,
        t->log_updates = TRUE;
 }
 
+bool mail_index_cancel_flag_updates(struct mail_index_transaction *t,
+                                   uint32_t seq)
+{
+       struct mail_transaction_flag_update *updates, tmp_update;
+       unsigned int i, count;
+
+       if (!array_is_created(&t->updates))
+               return FALSE;
+
+       updates = array_get_modifiable(&t->updates, &count);
+       i = mail_index_transaction_get_flag_update_pos(t, 0, count, seq);
+       if (i == count)
+               return FALSE;
+       else {
+               i_assert(seq <= updates[i].uid2);
+               if (seq < updates[i].uid1)
+                       return FALSE;
+       }
+
+       /* exists */
+       if (updates[i].uid1 == seq) {
+               if (updates[i].uid2 != seq)
+                       updates[i].uid1++;
+               else if (count > 1)
+                       array_delete(&t->updates, i, 1);
+               else
+                       array_free(&t->updates);
+       } else if (updates[i].uid2 == seq) {
+               updates[i].uid2--;
+       } else {
+               /* need to split it in two */
+               tmp_update = updates[i];
+               tmp_update.uid1 = seq+1;
+               updates[i].uid2 = seq-1;
+               array_insert(&t->updates, i + 1, &tmp_update, 1);
+       }
+       return TRUE;
+}
+
+static bool mail_index_cancel_array(ARRAY_TYPE(seq_range) *array, uint32_t seq)
+{
+       if (array_is_created(array)) {
+               if (seq_range_array_remove(array, seq)) {
+                       if (array_count(array) == 0)
+                               array_free(array);
+                       return TRUE;
+               }
+       }
+       return FALSE;
+}
+
+bool mail_index_cancel_keyword_updates(struct mail_index_transaction *t,
+                                      uint32_t seq)
+{
+       struct mail_index_transaction_keyword_update *kw;
+       unsigned int i, count;
+       bool ret, have_kw_changes = FALSE;
+
+       ret = mail_index_cancel_array(&t->keyword_resets, seq);
+       if (!array_is_created(&t->keyword_updates))
+               return ret;
+
+       kw = array_get_modifiable(&t->keyword_updates, &count);
+       for (i = 0; i < count; i++) {
+               if (mail_index_cancel_array(&kw[i].add_seq, seq))
+                       ret = TRUE;
+               if (mail_index_cancel_array(&kw[i].remove_seq, seq))
+                       ret = TRUE;
+               if (array_is_created(&kw[i].add_seq) ||
+                   array_is_created(&kw[i].remove_seq))
+                       have_kw_changes = TRUE;
+       }
+       if (!have_kw_changes)
+               array_free(&t->keyword_updates);
+       return ret;
+}
+
 void mail_index_transaction_reset(struct mail_index_transaction *t)
 {
        t->v.reset(t);
diff --git a/src/lib-index/test-mail-index-transaction-finish.c b/src/lib-index/test-mail-index-transaction-finish.c
new file mode 100644 (file)
index 0000000..415e5ba
--- /dev/null
@@ -0,0 +1,213 @@
+/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "test-common.h"
+#include "mail-index-private.h"
+#include "mail-index-modseq.h"
+#include "mail-index-transaction-private.h"
+
+#include <stdlib.h>
+
+static struct mail_index_record recs[20];
+static uint64_t modseqs[N_ELEMENTS(recs)];
+
+bool mail_index_map_get_ext_idx(struct mail_index_map *map ATTR_UNUSED,
+                               uint32_t ext_id ATTR_UNUSED,
+                               uint32_t *idx_r ATTR_UNUSED) { return FALSE; }
+void mail_index_ext_set_reset_id(struct mail_index_transaction *t ATTR_UNUSED,
+                                uint32_t ext_id ATTR_UNUSED,
+                                uint32_t reset_id ATTR_UNUSED) { }
+void mail_index_transaction_set_log_updates(struct mail_index_transaction *t ATTR_UNUSED) { }
+void mail_index_update_day_headers(struct mail_index_transaction *t ATTR_UNUSED) {}
+bool mail_index_cancel_flag_updates(struct mail_index_transaction *t ATTR_UNUSED,
+                                   uint32_t seq ATTR_UNUSED) { return TRUE; }
+bool mail_index_cancel_keyword_updates(struct mail_index_transaction *t ATTR_UNUSED,
+                                      uint32_t seq ATTR_UNUSED) { return TRUE; }
+void mail_index_transaction_sort_appends(struct mail_index_transaction *t ATTR_UNUSED) {}
+int mail_index_map(struct mail_index *index ATTR_UNUSED,
+                  enum mail_index_sync_handler_type type ATTR_UNUSED) { return 1; }
+
+const struct mail_index_record *
+mail_index_lookup(struct mail_index_view *view ATTR_UNUSED, uint32_t seq)
+{
+       i_assert(seq < N_ELEMENTS(recs));
+       return &recs[seq];
+}
+
+struct mail_index_record *
+mail_index_transaction_lookup(struct mail_index_transaction *t ATTR_UNUSED,
+                             uint32_t seq)
+{
+       i_assert(seq < N_ELEMENTS(recs));
+       return &recs[seq];
+}
+
+uint64_t mail_index_modseq_lookup(struct mail_index_view *view ATTR_UNUSED,
+                                 uint32_t seq)
+{
+       i_assert(seq < N_ELEMENTS(modseqs));
+       return modseqs[seq];
+}
+
+uint64_t mail_index_modseq_get_highest(struct mail_index_view *view ATTR_UNUSED)
+{
+       return modseqs[0];
+}
+
+static void test_mail_index_transaction_finish_flag_updates(void)
+{
+       struct mail_index_transaction *t;
+       const struct mail_transaction_flag_update *updates;
+       struct mail_transaction_flag_update u;
+       unsigned int count;
+
+       t = t_new(struct mail_index_transaction, 1);
+       t->drop_unnecessary_flag_updates = TRUE;
+
+       memset(&u, 0, sizeof(u));
+       u.add_flags = MAIL_SEEN; u.remove_flags = MAIL_DRAFT;
+
+       test_begin("mail index transaction finish flag updates");
+
+       /* test fast path: all changed */
+       t_array_init(&t->updates, 10);
+       u.uid1 = 1; u.uid2 = 2;
+       array_append(&t->updates, &u, 1);
+       u.uid1 = 4; u.uid2 = 5;
+       array_append(&t->updates, &u, 1);
+       mail_index_transaction_finish(t);
+
+       updates = array_get(&t->updates, &count);
+       test_assert(count == 2);
+       test_assert(updates[0].uid1 == 1 && updates[0].uid2 == 2);
+       test_assert(updates[1].uid1 == 4 && updates[1].uid2 == 5);
+
+       /* nothing changed */
+       recs[1].flags = MAIL_SEEN;
+       recs[2].flags = MAIL_SEEN;
+       recs[4].flags = MAIL_SEEN;
+       recs[5].flags = MAIL_SEEN;
+       mail_index_transaction_finish(t);
+       test_assert(!array_is_created(&t->updates));
+
+       /* some changes */
+       t_array_init(&t->updates, 10);
+       u.uid1 = 2; u.uid2 = 3;
+       array_append(&t->updates, &u, 1);
+       u.uid1 = 5; u.uid2 = 6;
+       array_append(&t->updates, &u, 1);
+       mail_index_transaction_finish(t);
+
+       updates = array_get(&t->updates, &count);
+       test_assert(count == 2);
+       test_assert(updates[0].uid1 == 3 && updates[0].uid2 == 3);
+       test_assert(updates[1].uid1 == 6 && updates[1].uid2 == 6);
+
+       test_end();
+}
+
+static void test_mail_index_transaction_finish_check_conflicts(void)
+{
+       struct mail_index_transaction *t;
+       const struct seq_range *conflicts;
+       ARRAY_TYPE(seq_range) conflict_seqs = ARRAY_INIT;
+       unsigned int count;
+
+       t = t_new(struct mail_index_transaction, 1);
+       t->view = t_new(struct mail_index_view, 1);
+       t->min_flagupdate_seq = 5;
+       t->max_flagupdate_seq = 8;
+       t->conflict_seqs = &conflict_seqs;
+
+       modseqs[0] = 1234;
+       modseqs[5] = 5;
+       modseqs[6] = 8;
+       modseqs[7] = 6;
+       modseqs[8] = 7;
+
+       test_begin("mail index transaction finish check conflicts");
+
+       /* fast path: no conflicts */
+       t->max_modseq = 1234;
+       mail_index_transaction_finish(t);
+       test_assert(!array_is_created(&conflict_seqs));
+
+       /* try some conflicts */
+       t->max_modseq = 6;
+       mail_index_transaction_finish(t);
+
+       conflicts = array_get(&conflict_seqs, &count);
+       test_assert(count == 2);
+       test_assert(conflicts[0].seq1 == 6 && conflicts[0].seq2 == 6);
+       test_assert(conflicts[1].seq1 == 8 && conflicts[1].seq2 == 8);
+
+       test_end();
+}
+
+static void test_mail_index_transaction_finish_expunges(void)
+{
+       struct mail_index_transaction *t;
+       uint8_t guid1[MAIL_GUID_128_SIZE];
+       uint8_t guid2[MAIL_GUID_128_SIZE];
+       uint8_t guid3[MAIL_GUID_128_SIZE];
+       const struct mail_transaction_expunge_guid *expunges;
+       struct mail_transaction_expunge_guid expunge;
+       unsigned int i, count;
+
+       for (i = 0; i < sizeof(guid2); i++) {
+               guid1[i] = i + 1;
+               guid2[i] = i ^ 0xff;
+               guid3[i] = i + 0x80;
+       }
+
+       recs[1].uid = 12;
+       recs[2].uid = 15;
+       recs[3].uid = 18;
+
+       t = t_new(struct mail_index_transaction, 1);
+       t->expunges_nonsorted = TRUE;
+
+       test_begin("mail index transaction finish expunges");
+
+       t_array_init(&t->expunges, 3);
+       expunge.uid = 2;
+       memcpy(expunge.guid_128, guid2, sizeof(expunge.guid_128));
+       array_append(&t->expunges, &expunge, 1);
+       array_append(&t->expunges, &expunge, 1);
+       expunge.uid = 1;
+       memcpy(expunge.guid_128, guid1, sizeof(expunge.guid_128));
+       array_append(&t->expunges, &expunge, 1);
+       array_append(&t->expunges, &expunge, 1);
+       expunge.uid = 3;
+       memcpy(expunge.guid_128, guid3, sizeof(expunge.guid_128));
+       array_append(&t->expunges, &expunge, 1);
+       array_append(&t->expunges, &expunge, 1);
+
+       mail_index_transaction_finish(t);
+
+       expunges = array_get(&t->expunges, &count);
+       test_assert(count == 3);
+       test_assert(expunges[0].uid == 12);
+       test_assert(memcmp(expunges[0].guid_128, guid1, sizeof(guid1)) == 0);
+       test_assert(expunges[1].uid == 15);
+       test_assert(memcmp(expunges[1].guid_128, guid2, sizeof(guid2)) == 0);
+       test_assert(expunges[2].uid == 18);
+       test_assert(memcmp(expunges[2].guid_128, guid3, sizeof(guid3)) == 0);
+       test_end();
+}
+
+int main(void)
+{
+       static void (*test_functions[])(void) = {
+               test_mail_index_transaction_finish_flag_updates,
+               test_mail_index_transaction_finish_check_conflicts,
+               test_mail_index_transaction_finish_expunges,
+               NULL
+       };
+       unsigned int i;
+
+       for (i = 1; i < N_ELEMENTS(recs); i++)
+               recs[i].uid = i;
+       return test_run(test_functions);
+}
index 07dcf7402b72a4a4619974f9ea4c0bfa5738817e..84d1baeffefc6984f5bd12977115f9cc3209373e 100644 (file)
@@ -329,6 +329,38 @@ static void test_mail_index_flag_update_random(void)
        test_end();
 }
 
+static void test_mail_index_cancel_flag_updates(void)
+{
+       struct mail_index_transaction *t;
+       const struct mail_transaction_flag_update *updates;
+       unsigned int count;
+
+       hdr.messages_count = 20;
+       t = mail_index_transaction_new();
+
+       test_begin("mail index cancel flag updates");
+
+       mail_index_update_flags_range(t, 5, 7, MODIFY_REPLACE, 0);
+       updates = array_get(&t->updates, &count);
+       test_assert(count == 1);
+       test_assert(updates[0].uid1 == 5 && updates[0].uid2 == 7);
+       mail_index_cancel_flag_updates(t, 5);
+       test_assert(updates[0].uid1 == 6 && updates[0].uid2 == 7);
+       mail_index_cancel_flag_updates(t, 7);
+       test_assert(updates[0].uid1 == 6 && updates[0].uid2 == 6);
+       mail_index_cancel_flag_updates(t, 6);
+       test_assert(!array_is_created(&t->updates));
+
+       mail_index_update_flags_range(t, 5, 7, MODIFY_REPLACE, 0);
+       mail_index_cancel_flag_updates(t, 6);
+       updates = array_get(&t->updates, &count);
+       test_assert(count == 2);
+       test_assert(updates[0].uid1 == 5 && updates[0].uid2 == 5);
+       test_assert(updates[1].uid1 == 7 && updates[1].uid2 == 7);
+
+       test_end();
+}
+
 static void test_mail_index_flag_update_appends(void)
 {
        struct mail_index_transaction *t;
@@ -419,6 +451,50 @@ static void test_mail_index_transaction_get_flag_update_pos(void)
        test_end();
 }
 
+static void test_mail_index_expunge(void)
+{
+       static uint8_t empty_guid[MAIL_GUID_128_SIZE] = { 0, };
+       struct mail_index_transaction *t;
+       const struct mail_transaction_expunge_guid *expunges;
+       uint8_t guid2[MAIL_GUID_128_SIZE];
+       uint8_t guid3[MAIL_GUID_128_SIZE];
+       uint8_t guid4[MAIL_GUID_128_SIZE];
+       unsigned int i, count;
+
+       test_begin("mail index expunge");
+
+       hdr.messages_count = 10;
+       t = mail_index_transaction_new();
+       for (i = 0; i < sizeof(guid2); i++) {
+               guid2[i] = i + 1;
+               guid3[i] = i ^ 0xff;
+               guid4[i] = i + 0x80;
+       }
+
+       mail_index_expunge_guid(t, 4, guid4);
+       test_assert(!t->expunges_nonsorted);
+       mail_index_expunge_guid(t, 2, guid2);
+       test_assert(t->expunges_nonsorted);
+       mail_index_expunge_guid(t, 3, guid3);
+       mail_index_expunge(t, 1);
+       mail_index_expunge(t, 5);
+
+       expunges = array_get(&t->expunges, &count);
+       test_assert(count == 5);
+       test_assert(expunges[0].uid == 4);
+       test_assert(memcmp(expunges[0].guid_128, guid4, sizeof(guid4)) == 0);
+       test_assert(expunges[1].uid == 2);
+       test_assert(memcmp(expunges[1].guid_128, guid2, sizeof(guid2)) == 0);
+       test_assert(expunges[2].uid == 3);
+       test_assert(memcmp(expunges[2].guid_128, guid3, sizeof(guid3)) == 0);
+       test_assert(expunges[3].uid == 1);
+       test_assert(memcmp(expunges[3].guid_128, empty_guid, sizeof(empty_guid)) == 0);
+       test_assert(expunges[4].uid == 5);
+       test_assert(memcmp(expunges[4].guid_128, empty_guid, sizeof(empty_guid)) == 0);
+
+       test_end();
+}
+
 int main(void)
 {
        static void (*test_functions[])(void) = {
@@ -428,7 +504,9 @@ int main(void)
                test_mail_index_flag_update_complex_merges,
                test_mail_index_flag_update_random,
                test_mail_index_flag_update_appends,
+               test_mail_index_cancel_flag_updates,
                test_mail_index_transaction_get_flag_update_pos,
+               test_mail_index_expunge,
                NULL
        };
        return test_run(test_functions);