Mercurial > dovecot > core-2.2
diff src/dsync/dsync-brain.c @ 11676:cf7f6912af02 HEAD
dsync: Added backup command, which syncs source to destination, discarding any changes in dest.
It doesn't work perfectly in all situations. Especially if destination had
saved/expunged mails in INBOX, dsync can't resolve it. For non-INBOXes it
deletes the mailbox and fails a bit later, so that the next dsync can do a
full resync for the mailbox.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 01 Jul 2010 17:02:20 +0100 |
parents | c955d4789553 |
children | b4f029f7793a |
line wrap: on
line diff
--- a/src/dsync/dsync-brain.c Thu Jul 01 16:38:12 2010 +0100 +++ b/src/dsync/dsync-brain.c Thu Jul 01 17:02:20 2010 +0100 @@ -25,6 +25,7 @@ brain->mailbox = i_strdup(mailbox); brain->flags = flags; brain->verbose = (flags & DSYNC_BRAIN_FLAG_VERBOSE) != 0; + brain->backup = (flags & DSYNC_BRAIN_FLAG_BACKUP) != 0; return brain; } @@ -235,20 +236,68 @@ pool_unref(&list->pool); } +enum dsync_brain_mailbox_action { + DSYNC_BRAIN_MAILBOX_ACTION_NONE, + DSYNC_BRAIN_MAILBOX_ACTION_CREATE, + DSYNC_BRAIN_MAILBOX_ACTION_DELETE +}; + +static void +dsync_brain_mailbox_action(struct dsync_brain *brain, + enum dsync_brain_mailbox_action action, + struct dsync_worker *action_worker, + struct dsync_mailbox *action_box) +{ + struct dsync_mailbox new_box; + + if (brain->backup && action_worker == brain->src_worker) { + /* backup mode: switch actions */ + action_worker = brain->dest_worker; + switch (action) { + case DSYNC_BRAIN_MAILBOX_ACTION_NONE: + break; + case DSYNC_BRAIN_MAILBOX_ACTION_CREATE: + action = DSYNC_BRAIN_MAILBOX_ACTION_DELETE; + break; + case DSYNC_BRAIN_MAILBOX_ACTION_DELETE: + action = DSYNC_BRAIN_MAILBOX_ACTION_CREATE; + break; + } + } + + switch (action) { + case DSYNC_BRAIN_MAILBOX_ACTION_NONE: + break; + case DSYNC_BRAIN_MAILBOX_ACTION_CREATE: + new_box = *action_box; + new_box.uid_next = 0; + new_box.highest_modseq = 0; + dsync_worker_create_mailbox(action_worker, &new_box); + break; + case DSYNC_BRAIN_MAILBOX_ACTION_DELETE: + if (!dsync_mailbox_is_noselect(action_box)) + dsync_worker_delete_mailbox(action_worker, action_box); + else + dsync_worker_delete_dir(action_worker, action_box); + break; + } +} + static void dsync_brain_sync_mailboxes(struct dsync_brain *brain) { - struct dsync_mailbox *const *src_boxes, *const *dest_boxes, new_box; + struct dsync_mailbox *const *src_boxes, *const *dest_boxes, *action_box; unsigned int src, dest, src_count, dest_count; + enum dsync_brain_mailbox_action action; + struct dsync_worker *action_worker; bool src_deleted, dest_deleted; int ret; - memset(&new_box, 0, sizeof(new_box)); - /* create/delete missing mailboxes. the mailboxes are sorted by GUID, so we can do this quickly. */ src_boxes = array_get(&brain->src_mailbox_list->mailboxes, &src_count); dest_boxes = array_get(&brain->dest_mailbox_list->mailboxes, &dest_count); for (src = dest = 0; src < src_count && dest < dest_count; ) { + action = DSYNC_BRAIN_MAILBOX_ACTION_NONE; src_deleted = (src_boxes[src]->flags & DSYNC_MAILBOX_FLAG_DELETED_MAILBOX) != 0; dest_deleted = (dest_boxes[dest]->flags & @@ -258,74 +307,73 @@ if (ret < 0) { /* exists only in source */ if (!src_deleted) { - new_box = *src_boxes[src]; - new_box.uid_next = 0; - new_box.highest_modseq = 0; - dsync_worker_create_mailbox(brain->dest_worker, - &new_box); + action = DSYNC_BRAIN_MAILBOX_ACTION_CREATE; + action_worker = brain->dest_worker; + action_box = src_boxes[src]; } src++; } else if (ret > 0) { /* exists only in dest */ if (!dest_deleted) { - new_box = *dest_boxes[dest]; - new_box.uid_next = 0; - new_box.highest_modseq = 0; - dsync_worker_create_mailbox(brain->src_worker, - &new_box); + action = DSYNC_BRAIN_MAILBOX_ACTION_CREATE; + action_worker = brain->src_worker; + action_box = dest_boxes[dest]; } dest++; } else if (src_deleted) { /* delete from dest too */ if (!dest_deleted) { - dsync_worker_delete_mailbox(brain->dest_worker, - src_boxes[src]); + action = DSYNC_BRAIN_MAILBOX_ACTION_DELETE; + action_worker = brain->dest_worker; + action_box = dest_boxes[dest]; } src++; dest++; } else if (dest_deleted) { /* delete from src too */ - dsync_worker_delete_mailbox(brain->src_worker, - dest_boxes[dest]); + action = DSYNC_BRAIN_MAILBOX_ACTION_DELETE; + action_worker = brain->src_worker; + action_box = src_boxes[src]; src++; dest++; } else { src++; dest++; } + dsync_brain_mailbox_action(brain, action, + action_worker, action_box); } for (; src < src_count; src++) { if ((src_boxes[src]->flags & DSYNC_MAILBOX_FLAG_DELETED_MAILBOX) != 0) continue; - new_box = *src_boxes[src]; - new_box.uid_next = 0; - new_box.highest_modseq = 0; - dsync_worker_create_mailbox(brain->dest_worker, &new_box); + dsync_brain_mailbox_action(brain, + DSYNC_BRAIN_MAILBOX_ACTION_CREATE, + brain->dest_worker, src_boxes[src]); } for (; dest < dest_count; dest++) { if ((dest_boxes[dest]->flags & DSYNC_MAILBOX_FLAG_DELETED_MAILBOX) != 0) continue; - new_box = *dest_boxes[dest]; - new_box.uid_next = 0; - new_box.highest_modseq = 0; - dsync_worker_create_mailbox(brain->src_worker, &new_box); + dsync_brain_mailbox_action(brain, + DSYNC_BRAIN_MAILBOX_ACTION_CREATE, + brain->src_worker, dest_boxes[dest]); } } static void dsync_brain_sync_dirs(struct dsync_brain *brain) { - struct dsync_mailbox *const *src_boxes, *const *dest_boxes, new_box; + struct dsync_mailbox *const *src_boxes, *const *dest_boxes, *action_box; unsigned int src, dest, src_count, dest_count; + enum dsync_brain_mailbox_action action; + struct dsync_worker *action_worker; 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; ) { + action = DSYNC_BRAIN_MAILBOX_ACTION_NONE; src_deleted = (src_boxes[src]->flags & DSYNC_MAILBOX_FLAG_DELETED_DIR) != 0; dest_deleted = (dest_boxes[dest]->flags & @@ -336,50 +384,57 @@ if (ret < 0) { /* exists only in source */ if (!src_deleted) { - new_box = *src_boxes[src]; - dsync_worker_create_mailbox(brain->dest_worker, - &new_box); + action = DSYNC_BRAIN_MAILBOX_ACTION_CREATE; + action_worker = brain->dest_worker; + action_box = src_boxes[src]; } 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); + action = DSYNC_BRAIN_MAILBOX_ACTION_CREATE; + action_worker = brain->src_worker; + action_box = dest_boxes[dest]; } dest++; } else if (src_deleted) { /* delete from dest too */ if (!dest_deleted) { - dsync_worker_delete_dir(brain->dest_worker, - dest_boxes[dest]); + action = DSYNC_BRAIN_MAILBOX_ACTION_DELETE; + action_worker = brain->dest_worker; + action_box = dest_boxes[dest]; } src++; dest++; } else if (dest_deleted) { /* delete from src too */ - dsync_worker_delete_dir(brain->src_worker, - src_boxes[src]); + action = DSYNC_BRAIN_MAILBOX_ACTION_DELETE; + action_worker = brain->src_worker; + action_box = src_boxes[src]; src++; dest++; } else { src++; dest++; } + i_assert(dsync_mailbox_is_noselect(action_box)); + dsync_brain_mailbox_action(brain, action, + action_worker, action_box); } 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); + dsync_brain_mailbox_action(brain, + DSYNC_BRAIN_MAILBOX_ACTION_CREATE, + brain->dest_worker, src_boxes[src]); } 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); + dsync_brain_mailbox_action(brain, + DSYNC_BRAIN_MAILBOX_ACTION_CREATE, + brain->src_worker, dest_boxes[dest]); } } @@ -410,8 +465,11 @@ static void dsync_brain_sync_subscriptions(struct dsync_brain *brain) { const struct dsync_worker_subscription *src_subs, *dest_subs; + const struct dsync_worker_subscription *action_subs; + struct dsync_worker *action_worker; unsigned int src, dest, src_count, dest_count; time_t last_change; + bool subscribe; int ret; /* subscriptions are sorted by name. */ @@ -435,33 +493,40 @@ if (ret < 0) { /* subscribed only in source */ + action_subs = &src_subs[src]; if (dsync_brain_is_unsubscribed(brain->dest_subs_list, &src_subs[src], &last_change)) { - dsync_worker_set_subscribed(brain->src_worker, - src_subs[src].vname, - last_change, FALSE); + action_worker = brain->src_worker; + subscribe = FALSE; } else { - dsync_worker_set_subscribed(brain->dest_worker, - src_subs[src].vname, - last_change, TRUE); + action_worker = brain->dest_worker; + subscribe = TRUE; } src++; } else { /* subscribed only in dest */ + action_subs = &dest_subs[dest]; if (dsync_brain_is_unsubscribed(brain->src_subs_list, &dest_subs[dest], &last_change)) { - dsync_worker_set_subscribed(brain->dest_worker, - dest_subs[dest].vname, - last_change, FALSE); + action_worker = brain->dest_worker; + subscribe = FALSE; } else { - dsync_worker_set_subscribed(brain->src_worker, - dest_subs[dest].vname, - last_change, TRUE); + action_worker = brain->src_worker; + subscribe = TRUE; } dest++; } + + if (brain->backup && action_worker == brain->src_worker) { + /* backup mode: switch action */ + action_worker = brain->dest_worker; + subscribe = !subscribe; + last_change = ioloop_time; + } + dsync_worker_set_subscribed(action_worker, action_subs->vname, + last_change, subscribe); } } @@ -612,7 +677,8 @@ dsync_brain_sync_rename_mailbox(struct dsync_brain *brain, const struct dsync_brain_mailbox *mailbox) { - if (mailbox->src->last_change > mailbox->dest->last_change) { + if (mailbox->src->last_change > mailbox->dest->last_change || + brain->backup) { dsync_worker_rename_mailbox(brain->dest_worker, &mailbox->box.mailbox_guid, mailbox->src); @@ -629,7 +695,10 @@ const struct dsync_brain_mailbox *mailbox; array_foreach(&brain->mailbox_sync->mailboxes, mailbox) { - dsync_worker_update_mailbox(brain->src_worker, &mailbox->box); + if (!brain->backup) { + dsync_worker_update_mailbox(brain->src_worker, + &mailbox->box); + } dsync_worker_update_mailbox(brain->dest_worker, &mailbox->box); if (mailbox->src != NULL && mailbox->dest != NULL && @@ -735,6 +804,7 @@ bool dsync_brain_has_unexpected_changes(struct dsync_brain *brain) { - return dsync_worker_has_unexpected_changes(brain->src_worker) || + return brain->unexpected_changes || + dsync_worker_has_unexpected_changes(brain->src_worker) || dsync_worker_has_unexpected_changes(brain->dest_worker); }