Mercurial > dovecot > core-2.2
view src/doveadm/dsync/dsync-mailbox-tree-fill.c @ 14584:b2076acc3715
Initial version of dsync rewrite.
* doveadm backup not implemented at all yet
* syncing mailbox renames is somewhat broken (at least renaming \noselect
mailboxes)
* saving/restoring "state" is implemented by dsync brain, but not by
doveadm. this should be easy to do, just need to figure out how the
replication code wants it.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 22 May 2012 23:17:31 +0300 |
parents | |
children | e852d1fbf40a |
line wrap: on
line source
/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "array.h" #include "hash.h" #include "guid.h" #include "str.h" #include "mailbox-log.h" #include "mail-namespace.h" #include "mail-storage.h" #include "mailbox-list.h" #include "dsync-mailbox-tree-private.h" static int dsync_mailbox_tree_add_node(struct dsync_mailbox_tree *tree, const struct mailbox_info *info, struct dsync_mailbox_node **node_r) { struct dsync_mailbox_node *node; node = dsync_mailbox_tree_get(tree, info->name); if (node->ns != info->ns) { i_assert(node->ns != NULL); i_error("Mailbox '%s' exists in two namespaces: '%s' and '%s'", info->name, node->ns->prefix, info->ns->prefix); return -1; } *node_r = node; return 0; } static int dsync_mailbox_tree_add(struct dsync_mailbox_tree *tree, const struct mailbox_info *info) { struct dsync_mailbox_node *node; struct mailbox *box; struct mailbox_metadata metadata; struct mailbox_status status; const char *errstr; enum mail_error error; if ((info->flags & MAILBOX_NONEXISTENT) != 0) return 0; if (dsync_mailbox_tree_add_node(tree, info, &node) < 0) return -1; node->existence = DSYNC_MAILBOX_NODE_EXISTS; if ((info->flags & MAILBOX_NOSELECT) != 0) return 0; /* get GUID and UIDVALIDITY for selectable mailbox */ box = mailbox_alloc(info->ns->list, info->name, 0); if (mailbox_get_metadata(box, MAILBOX_METADATA_GUID, &metadata) < 0 || mailbox_get_status(box, STATUS_UIDVALIDITY, &status) < 0) { errstr = mailbox_get_last_error(box, &error); switch (error) { case MAIL_ERROR_NOTFOUND: /* mailbox was just deleted? */ break; case MAIL_ERROR_NOTPOSSIBLE: /* invalid mbox files? ignore */ break; default: i_error("Failed to access mailbox %s: %s", info->name, errstr); mailbox_free(&box); return -1; } } else { memcpy(node->mailbox_guid, metadata.guid, sizeof(node->mailbox_guid)); node->uid_validity = status.uidvalidity; } mailbox_free(&box); return 0; } static struct dsync_mailbox_node * dsync_mailbox_tree_find_sha(struct dsync_mailbox_tree *tree, struct mail_namespace *ns, const guid_128_t sha128) { struct dsync_mailbox_node *node; if (tree->name128_hash == NULL) dsync_mailbox_tree_build_name128_hash(tree); node = hash_table_lookup(tree->name128_hash, sha128); return node == NULL || node->ns != ns ? NULL : node; } static int dsync_mailbox_tree_add_change_timestamps(struct dsync_mailbox_tree *tree, struct mail_namespace *ns) { struct dsync_mailbox_node *node; struct dsync_mailbox_delete *del; struct mailbox_log *log; struct mailbox_log_iter *iter; const struct mailbox_log_record *rec; time_t timestamp; log = mailbox_list_get_changelog(ns->list); if (log == NULL) return 0; iter = mailbox_log_iter_init(log); while ((rec = mailbox_log_iter_next(iter)) != NULL) { node = rec->type == MAILBOX_LOG_RECORD_DELETE_MAILBOX ? NULL : dsync_mailbox_tree_find_sha(tree, ns, rec->mailbox_guid); switch (rec->type) { case MAILBOX_LOG_RECORD_DELETE_MAILBOX: if (hash_table_lookup(tree->guid_hash, rec->mailbox_guid) != NULL) { /* mailbox still exists. maybe it was restored from backup or something. */ break; } del = array_append_space(&tree->deletes); del->delete_mailbox = TRUE; memcpy(del->guid, rec->mailbox_guid, sizeof(del->guid)); break; case MAILBOX_LOG_RECORD_DELETE_DIR: if (node != NULL) { /* mailbox exists again, skip it */ break; } del = array_append_space(&tree->deletes); memcpy(del->guid, rec->mailbox_guid, sizeof(del->guid)); break; case MAILBOX_LOG_RECORD_RENAME: case MAILBOX_LOG_RECORD_SUBSCRIBE: case MAILBOX_LOG_RECORD_UNSUBSCRIBE: if (node == NULL) break; timestamp = mailbox_log_record_get_timestamp(rec); if (rec->type == MAILBOX_LOG_RECORD_RENAME) node->last_renamed = timestamp; else node->last_subscription_change = timestamp; break; } } if (mailbox_log_iter_deinit(&iter) < 0) { i_error("Mailbox log iteration for namespace '%s' failed", ns->prefix); return -1; } return 0; } int dsync_mailbox_tree_fill(struct dsync_mailbox_tree *tree, struct mail_namespace *ns) { const enum mailbox_list_iter_flags list_flags = MAILBOX_LIST_ITER_NO_AUTO_BOXES; const enum mailbox_list_iter_flags subs_list_flags = MAILBOX_LIST_ITER_NO_AUTO_BOXES | MAILBOX_LIST_ITER_SELECT_SUBSCRIBED | MAILBOX_LIST_ITER_RETURN_NO_FLAGS; struct mailbox_list_iterate_context *iter; struct dsync_mailbox_node *node; const struct mailbox_info *info; int ret = 0; i_assert(mail_namespace_get_sep(ns) == tree->sep); /* assign namespace to its root, so it gets copied to children */ if (ns->prefix_len > 0) { node = dsync_mailbox_tree_get(tree, t_strndup(ns->prefix, ns->prefix_len-1)); node->ns = ns; } else { tree->root.ns = ns; } /* first add all of the existing mailboxes */ iter = mailbox_list_iter_init(ns->list, "*", list_flags); while ((info = mailbox_list_iter_next(iter)) != NULL) { if (dsync_mailbox_tree_add(tree, info) < 0) ret = -1; } if (mailbox_list_iter_deinit(&iter) < 0) { i_error("Mailbox listing for namespace '%s' failed", ns->prefix); ret = -1; } /* add subscriptions */ iter = mailbox_list_iter_init(ns->list, "*", subs_list_flags); while ((info = mailbox_list_iter_next(iter)) != NULL) { if (dsync_mailbox_tree_add_node(tree, info, &node) < 0) ret = -1; else node->subscribed = TRUE; } if (mailbox_list_iter_deinit(&iter) < 0) { i_error("Mailbox listing for namespace '%s' failed", ns->prefix); ret = -1; } if (dsync_mailbox_tree_build_guid_hash(tree) < 0) ret = -1; /* add timestamps */ if (dsync_mailbox_tree_add_change_timestamps(tree, ns) < 0) ret = -1; return ret; }