]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
dsync: Fixed syncing \noselect mailboxes.
authorTimo Sirainen <tss@iki.fi>
Fri, 11 Jun 2010 21:36:38 +0000 (22:36 +0100)
committerTimo Sirainen <tss@iki.fi>
Fri, 11 Jun 2010 21:36:38 +0000 (22:36 +0100)
--HG--
branch : HEAD

src/dsync/dsync-brain.c
src/dsync/dsync-data.c
src/dsync/dsync-data.h
src/dsync/dsync-proxy-client.c
src/dsync/dsync-proxy-server-cmd.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-worker.c
src/dsync/test-dsync-worker.h

index adfdca6876be243f024885de8836f50de768f766..b3c37b2a78ea454fa90e85d6f28cda2e979f2b5b 100644 (file)
@@ -102,7 +102,7 @@ static void dsync_worker_mailbox_input(void *context)
                if (dsync_worker_mailbox_iter_deinit(&list->iter) < 0)
                        dsync_brain_fail(list->brain);
                array_sort(&list->mailboxes, dsync_mailbox_p_guid_cmp);
-               array_sort(&list->dirs, dsync_mailbox_p_name_cmp);
+               array_sort(&list->dirs, dsync_mailbox_p_name_sha1_cmp);
                dsync_brain_mailbox_list_finished(list->brain);
        }
 }
@@ -313,6 +313,76 @@ static void dsync_brain_sync_mailboxes(struct dsync_brain *brain)
        }
 }
 
