]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
dsync: Write mailbox changelog records using original timestamps.
authorTimo Sirainen <tss@iki.fi>
Mon, 21 Dec 2009 20:17:08 +0000 (15:17 -0500)
committerTimo Sirainen <tss@iki.fi>
Mon, 21 Dec 2009 20:17:08 +0000 (15:17 -0500)
--HG--
branch : HEAD

15 files changed:
src/dsync/dsync-brain.c
src/dsync/dsync-data.h
src/dsync/dsync-proxy-client.c
src/dsync/dsync-proxy-server-cmd.c
src/dsync/dsync-proxy.c
src/dsync/dsync-worker-local.c
src/dsync/dsync-worker-private.h
src/dsync/dsync-worker.c
src/dsync/dsync-worker.h
src/dsync/test-dsync-brain.c
src/dsync/test-dsync-proxy-server-cmd.c
src/dsync/test-dsync-worker.c
src/lib-storage/mailbox-list-private.h
src/lib-storage/mailbox-list.c
src/lib-storage/mailbox-list.h

index df9ead81cc2aba8bb7c4bee90d9744b9d824d84d..1eb59bf9a7052bf966ceba8dd56b3df823f8d63d 100644 (file)
@@ -279,13 +279,13 @@ static void dsync_brain_sync_mailboxes(struct dsync_brain *brain)
                        /* delete from dest too */
                        if (!dest_deleted) {
                                dsync_worker_delete_mailbox(brain->dest_worker,
-                                       &dest_boxes[dest]->mailbox_guid);
+                                                           src_boxes[src]);
                        }
                        src++; dest++;
                } else if (dest_deleted) {
                        /* delete from src too */
                        dsync_worker_delete_mailbox(brain->src_worker,
-                               &src_boxes[src]->mailbox_guid);
+                                                   dest_boxes[dest]);
                        src++; dest++;
                } else {
                        src++; dest++;
@@ -315,7 +315,8 @@ static void dsync_brain_sync_mailboxes(struct dsync_brain *brain)
 
 static bool
 dsync_brain_is_unsubscribed(struct dsync_brain_subs_list *list,
-                           const struct dsync_worker_subscription *subs)
+                           const struct dsync_worker_subscription *subs,
+                           time_t *last_change_r)
 {
        const struct dsync_worker_unsubscription *unsubs;
        struct dsync_worker_unsubscription lookup;
@@ -324,16 +325,23 @@ dsync_brain_is_unsubscribed(struct dsync_brain_subs_list *list,
        dsync_str_sha_to_guid(subs->storage_name, &lookup.name_sha1);
        unsubs = array_bsearch(&list->unsubscriptions, &lookup,
                               dsync_worker_unsubscription_cmp);
-       if (unsubs == NULL)
+       if (unsubs == NULL) {
+               *last_change_r = 0;
                return FALSE;
-       else
-               return unsubs->last_change > subs->last_change;
+       } else if (unsubs->last_change <= subs->last_change) {
+               *last_change_r = subs->last_change;
+               return FALSE;
+       } else {
+               *last_change_r = unsubs->last_change;
+               return TRUE;
+       }
 }
 
 static void dsync_brain_sync_subscriptions(struct dsync_brain *brain)
 {
        const struct dsync_worker_subscription *src_subs, *dest_subs;
        unsigned int src, dest, src_count, dest_count;
+       time_t last_change;
        int ret;
 
        /* subscriptions are sorted by name. */
@@ -358,27 +366,29 @@ static void dsync_brain_sync_subscriptions(struct dsync_brain *brain)
                if (ret < 0) {
                        /* subscribed only in source */
                        if (dsync_brain_is_unsubscribed(brain->dest_subs_list,
-                                                       &src_subs[src])) {
+                                                       &src_subs[src],
+                                                       &last_change)) {
                                dsync_worker_set_subscribed(brain->src_worker,
                                                            src_subs[src].vname,
-                                                           FALSE);
+                                                           last_change, FALSE);
                        } else {
                                dsync_worker_set_subscribed(brain->dest_worker,
                                                            src_subs[src].vname,
-                                                           TRUE);
+                                                           last_change, TRUE);
                        }
                        src++;
                } else {
                        /* subscribed only in dest */
                        if (dsync_brain_is_unsubscribed(brain->src_subs_list,
-                                                       &dest_subs[dest])) {
+                                                       &dest_subs[dest],
+                                                       &last_change)) {
                                dsync_worker_set_subscribed(brain->dest_worker,
                                                            dest_subs[dest].vname,
-                                                           FALSE);
+                                                           last_change, FALSE);
                        } else {
                                dsync_worker_set_subscribed(brain->src_worker,
                                                            dest_subs[dest].vname,
-                                                           TRUE);
+                                                           last_change, TRUE);
                        }
                        dest++;
                }