+static void dsync_brain_sync_dirs(struct dsync_brain *brain)
+{
+       struct dsync_mailbox *const *src_boxes, *const *dest_boxes, new_box;
+       unsigned int src, dest, src_count, dest_count;
+       bool src_deleted, dest_deleted;
+       int ret;
+
+       memset(&new_box, 0, sizeof(new_box));
+
+       /* create/delete missing directories. */
+       src_boxes = array_get(&brain->src_mailbox_list->dirs, &src_count);
+       dest_boxes = array_get(&brain->dest_mailbox_list->dirs, &dest_count);
+       for (src = dest = 0; src < src_count && dest < dest_count; ) {
+               src_deleted = (src_boxes[src]->flags &
+                              DSYNC_MAILBOX_FLAG_DELETED_DIR) != 0;
+               dest_deleted = (dest_boxes[dest]->flags &
+                               DSYNC_MAILBOX_FLAG_DELETED_DIR) != 0;
+               ret = memcmp(src_boxes[src]->name_sha1.guid,
+                            dest_boxes[dest]->name_sha1.guid,
+                            sizeof(src_boxes[src]->name_sha1.guid));
+               if (ret < 0) {
+                       /* exists only in source */
+                       if (!src_deleted) {
+                               new_box = *src_boxes[src];
+                               dsync_worker_create_mailbox(brain->dest_worker,
+                                                           &new_box);
+                       }
+                       src++;
+               } else if (ret > 0) {
+                       /* exists only in dest */
+                       if (!dest_deleted) {
+                               new_box = *dest_boxes[dest];
+                               dsync_worker_create_mailbox(brain->src_worker,
+                                                           &new_box);
+                       }
+                       dest++;
+               } else if (src_deleted) {
+                       /* delete from dest too */
+                       if (!dest_deleted) {
+                               dsync_worker_delete_dir(brain->dest_worker,
+                                                       dest_boxes[dest]);
+                       }
+                       src++; dest++;
+               } else if (dest_deleted) {
+                       /* delete from src too */
+                       dsync_worker_delete_dir(brain->src_worker,
+                                               src_boxes[src]);
+                       src++; dest++;
+               } else {
+                       src++; dest++;
+               }
+       }
+       for (; src < src_count; src++) {
+               if ((src_boxes[src]->flags &
+                    DSYNC_MAILBOX_FLAG_DELETED_DIR) != 0)
+                       continue;
+
+               new_box = *src_boxes[src];
+               dsync_worker_create_mailbox(brain->dest_worker, &new_box);
+       }
+       for (; dest < dest_count; dest++) {
+               if ((dest_boxes[dest]->flags &
+                    DSYNC_MAILBOX_FLAG_DELETED_DIR) != 0)
+                       continue;
+
+               new_box = *dest_boxes[dest];
+               dsync_worker_create_mailbox(brain->src_worker, &new_box);
+       }
+}
+
 static bool
 dsync_brain_is_unsubscribed(struct dsync_brain_subs_list *list,
                            const struct dsync_worker_subscription *subs,
@@ -612,6 +682,7 @@ void dsync_brain_sync(struct dsync_brain *brain)
                break;
        case DSYNC_STATE_SYNC_MAILBOXES:
                dsync_brain_sync_mailboxes(brain);
+               dsync_brain_sync_dirs(brain);
                brain->state++;
                /* fall through */
        case DSYNC_STATE_SYNC_SUBSCRIPTIONS:
index 19f70cd674f04df531d761dd06dee4b62fa4300e..00e533e59e576df748a2b2173975a3788146c0ab 100644 (file)
@@ -62,16 +62,23 @@ int dsync_mailbox_p_guid_cmp(struct dsync_mailbox *const *box1,
        return dsync_mailbox_guid_cmp(*box1, *box2);
 }
 
-int dsync_mailbox_name_cmp(const struct dsync_mailbox *box1,
-                          const struct dsync_mailbox *box2)
+int dsync_mailbox_name_sha1_cmp(const struct dsync_mailbox *box1,
+                               const struct dsync_mailbox *box2)
 {
+       int ret;
+
+       ret = memcmp(box1->name_sha1.guid, box2->name_sha1.guid,
+                    sizeof(box1->name_sha1.guid));
+       if (ret != 0)
+               return ret;
+
        return strcmp(box1->name, box2->name);
 }
 
-int dsync_mailbox_p_name_cmp(struct dsync_mailbox *const *box1,
-                            struct dsync_mailbox *const *box2)
+int dsync_mailbox_p_name_sha1_cmp(struct dsync_mailbox *const *box1,
+                                 struct dsync_mailbox *const *box2)
 {
-       return dsync_mailbox_name_cmp(*box1, *box2);
+       return dsync_mailbox_name_sha1_cmp(*box1, *box2);
 }
 
 bool dsync_keyword_list_equals(const char *const *k1, const char *const *k2)
index 12f79dc7c40d0ee123f02a023147dbf351ecec53..a5e3a1df63d3437b4cee1f276e9ed98df31d1391 100644 (file)
@@ -66,10 +66,10 @@ int dsync_mailbox_guid_cmp(const struct dsync_mailbox *box1,
 int dsync_mailbox_p_guid_cmp(struct dsync_mailbox *const *box1,
                             struct dsync_mailbox *const *box2);
 
-int dsync_mailbox_name_cmp(const struct dsync_mailbox *box1,
-                          const struct dsync_mailbox *box2);
-int dsync_mailbox_p_name_cmp(struct dsync_mailbox *const *box1,
-                            struct dsync_mailbox *const *box2);
+int dsync_mailbox_name_sha1_cmp(const struct dsync_mailbox *box1,
+                               const struct dsync_mailbox *box2);
+int dsync_mailbox_p_name_sha1_cmp(struct dsync_mailbox *const *box1,
+                                 struct dsync_mailbox *const *box2);
 
 bool dsync_keyword_list_equals(const char *const *k1, const char *const *k2);
 
index 591981392c8809581c62c60c4221d1e63c686ff7..34917bf29e1c59a697f7f3dcfef5986835ab1e5b 100644 (file)
@@ -726,6 +726,25 @@ proxy_client_worker_delete_mailbox(struct dsync_worker *_worker,
        } T_END;
 }
 
+static void
+proxy_client_worker_delete_dir(struct dsync_worker *_worker,
+                              const struct dsync_mailbox *dsync_box)
+{
+       struct proxy_client_dsync_worker *worker =
+               (struct proxy_client_dsync_worker *)_worker;
+
+       i_assert(worker->save_input == NULL);
+
+       T_BEGIN {
+               string_t *str = t_str_new(128);
+
+               str_append(str, "DIR-DELETE\t");
+               str_tabescape_write(str, dsync_box->name);
+               str_printfa(str, "\t%s\n", dec2str(dsync_box->last_change));
+               o_stream_send(worker->output, str_data(str), str_len(str));
+       } T_END;
+}
+
 static void
 proxy_client_worker_rename_mailbox(struct dsync_worker *_worker,
                                   const mailbox_guid_t *mailbox,
@@ -1037,6 +1056,7 @@ struct dsync_worker_vfuncs proxy_client_dsync_worker = {
 
        proxy_client_worker_create_mailbox,
        proxy_client_worker_delete_mailbox,
+       proxy_client_worker_delete_dir,
        proxy_client_worker_rename_mailbox,
        proxy_client_worker_update_mailbox,
 
index 7df73e56c81f478cc93ec914ffbb58a0ea88f57a..501aa505f3df01e762c7bfa870f581d8501c86d0 100644 (file)
@@ -261,6 +261,21 @@ cmd_box_delete(struct dsync_proxy_server *server, const char *const *args)
        return 1;
 }
 
+static int
+cmd_dir_delete(struct dsync_proxy_server *server, const char *const *args)
+{
+       struct dsync_mailbox dsync_box;
+
+       if (str_array_length(args) < 2)
+               return -1;
+
+       memset(&dsync_box, 0, sizeof(dsync_box));
+       dsync_box.name = str_tabunescape(t_strdup_noconst(args[0]));
+       dsync_box.last_change = strtoul(args[1], NULL, 10);
+       dsync_worker_delete_dir(server->worker, &dsync_box);
+       return 1;
+}
+
 static int
 cmd_box_rename(struct dsync_proxy_server *server, const char *const *args)
 {
@@ -552,6 +567,7 @@ static struct dsync_proxy_server_command commands[] = {
        { "MSG-LIST", cmd_msg_list },
        { "BOX-CREATE", cmd_box_create },
        { "BOX-DELETE", cmd_box_delete },
+       { "DIR-DELETE", cmd_dir_delete },
        { "BOX-RENAME", cmd_box_rename },
        { "BOX-UPDATE", cmd_box_update },
        { "BOX-SELECT", cmd_box_select },
index d53897af0b0cfb62a13d3468bbe49e7ca25e5895..52c6692d52acf3a515d30ae332e9a09d511a31f0 100644 (file)
@@ -454,7 +454,8 @@ iter_next_deleted(struct local_dsync_worker_mailbox_iter *iter,
                        dsync_box_r->name = "";
                        dsync_box_r->name_sha1 = change->name_sha1;
                        dsync_box_r->last_change = change->last_delete;
-                       dsync_box_r->flags |= DSYNC_MAILBOX_FLAG_DELETED_DIR;
+                       dsync_box_r->flags |= DSYNC_MAILBOX_FLAG_NOSELECT |
+                               DSYNC_MAILBOX_FLAG_DELETED_DIR;
                        return 1;
                }
        }
@@ -478,7 +479,7 @@ local_worker_mailbox_iter_next(struct dsync_worker_mailbox_iter *_iter,
        struct mailbox_status status;
        uint8_t mailbox_guid[MAIL_GUID_128_SIZE];
        struct local_dsync_mailbox_change *change;
-       struct local_dsync_dir_change *dir_change;
+       struct local_dsync_dir_change *dir_change, change_lookup;
        const char *const *fields;
        unsigned int i, field_count;
 
@@ -491,17 +492,20 @@ local_worker_mailbox_iter_next(struct dsync_worker_mailbox_iter *_iter,
        dsync_box_r->name = info->name;
        dsync_box_r->name_sep = info->ns->sep;
 
+       storage_name = mail_namespace_get_storage_name(info->ns, info->name);
+       dsync_str_sha_to_guid(storage_name, &dsync_box_r->name_sha1);
+
        /* get last change timestamp */
-       dsync_str_sha_to_guid(info->name, &dsync_box_r->name_sha1);
-       dir_change = hash_table_lookup(worker->mailbox_changes_hash,
-                                      dsync_box_r->name_sha1.guid);
+       change_lookup.list = info->ns->list;
+       change_lookup.name_sha1 = dsync_box_r->name_sha1;
+       dir_change = hash_table_lookup(worker->dir_changes_hash,
+                                      &change_lookup);
        if (dir_change != NULL) {
                /* it shouldn't be marked as deleted, but drop it to be sure */
                dir_change->deleted_dir = FALSE;
                dsync_box_r->last_change = dir_change->last_rename;
        }
 
-       storage_name = mail_namespace_get_storage_name(info->ns, info->name);
        if ((info->flags & MAILBOX_NOSELECT) != 0) {
                dsync_box_r->flags |= DSYNC_MAILBOX_FLAG_NOSELECT;
                local_dsync_worker_add_mailbox(worker, info->ns, storage_name,
@@ -1135,6 +1139,27 @@ local_worker_delete_mailbox(struct dsync_worker *_worker,
        mailbox_list_set_changelog_timestamp(lbox->ns->list, (time_t)-1);
 }
 
+static void
+local_worker_delete_dir(struct dsync_worker *_worker,
+                       const struct dsync_mailbox *dsync_box)
+{
+       struct local_dsync_worker *worker =
+               (struct local_dsync_worker *)_worker;
+       struct mail_namespace *ns;
+       const char *storage_name;
+
+       storage_name = dsync_box->name;
+       ns = mail_namespace_find(worker->user->namespaces, &storage_name);
+
+       mailbox_list_set_changelog_timestamp(ns->list, dsync_box->last_change);
+       if (mailbox_list_delete_dir(ns->list, storage_name) < 0) {
+               i_error("Can't delete mailbox directory %s: %s",
+                       dsync_box->name,
+                       mailbox_list_get_last_error(ns->list, NULL));
+       }
+       mailbox_list_set_changelog_timestamp(ns->list, (time_t)-1);
+}
+
 static void
 local_worker_rename_mailbox(struct dsync_worker *_worker,
                            const mailbox_guid_t *mailbox,
@@ -1632,6 +1657,7 @@ struct dsync_worker_vfuncs local_dsync_worker = {
 
        local_worker_create_mailbox,
        local_worker_delete_mailbox,
+       local_worker_delete_dir,
        local_worker_rename_mailbox,
        local_worker_update_mailbox,
 
index faa2c3b76826454b90f84727b14805bf478e7d0b..8e6455583b00d71ca80bd2ba09cd0ed3a80c5765 100644 (file)
@@ -40,6 +40,8 @@ struct dsync_worker_vfuncs {
                               const struct dsync_mailbox *dsync_box);
        void (*delete_mailbox)(struct dsync_worker *worker,
                               const struct dsync_mailbox *dsync_box);
+       void (*delete_dir)(struct dsync_worker *worker,
+                          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 bf4d7f665d1965e69ae7da5f21b97c74f768cb95..7d9fc7b8478afb64092911c1419a4a9d0e3c7a10 100644 (file)
@@ -145,6 +145,14 @@ void dsync_worker_delete_mailbox(struct dsync_worker *worker,
        } T_END;
 }
 
+void dsync_worker_delete_dir(struct dsync_worker *worker,
+                            const struct dsync_mailbox *dsync_box)
+{
+       if (!worker->readonly) T_BEGIN {
+               worker->v.delete_dir(worker, dsync_box);
+       } T_END;
+}
+
 void dsync_worker_rename_mailbox(struct dsync_worker *worker,
                                 const mailbox_guid_t *mailbox,
                                 const struct dsync_mailbox *dsync_box)
index cd5717483e408807ba8384de25e1d204be3ad26b..34939c4bee8b768b2b3f5c0bfb5e3d56785f3eea 100644 (file)
@@ -101,6 +101,9 @@ void dsync_worker_create_mailbox(struct dsync_worker *worker,
 /* Delete mailbox/dir with given GUID. */
 void dsync_worker_delete_mailbox(struct dsync_worker *worker,
                                 const struct dsync_mailbox *dsync_box);
+/* Delete mailbox's directory. Fail if it would also delete mailbox. */
+void dsync_worker_delete_dir(struct dsync_worker *worker,
+                            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 cac2f6ceed9733f321641afb5e95323d2e565c11..c05936d0cc7d002d945688a4d5e2171865b91e81 100644 (file)
@@ -245,6 +245,20 @@ test_worker_delete_mailbox(struct dsync_worker *_worker,
        array_append(&worker->box_events, &event, 1);
 }
 
+static void
+test_worker_delete_dir(struct dsync_worker *_worker,
+                      const struct dsync_mailbox *dsync_box)
+{
+       struct test_dsync_worker *worker = (struct test_dsync_worker *)_worker;
+       struct test_dsync_box_event event;
+
+       memset(&event, 0, sizeof(event));
+       event.type = LAST_BOX_TYPE_DELETE_DIR;
+
+       event.box = *dsync_box;
+       array_append(&worker->box_events, &event, 1);
+}
+
 static void
 test_worker_rename_mailbox(struct dsync_worker *_worker,
                           const mailbox_guid_t *mailbox,
@@ -447,6 +461,7 @@ struct dsync_worker_vfuncs test_dsync_worker = {
 
        test_worker_create_mailbox,
        test_worker_delete_mailbox,
+       test_worker_delete_dir,
        test_worker_rename_mailbox,
        test_worker_update_mailbox,
 
index e908635cf4610169d5ed50ff816d8cbc5f717ee2..f2ce6bf0a061950ff5f0f1ca203203cea1ac72f9 100644 (file)
@@ -6,6 +6,7 @@
 enum test_dsync_last_box_type {
        LAST_BOX_TYPE_CREATE,
        LAST_BOX_TYPE_DELETE,
+       LAST_BOX_TYPE_DELETE_DIR,
        LAST_BOX_TYPE_RENAME,
        LAST_BOX_TYPE_UPDATE,
        LAST_BOX_TYPE_SUBSCRIBE,