@@ -532,7 +542,7 @@ static void
 dsync_brain_sync_rename_mailbox(struct dsync_brain *brain,
                                const struct dsync_brain_mailbox *mailbox)
 {
-       if (mailbox->src->last_renamed > mailbox->dest->last_renamed) {
+       if (mailbox->src->last_changed > mailbox->dest->last_changed) {
                dsync_worker_rename_mailbox(brain->dest_worker,
                                            &mailbox->box.mailbox_guid,
                                            mailbox->src);
index abff6be2d01cf94a4d6a084d20a1e7a1886c1514..f303d515763f5f5c97329d142fe8b83ca6f1de47 100644 (file)
@@ -24,7 +24,7 @@ struct dsync_mailbox {
 
        uint32_t uid_validity, uid_next;
        uint64_t highest_modseq;
-       time_t last_renamed;
+       time_t last_changed;
        enum dsync_mailbox_flags flags;
        ARRAY_TYPE(const_string) cache_fields;
 };
index b9012b4dd479703324b0bf720cfc0c9949c10a78..11319dc6c9db1eff9124f0ae1acd4a8b6031de0b 100644 (file)
@@ -545,7 +545,8 @@ proxy_client_worker_subs_iter_deinit(struct dsync_worker_subs_iter *_iter)
 
 static void
 proxy_client_worker_set_subscribed(struct dsync_worker *_worker,
-                                  const char *name, bool set)
+                                  const char *name, time_t last_change,
+                                  bool set)
 {
        struct proxy_client_dsync_worker *worker =
                (struct proxy_client_dsync_worker *)_worker;
@@ -555,7 +556,8 @@ proxy_client_worker_set_subscribed(struct dsync_worker *_worker,
 
                str_append(str, "SUBS-SET\t");
                str_tabescape_write(str, name);
-               str_printfa(str, "\t%d\n", set ? 1 : 0);
+               str_printfa(str, "\t%s\t%d\n", dec2str(last_change),
+                           set ? 1 : 0);
                o_stream_send(worker->output, str_data(str), str_len(str));
        } T_END;
 }
@@ -678,7 +680,7 @@ proxy_client_worker_create_mailbox(struct dsync_worker *_worker,
 
 static void
 proxy_client_worker_delete_mailbox(struct dsync_worker *_worker,
-                                  const mailbox_guid_t *mailbox)
+                                  const struct dsync_mailbox *dsync_box)
 {
        struct proxy_client_dsync_worker *worker =
                (struct proxy_client_dsync_worker *)_worker;
@@ -689,8 +691,8 @@ proxy_client_worker_delete_mailbox(struct dsync_worker *_worker,
                string_t *str = t_str_new(128);
 
                str_append(str, "BOX-DELETE\t");
-               dsync_proxy_mailbox_guid_export(str, mailbox);
-               str_append_c(str, '\n');
+               dsync_proxy_mailbox_guid_export(str, &dsync_box->mailbox_guid);
+               str_printfa(str, "\t%s\n", dec2str(dsync_box->last_changed));
                o_stream_send(worker->output, str_data(str), str_len(str));
        } T_END;
 }
index 47260ded6a3e8d354c8f958a93eadfa261f92216..879628f713f71cf67635cf3df416cdf452a7f644 100644 (file)
@@ -151,13 +151,14 @@ cmd_subs_list(struct dsync_proxy_server *server,
 static int
 cmd_subs_set(struct dsync_proxy_server *server, const char *const *args)
 {
-       if (args[0] == NULL || args[1] == NULL) {
+       if (str_array_length(args) < 3) {
                i_error("subs-set: Missing parameters");
                return -1;
        }
 
        dsync_worker_set_subscribed(server->worker, args[0],
-                                   strcmp(args[1], "1") == 0);
+                                   strtoul(args[1], NULL, 10),
+                                   strcmp(args[2], "1") == 0);
        return 1;
 }
 
@@ -244,14 +245,19 @@ static int
 cmd_box_delete(struct dsync_proxy_server *server, const char *const *args)
 {
        mailbox_guid_t guid;
+       struct dsync_mailbox dsync_box;
 
-       if (args[0] == NULL ||
-           dsync_proxy_mailbox_guid_import(args[0], &guid) < 0) {
+       if (str_array_length(args) < 2)
+               return -1;
+       if (dsync_proxy_mailbox_guid_import(args[0], &guid) < 0) {
                i_error("box-delete: Invalid mailbox GUID '%s'", args[0]);
                return -1;
        }
 
-       dsync_worker_delete_mailbox(server->worker, &guid);
+       memset(&dsync_box, 0, sizeof(dsync_box));
+       dsync_box.mailbox_guid = guid;
+       dsync_box.last_changed = strtoul(args[1], NULL, 10);
+       dsync_worker_delete_mailbox(server->worker, &dsync_box);
        return 1;
 }
 
index ee644e56d9f317ca1ac151be26b74e9e22c8d727..1c9c804b64604dc024cc16bc23626d3ea23b3d1e 100644 (file)
@@ -163,7 +163,7 @@ void dsync_proxy_mailbox_export(string_t *str,
        str_tabescape_write(str, s);
        str_append_c(str, '\t');
        dsync_proxy_mailbox_guid_export(str, &box->dir_guid);
-       str_printfa(str, "\t%lu\t%u", (unsigned long)box->last_renamed,
+       str_printfa(str, "\t%lu\t%u", (unsigned long)box->last_changed,
                    box->flags);
 
        if (mail_guid_128_is_empty(box->mailbox_guid.guid)) {
@@ -207,7 +207,7 @@ int dsync_proxy_mailbox_import_unescaped(pool_t pool, const char *const *args,
                *error_r = "Invalid dir GUID";
                return -1;
        }
-       box_r->last_renamed = strtoul(args[i++], &p, 10);
+       box_r->last_changed = strtoul(args[i++], &p, 10);
        if (*p != '\0') {
                *error_r = "Invalid mailbox last_renamed";
                return -1;
index 54a1f260535b80ef961506b6f44d064bffa23586..5414c71e7d67cca446462bfc857ab8fc5b838610 100644 (file)
@@ -51,6 +51,7 @@ struct local_dsync_mailbox {
 struct local_dsync_mailbox_change {
        mailbox_guid_t guid;
        time_t last_renamed;
+       time_t last_deleted;
        unsigned int deleted_mailbox:1;
        unsigned int deleted_dir:1;
 };
@@ -126,15 +127,8 @@ struct dsync_worker *
 dsync_worker_init_local(struct mail_user *user, char alt_char)
 {
        struct local_dsync_worker *worker;
-       struct mail_namespace *ns;
        pool_t pool;
 
-       /* whatever we do, we do it because we're trying to sync,
-          not because of a user action. don't log these mailbox list changes
-          so we don't do wrong decisions on future syncs. */
-       for (ns = user->namespaces; ns != NULL; ns = ns->next)
-               mailbox_list_set_changelog_writable(ns->list, FALSE);
-
        pool = pool_alloconly_create("local dsync worker", 10240);
        worker = p_new(pool, struct local_dsync_worker, 1);
        worker->worker.v = local_dsync_worker;
@@ -181,6 +175,7 @@ dsync_worker_save_mailbox_change(struct local_dsync_worker *worker,
                                 const struct mailbox_log_record *rec)
 {
        struct local_dsync_mailbox_change *change;
+       time_t stamp;
 
        change = hash_table_lookup(worker->mailbox_changes_hash,
                                   rec->mailbox_guid);
@@ -191,16 +186,20 @@ dsync_worker_save_mailbox_change(struct local_dsync_worker *worker,
                hash_table_insert(worker->mailbox_changes_hash,
                                  change->guid.guid, change);
        }
+
+       stamp = mailbox_log_record_get_timestamp(rec);
        switch (rec->type) {
        case MAILBOX_LOG_RECORD_DELETE_MAILBOX:
                change->deleted_mailbox = TRUE;
+               if (change->last_deleted < stamp)
+                       change->last_deleted = stamp;
                break;
        case MAILBOX_LOG_RECORD_DELETE_DIR:
                change->deleted_dir = TRUE;
                break;
        case MAILBOX_LOG_RECORD_RENAME:
-               change->last_renamed =
-                       mailbox_log_record_get_timestamp(rec);
+               if (change->last_renamed < stamp)
+                       change->last_renamed = stamp;
                break;
        case MAILBOX_LOG_RECORD_SUBSCRIBE:
        case MAILBOX_LOG_RECORD_UNSUBSCRIBE:
@@ -220,12 +219,14 @@ dsync_worker_save_subscription_change(struct local_dsync_worker *worker,
                                      const struct mailbox_log_record *rec)
 {
        struct local_dsync_subscription_change *change, new_change;
+       time_t stamp;
 
        memset(&new_change, 0, sizeof(new_change));
        new_change.list = list;
        memcpy(new_change.name_sha1.guid, rec->mailbox_guid,
               sizeof(new_change.name_sha1.guid));
 
+       stamp = mailbox_log_record_get_timestamp(rec);
        change = hash_table_lookup(worker->subscription_changes_hash,
                                   &new_change);
        if (change == NULL) {
@@ -233,7 +234,13 @@ dsync_worker_save_subscription_change(struct local_dsync_worker *worker,
                *change = new_change;
                hash_table_insert(worker->subscription_changes_hash,
                                  change, change);
+       } else if (change->last_change > stamp) {
+               /* we've already seen a newer subscriptions state. this is
+                  probably a stale record created by dsync */
+               return;
        }
+       change->last_change = stamp;
+
        switch (rec->type) {
        case MAILBOX_LOG_RECORD_DELETE_MAILBOX:
        case MAILBOX_LOG_RECORD_DELETE_DIR:
@@ -246,7 +253,6 @@ dsync_worker_save_subscription_change(struct local_dsync_worker *worker,
                change->unsubscribed = TRUE;
                break;
        }
-       change->last_change = mailbox_log_record_get_timestamp(rec);
 }
 
 static int
@@ -391,6 +397,7 @@ iter_next_deleted(struct local_dsync_worker_mailbox_iter *iter,
                        /* the name doesn't matter */
                        dsync_box_r->name = "";
                        dsync_box_r->mailbox_guid = change->guid;
+                       dsync_box_r->last_changed = change->last_deleted;
                        dsync_box_r->flags |=
                                DSYNC_MAILBOX_FLAG_DELETED_MAILBOX;
                        return 1;
@@ -399,6 +406,7 @@ iter_next_deleted(struct local_dsync_worker_mailbox_iter *iter,
                        /* the name doesn't matter */
                        dsync_box_r->name = "";
                        dsync_box_r->dir_guid = change->guid;
+                       dsync_box_r->last_changed = change->last_deleted;
                        dsync_box_r->flags |= DSYNC_MAILBOX_FLAG_DELETED_DIR;
                        return 1;
                }
@@ -442,13 +450,13 @@ local_worker_mailbox_iter_next(struct dsync_worker_mailbox_iter *_iter,
                return -1;
        }
 
-       /* get last rename timestamp */
+       /* get last change timestamp */
        change = hash_table_lookup(worker->mailbox_changes_hash,
                                   dsync_box_r->dir_guid.guid);
        if (change != NULL) {
                /* it shouldn't be marked as deleted, but drop it to be sure */
                change->deleted_dir = FALSE;
-               dsync_box_r->last_renamed = change->last_renamed;
+               dsync_box_r->last_changed = change->last_renamed;
        }
 
        storage_name = mail_namespace_get_storage_name(info->ns, info->name);
@@ -615,7 +623,7 @@ local_worker_subs_iter_deinit(struct dsync_worker_subs_iter *_iter)
 
 static void
 local_worker_set_subscribed(struct dsync_worker *_worker,
-                           const char *name, bool set)
+                           const char *name, time_t last_change, bool set)
 {
        struct local_dsync_worker *worker =
                (struct local_dsync_worker *)_worker;
@@ -629,11 +637,13 @@ local_worker_set_subscribed(struct dsync_worker *_worker,
                return;
        }
 
+       mailbox_list_set_changelog_timestamp(ns->list, last_change);
        if (mailbox_list_set_subscribed(ns->list, storage_name, set) < 0) {
                dsync_worker_set_failure(_worker);
                i_error("Can't update subscription %s: %s", name,
                        mailbox_list_get_last_error(ns->list, NULL));
        }
+       mailbox_list_set_changelog_timestamp(ns->list, (time_t)-1);
 }
 
 static int local_mailbox_open(struct local_dsync_worker *worker,
@@ -1010,11 +1020,12 @@ local_worker_create_mailbox(struct dsync_worker *_worker,
 
 static void
 local_worker_delete_mailbox(struct dsync_worker *_worker,
-                           const mailbox_guid_t *mailbox)
+                           const struct dsync_mailbox *dsync_box)
 {
        struct local_dsync_worker *worker =
                (struct local_dsync_worker *)_worker;
        struct local_dsync_mailbox *lbox;
+       const mailbox_guid_t *mailbox = &dsync_box->mailbox_guid;
 
        lbox = hash_table_lookup(worker->mailbox_hash, mailbox);
        if (lbox == NULL) {
@@ -1024,12 +1035,15 @@ local_worker_delete_mailbox(struct dsync_worker *_worker,
                return;
        }
 
+       mailbox_list_set_changelog_timestamp(lbox->ns->list,
+                                            dsync_box->last_changed);
        if (mailbox_list_delete_mailbox(lbox->ns->list,
                                        lbox->storage_name) < 0) {
                i_error("Can't delete mailbox %s: %s", lbox->storage_name,
                        mailbox_list_get_last_error(lbox->ns->list, NULL));
                dsync_worker_set_failure(_worker);
        }
+       mailbox_list_set_changelog_timestamp(lbox->ns->list, (time_t)-1);
 }
 
 static void
@@ -1086,6 +1100,7 @@ local_worker_rename_mailbox(struct dsync_worker *_worker,
                return;
        }
 
+       mailbox_list_set_changelog_timestamp(list, dsync_box->last_changed);
        if (mailbox_list_rename_mailbox(list, lbox->storage_name,
                                        list, newname, TRUE) < 0) {
                i_error("Can't rename mailbox %s to %s: %s", lbox->storage_name,
@@ -1097,6 +1112,7 @@ local_worker_rename_mailbox(struct dsync_worker *_worker,
                local_worker_rename_children(worker, oldname, newname,
                                             lbox->ns->sep);
        }
+       mailbox_list_set_changelog_timestamp(list, (time_t)-1);
 }
 
 static bool
index caa58fb874cbc40787fe832d0a0f94b8ab5c804a..faa2c3b76826454b90f84727b14805bf478e7d0b 100644 (file)
@@ -25,7 +25,7 @@ struct dsync_worker_vfuncs {
                                 struct dsync_worker_unsubscription *rec_r);
        int (*subs_iter_deinit)(struct dsync_worker_subs_iter *iter);
        void (*set_subscribed)(struct dsync_worker *worker,
-                              const char *name, bool set);
+                              const char *name, time_t last_change, bool set);
 
        struct dsync_worker_msg_iter *
                (*msg_iter_init)(struct dsync_worker *worker,
@@ -39,7 +39,7 @@ struct dsync_worker_vfuncs {
        void (*create_mailbox)(struct dsync_worker *worker,
                               const struct dsync_mailbox *dsync_box);
        void (*delete_mailbox)(struct dsync_worker *worker,
-                              const mailbox_guid_t *mailbox);
+                              const struct dsync_mailbox *dsync_box);
        void (*rename_mailbox)(struct dsync_worker *worker,
                               const mailbox_guid_t *mailbox,
                               const struct dsync_mailbox *dsync_box);
index 90dea7968f3cbac0f899f0eb08501a7b6f001b63..c528a5d896fb4c0c48167223476de226faf0de77 100644 (file)
@@ -88,9 +88,9 @@ int dsync_worker_subs_iter_deinit(struct dsync_worker_subs_iter **_iter)
 }
 
 void dsync_worker_set_subscribed(struct dsync_worker *worker,
-                                const char *name, bool set)
+                                const char *name, time_t last_change, bool set)
 {
-       worker->v.set_subscribed(worker, name, set);
+       worker->v.set_subscribed(worker, name, last_change, set);
 }
 
 struct dsync_worker_msg_iter *
@@ -132,10 +132,10 @@ void dsync_worker_create_mailbox(struct dsync_worker *worker,
 }
 
 void dsync_worker_delete_mailbox(struct dsync_worker *worker,
-                                const mailbox_guid_t *mailbox)
+                                const struct dsync_mailbox *dsync_box)
 {
        if (!worker->readonly)
-               worker->v.delete_mailbox(worker, mailbox);
+               worker->v.delete_mailbox(worker, dsync_box);
 }
 
 void dsync_worker_rename_mailbox(struct dsync_worker *worker,
index 8add5e953bb822be790e3c38467150bce529d536..cd5717483e408807ba8384de25e1d204be3ad26b 100644 (file)
@@ -75,7 +75,8 @@ int dsync_worker_subs_iter_next_un(struct dsync_worker_subs_iter *iter,
 int dsync_worker_subs_iter_deinit(struct dsync_worker_subs_iter **iter);
 /* Subscribe/unsubscribe mailbox */
 void dsync_worker_set_subscribed(struct dsync_worker *worker,
-                                const char *name, bool set);
+                                const char *name, time_t last_change,
+                                bool set);
 
 /* Iterate through all messages in given mailboxes. The mailboxes are iterated
    in the given order. */
@@ -99,7 +100,7 @@ void dsync_worker_create_mailbox(struct dsync_worker *worker,
                                 const struct dsync_mailbox *dsync_box);
 /* Delete mailbox/dir with given GUID. */
 void dsync_worker_delete_mailbox(struct dsync_worker *worker,
-                                const mailbox_guid_t *mailbox);
+                                const struct dsync_mailbox *dsync_box);
 /* Change a mailbox and its childrens' name. The name is taken from the given
    dsync_box (applying name_sep if necessary). */
 void dsync_worker_rename_mailbox(struct dsync_worker *worker,
index c8ce958a867aadee7f914dcf738e8fe9926c08b8..f7a29cfb8939faa30e43dcbbc6267d24a21605ce 100644 (file)
@@ -92,7 +92,8 @@ test_dsync_mailbox_delete_equals(const struct dsync_mailbox *dbox,
                                 const struct dsync_mailbox *obox)
 {
        return memcmp(dbox->mailbox_guid.guid, obox->mailbox_guid.guid,
-                     sizeof(dbox->mailbox_guid.guid)) == 0;
+                     sizeof(dbox->mailbox_guid.guid)) == 0 &&
+               dbox->last_changed == obox->last_changed;
 }
 
 static void
index a46624550a5980e65a6866252bc4f9957ec848a7..2ceaf09ef17695bc99a6c926bd2209d5c5b2da50 100644 (file)
@@ -75,7 +75,7 @@ static void test_dsync_proxy_box_list(void)
        memset(&box, 0, sizeof(box));
        box.name = "\t\001\r\nname\t\001\n\r";
        box.name_sep = '/';
-       box.last_renamed = 992;
+       box.last_changed = 992;
        box.flags = 123;
        memcpy(box.dir_guid.guid, test_mailbox_guid1, MAIL_GUID_128_SIZE);
        test_worker->box_iter.next_box = &box;
@@ -227,7 +227,7 @@ static void test_dsync_proxy_box_create(void)
        test_assert(strcmp(event.box.name, "noselect") == 0);
        test_assert(event.box.name_sep == '/');
        test_assert(memcmp(event.box.dir_guid.guid, test_mailbox_guid2, MAIL_GUID_128_SIZE) == 0);
-       test_assert(event.box.last_renamed == 553);
+       test_assert(event.box.last_changed == 553);
        test_assert(event.box.flags == 99);
        test_assert(event.box.uid_validity == 0);
 
@@ -244,7 +244,7 @@ static void test_dsync_proxy_box_create(void)
        test_assert(event.box.uid_validity == 1234567890);
        test_assert(event.box.uid_next == 9876);
        test_assert(event.box.highest_modseq == 28427847284728);
-       test_assert(event.box.last_renamed == 61);
+       test_assert(event.box.last_changed == 61);
 
        test_end();
 }
@@ -255,15 +255,17 @@ static void test_dsync_proxy_box_delete(void)
 
        test_begin("proxy server box delete");
 
-       test_assert(run_cmd("BOX-DELETE", TEST_MAILBOX_GUID1, NULL) == 1);
+       test_assert(run_cmd("BOX-DELETE", TEST_MAILBOX_GUID1, "4351", NULL) == 1);
        test_assert(test_dsync_worker_next_box_event(test_worker, &event));
        test_assert(event.type == LAST_BOX_TYPE_DELETE);
        test_assert(memcmp(event.box.mailbox_guid.guid, test_mailbox_guid1, MAIL_GUID_128_SIZE) == 0);
+       test_assert(event.box.last_changed == 4351);
 
-       test_assert(run_cmd("BOX-DELETE", TEST_MAILBOX_GUID2, NULL) == 1);
+       test_assert(run_cmd("BOX-DELETE", TEST_MAILBOX_GUID2, "653", NULL) == 1);
        test_assert(test_dsync_worker_next_box_event(test_worker, &event));
        test_assert(event.type == LAST_BOX_TYPE_DELETE);
        test_assert(memcmp(event.box.mailbox_guid.guid, test_mailbox_guid2, MAIL_GUID_128_SIZE) == 0);
+       test_assert(event.box.last_changed == 653);
 
        test_end();
 }
@@ -310,7 +312,7 @@ static void test_dsync_proxy_box_update(void)
        test_assert(event.box.uid_validity == 34343);
        test_assert(event.box.uid_next == 22);
        test_assert(event.box.highest_modseq == 2238427847284728);
-       test_assert(event.box.last_renamed == 53);
+       test_assert(event.box.last_changed == 53);
 
        test_end();
 }
index a0f1dbfbc7cb77ecd2b030ab0d28590f0908dcaf..916791537f19c7860641ad0a9dea573b5282173e 100644 (file)
@@ -212,12 +212,13 @@ bool test_dsync_worker_next_box_event(struct test_dsync_worker *worker,
 
 static void
 test_worker_set_subscribed(struct dsync_worker *_worker,
-                          const char *name, bool set)
+                          const char *name, time_t last_change, bool set)
 {
        struct dsync_mailbox dsync_box;
 
        memset(&dsync_box, 0, sizeof(dsync_box));
        dsync_box.name = name;
+       dsync_box.last_changed = last_change;
        test_worker_set_last_box(_worker, &dsync_box,
                                 set ? LAST_BOX_TYPE_SUBSCRIBE :
                                 LAST_BOX_TYPE_UNSUBSCRIBE);
@@ -232,7 +233,7 @@ test_worker_create_mailbox(struct dsync_worker *_worker,
 
 static void
 test_worker_delete_mailbox(struct dsync_worker *_worker,
-                          const mailbox_guid_t *mailbox)
+                          const struct dsync_mailbox *dsync_box)
 {
        struct test_dsync_worker *worker = (struct test_dsync_worker *)_worker;
        struct test_dsync_box_event event;
@@ -240,8 +241,7 @@ test_worker_delete_mailbox(struct dsync_worker *_worker,
        memset(&event, 0, sizeof(event));
        event.type = LAST_BOX_TYPE_DELETE;
 
-       event.box.mailbox_guid = *mailbox;
-       event.box.name = "";
+       event.box = *dsync_box;
        array_append(&worker->box_events, &event, 1);
 }
 
index 8eb47f03e0554d7fa3c4e5f396afdfcb3cee8857..fb7107fe8f0f47737c6a698106484f8c7db16bcb 100644 (file)
@@ -101,14 +101,13 @@ struct mailbox_list {
        const char *file_create_gid_origin;
 
        struct mailbox_log *changelog;
+       time_t changelog_timestamp;
 
        char *error_string;
        enum mail_error error;
        bool temporary_error;
 
        ARRAY_DEFINE(module_contexts, union mailbox_list_module_context *);
-
-       unsigned int changelog_disabled:1;
 };
 
 struct mailbox_list_iterate_context {
index 38f64fdcba7a19753dc22a751b4067cf5d37e468..cab441bdde5931fbb7dc6671273c88cf88a67769 100644 (file)
@@ -123,6 +123,7 @@ int mailbox_list_create(const char *driver, struct mail_namespace *ns,
        list->file_create_mode = (mode_t)-1;
        list->dir_create_mode = (mode_t)-1;
        list->file_create_gid = (gid_t)-1;
+       list->changelog_timestamp = (time_t)-1;
 
        /* copy settings */
        list->set.root_dir = p_strdup(list->pool, set->root_dir);
@@ -697,15 +698,19 @@ void mailbox_list_add_change(struct mailbox_list *list,
                             const uint8_t mailbox_guid[MAIL_GUID_128_SIZE])
 {
        struct mailbox_log_record rec;
+       time_t stamp;
 
-       if (!mailbox_list_init_changelog(list) || list->changelog_disabled ||
+       if (!mailbox_list_init_changelog(list) ||
            mail_guid_128_is_empty(mailbox_guid))
                return;
 
+       stamp = list->changelog_timestamp != (time_t)-1 ?
+               list->changelog_timestamp : ioloop_time;
+
        memset(&rec, 0, sizeof(rec));
        rec.type = type;
        memcpy(rec.mailbox_guid, mailbox_guid, sizeof(rec.mailbox_guid));
-       mailbox_log_record_set_timestamp(&rec, ioloop_time);
+       mailbox_log_record_set_timestamp(&rec, stamp);
        (void)mailbox_log_append(list->changelog, &rec);
 }
 
@@ -916,9 +921,10 @@ struct mailbox_log *mailbox_list_get_changelog(struct mailbox_list *list)
        return !mailbox_list_init_changelog(list) ? NULL : list->changelog;
 }
 
-void mailbox_list_set_changelog_writable(struct mailbox_list *list, bool set)
+void mailbox_list_set_changelog_timestamp(struct mailbox_list *list,
+                                         time_t stamp)
 {
-       list->changelog_disabled = !set;
+       list->changelog_timestamp = stamp;
 }
 
 static int mailbox_list_try_delete(struct mailbox_list *list, const char *dir)
index 5cdacbe2492df79ce2f2638093aecfc397793400..7f2335759cfbf6aa7013af410f2db979ff4ea8b9 100644 (file)
@@ -194,8 +194,11 @@ int mailbox_list_get_guid(struct mailbox_list *list, const char *name,
                          uint8_t mailbox_guid[MAIL_GUID_128_SIZE]);
 /* Returns mailbox's change log, or NULL if it doesn't have one. */
 struct mailbox_log *mailbox_list_get_changelog(struct mailbox_list *list);
-/* Enable/disable writing mailbox changes to changelog. */
-void mailbox_list_set_changelog_writable(struct mailbox_list *list, bool set);
+/* Specify timestamp to use when writing mailbox changes to changelog.
+   The same timestamp is used until stamp is set to (time_t)-1, after which
+   current time is used */
+void mailbox_list_set_changelog_timestamp(struct mailbox_list *list,
+                                         time_t stamp);
 
 /* Returns a prefix that temporary files should use without conflicting
    with the namespace. */