dovecot: Sync mailbox list index completely at once, instead of ...

dovecot at dovecot.org dovecot at dovecot.org
Wed Jul 18 02:26:13 EEST 2007


details:   http://hg.dovecot.org/dovecot/rev/b06dfb878783
changeset: 6056:b06dfb878783
user:      Timo Sirainen <tss at iki.fi>
date:      Wed Jul 18 02:26:08 2007 +0300
description:
Sync mailbox list index completely at once, instead of in pieces and keeping
the index locked while LIST replies are being returned.

diffstat:

2 files changed, 115 insertions(+), 147 deletions(-)
src/lib-storage/list/index-mailbox-list.c |  260 ++++++++++++-----------------
src/lib-storage/list/index-mailbox-list.h |    2 

diffs (truncated from 348 to 300 lines):

diff -r 437dce5162c5 -r b06dfb878783 src/lib-storage/list/index-mailbox-list.c
--- a/src/lib-storage/list/index-mailbox-list.c	Wed Jul 18 01:57:45 2007 +0300
+++ b/src/lib-storage/list/index-mailbox-list.c	Wed Jul 18 02:26:08 2007 +0300
@@ -22,6 +22,40 @@ struct index_mailbox_list_module index_m
 	MODULE_CONTEXT_INIT(&mailbox_list_module_register);
 static void (*index_next_hook_mailbox_list_created)(struct mailbox_list *list);
 
+static enum mailbox_info_flags
+index_mailbox_list_index_flags_translate(enum mailbox_list_index_flags flags)
+{
+	enum mailbox_info_flags info_flags = 0;
+
+	if ((flags & MAILBOX_LIST_INDEX_FLAG_CHILDREN) != 0)
+		info_flags |= MAILBOX_CHILDREN;
+	if ((flags & MAILBOX_LIST_INDEX_FLAG_NOCHILDREN) != 0)
+		info_flags |= MAILBOX_NOCHILDREN;
+
+	if ((flags & MAILBOX_LIST_INDEX_FLAG_NONEXISTENT) != 0)
+		info_flags |= MAILBOX_NONEXISTENT;
+	if ((flags & MAILBOX_LIST_INDEX_FLAG_NOSELECT) != 0)
+		info_flags |= MAILBOX_NOSELECT;
+	return info_flags;
+}
+
+static enum mailbox_list_index_flags
+index_mailbox_list_info_flags_translate(enum mailbox_info_flags info_flags)
+{
+	enum mailbox_list_index_flags flags = 0;
+
+	if ((info_flags & MAILBOX_CHILDREN) != 0)
+		flags |= MAILBOX_LIST_INDEX_FLAG_CHILDREN;
+	else if ((info_flags & MAILBOX_NOCHILDREN) != 0)
+		flags |= MAILBOX_LIST_INDEX_FLAG_NOCHILDREN;
+
+	if ((info_flags & MAILBOX_NONEXISTENT) != 0)
+		flags |= MAILBOX_LIST_INDEX_FLAG_NONEXISTENT;
+	if ((info_flags & MAILBOX_NOSELECT) != 0)
+		flags |= MAILBOX_LIST_INDEX_FLAG_NOSELECT;
+	return flags;
+}
+
 static int
 index_mailbox_view_sync(struct index_mailbox_list_iterate_context *ctx)
 {
@@ -108,6 +142,58 @@ static void pattern_parse(struct mailbox
 	*recurse_level_r = recurse_level;
 }
 
+static int
+index_mailbox_list_sync(struct index_mailbox_list_iterate_context *ctx)
+{
+	struct mailbox_list *list = ctx->ctx.list;
+	struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list);
+	struct mailbox_list_iterate_context *iter;
+	struct mailbox_list_index_sync_ctx *sync_ctx;
+	const struct mailbox_info *info;
+	enum mailbox_list_sync_flags sync_flags;
+	enum mailbox_list_index_flags flags;
+	const char *patterns[2];
+	uint32_t seq;
+	int ret = 0;
+
+	/* FIXME: this works nicely with maildir++, but not others */
+	sync_flags = MAILBOX_LIST_SYNC_FLAG_RECURSIVE;
+	patterns[0] = "*"; patterns[1] = NULL;
+
+	if (mailbox_list_index_sync_init(ilist->list_index, "",
+					 sync_flags, &sync_ctx) < 0)
+		return -1;
+
+	ctx->info_pool = pool_alloconly_create("mailbox name pool", 128);
+	ctx->trans = mailbox_list_index_sync_get_transaction(sync_ctx);
+
+	iter = ilist->module_ctx.super.
+		iter_init(list, patterns, MAILBOX_LIST_ITER_RETURN_CHILDREN);
+	while ((info = ilist->module_ctx.super.iter_next(iter)) != NULL) {
+		if (mailbox_list_index_sync_more(sync_ctx, info->name,
+						 &seq) < 0) {
+			ret = -1;
+			break;
+		}
+
+		flags = index_mailbox_list_info_flags_translate(info->flags);
+		mail_index_update_flags(ctx->trans, seq, MODIFY_REPLACE, flags);
+	}
+	if (ilist->module_ctx.super.iter_deinit(iter) < 0)
+		ret = -1;
+
+	if (ret < 0) {
+		mailbox_list_index_sync_rollback(&sync_ctx);
+		return -1;
+	}
+
+	/* FIXME: single sync_stamp works only with maildir++ */
+	mail_index_update_header(ctx->trans,
+		offsetof(struct mail_index_header, sync_stamp),
+		&ctx->sync_stamp, sizeof(ctx->sync_stamp), TRUE);
+	return mailbox_list_index_sync_commit(&sync_ctx);
+}
+
 static struct mailbox_list_iterate_context *
 index_mailbox_list_iter_init(struct mailbox_list *list,
 			     const char *const *patterns,
@@ -115,8 +201,7 @@ index_mailbox_list_iter_init(struct mail
 {
 	struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list);
 	struct index_mailbox_list_iterate_context *ctx;
-	enum mailbox_list_sync_flags sync_flags;
-	const char *prefix, *cur_prefix, *const *tmp, *tmp_patterns[2];
+	const char *prefix, *cur_prefix, *const *tmp;
 	enum mailbox_list_iter_flags subs_flags;
 	int cur_recurse_level;
 
@@ -151,73 +236,35 @@ index_mailbox_list_iter_init(struct mail
 		    cur_recurse_level == -1)
 			ctx->recurse_level = cur_recurse_level;
 	}
-
-	if (index_mailbox_list_is_synced(ctx) > 0) {
-		/* synced, list from index */
+	if (prefix == NULL)
+		prefix = "";
+
+	if (!index_mailbox_list_is_synced(ctx) > 0) {
+		if (index_mailbox_list_sync(ctx) < 0) {
+			ctx->backend_ctx = ilist->module_ctx.super.
+				iter_init(list, patterns, flags);
+			return &ctx->ctx;
+		}
+		/* updated, we'll have to reopen views */
+		mail_index_view_close(&ctx->mail_view);
+		mailbox_list_index_view_deinit(&ctx->view);
+
+		ctx->mail_view = mail_index_view_open(ilist->mail_index);
+		ctx->view = mailbox_list_index_view_init(ilist->list_index,
+							 ctx->mail_view);
+	}
+
+	/* list from index */
+	if (ctx->info_pool == NULL) {
 		ctx->info_pool =
 			pool_alloconly_create("mailbox name pool", 128);
-		ctx->iter_ctx = mailbox_list_index_iterate_init(ctx->view,
-						prefix, ctx->recurse_level);
-		ctx->prefix = *prefix == '\0' ? i_strdup("") :
-			i_strdup_printf("%s%c", prefix, list->hierarchy_sep);
-	} else {
-		/* FIXME: this works nicely with maildir++, but not others */
-		sync_flags = MAILBOX_LIST_SYNC_FLAG_RECURSIVE;
-
-		if (ctx->recurse_level >= 0) {
-			ctx->mailbox_tree =
-				mailbox_tree_init(list->hierarchy_sep);
-		}
-
-		ctx->info_pool =
-			pool_alloconly_create("mailbox name pool", 128);
-		if (mailbox_list_index_sync_init(ilist->list_index, "",
-						 sync_flags,
-						 &ctx->sync_ctx) == 0) {
-			tmp_patterns[0] = "*"; tmp_patterns[1] = NULL;
-			patterns = tmp_patterns;
-			ctx->trans = mailbox_list_index_sync_get_transaction(
-								ctx->sync_ctx);
-		}
-
-		ctx->backend_ctx = ilist->module_ctx.super.
-			iter_init(list, patterns, flags);
-	}
+	}
+	ctx->iter_ctx =
+		mailbox_list_index_iterate_init(ctx->view, prefix,
+						ctx->recurse_level);
+	ctx->prefix = *prefix == '\0' ? i_strdup("") :
+		i_strdup_printf("%s%c", prefix, list->hierarchy_sep);
 	return &ctx->ctx;
-}
-
-static enum mailbox_info_flags
-index_mailbox_list_index_flags_translate(enum mailbox_list_index_flags flags)
-{
-	enum mailbox_info_flags info_flags = 0;
-
-	if ((flags & MAILBOX_LIST_INDEX_FLAG_CHILDREN) != 0)
-		info_flags |= MAILBOX_CHILDREN;
-	if ((flags & MAILBOX_LIST_INDEX_FLAG_NOCHILDREN) != 0)
-		info_flags |= MAILBOX_NOCHILDREN;
-
-	if ((flags & MAILBOX_LIST_INDEX_FLAG_NONEXISTENT) != 0)
-		info_flags |= MAILBOX_NONEXISTENT;
-	if ((flags & MAILBOX_LIST_INDEX_FLAG_NOSELECT) != 0)
-		info_flags |= MAILBOX_NOSELECT;
-	return info_flags;
-}
-
-static enum mailbox_list_index_flags
-index_mailbox_list_info_flags_translate(enum mailbox_info_flags info_flags)
-{
-	enum mailbox_list_index_flags flags = 0;
-
-	if ((info_flags & MAILBOX_CHILDREN) != 0)
-		flags |= MAILBOX_LIST_INDEX_FLAG_CHILDREN;
-	if ((info_flags & MAILBOX_NOCHILDREN) != 0)
-		flags |= MAILBOX_LIST_INDEX_FLAG_NOCHILDREN;
-
-	if ((info_flags & MAILBOX_NONEXISTENT) != 0)
-		flags |= MAILBOX_LIST_INDEX_FLAG_NONEXISTENT;
-	if ((info_flags & MAILBOX_NOSELECT) != 0)
-		flags |= MAILBOX_LIST_INDEX_FLAG_NOSELECT;
-	return flags;
 }
 
 /* skip nonexistent mailboxes when finding with "*" */
@@ -283,32 +330,6 @@ static int iter_next_nonsync(struct inde
 	return 0;
 }
 
-static struct mailbox_info *
-mailbox_info_move_to_parent(struct index_mailbox_list_iterate_context *ctx,
-			    const struct mailbox_info *info)
-{
-	const char *p, *name = info->name;
-	char sep = ctx->ctx.list->hierarchy_sep;
-
-	p_clear(ctx->info_pool);
-
-	t_push();
-	while ((p = strrchr(name, sep)) != NULL) {
-		name = t_strdup_until(name, p);
-		if (imap_match(ctx->glob, name) == IMAP_MATCH_YES) {
-			ctx->info.name = p_strdup(ctx->info_pool, name);
-			break;
-		}
-	}
-	t_pop();
-
-	if (p == NULL)
-		i_unreached();
-
-	ctx->info.flags = MAILBOX_CHILDREN | MAILBOX_NONEXISTENT;
-	return &ctx->info;
-}
-
 static const struct mailbox_info *
 index_mailbox_list_iter_next(struct mailbox_list_iterate_context *_ctx)
 {
@@ -316,8 +337,6 @@ index_mailbox_list_iter_next(struct mail
 		(struct index_mailbox_list_iterate_context *)_ctx;
 	struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(_ctx->list);
 	const struct mailbox_info *info;
-	uint32_t seq, flags;
-	enum imap_match_result match;
 
 	if (ctx->iter_ctx != NULL) {
 		if (iter_next_nonsync(ctx, &info) < 0) {
@@ -327,39 +346,7 @@ index_mailbox_list_iter_next(struct mail
 		return info;
 	}
 
-	do {
-		info = ilist->module_ctx.super.iter_next(ctx->backend_ctx);
-		if (info == NULL || ctx->sync_ctx == NULL)
-			return info;
-
-		/* if the sync fails, just ignore it. we don't require synced
-		   indexes to be able to return valid output. */
-		if (mailbox_list_index_sync_more(ctx->sync_ctx, info->name,
-						 &seq) == 0) {
-			flags = index_mailbox_list_info_flags_translate(
-								info->flags);
-			mail_index_update_flags(ctx->trans, seq, MODIFY_REPLACE,
-						flags);
-		}
-		match = imap_match(ctx->glob, info->name);
-		if ((match & IMAP_MATCH_PARENT) != 0) {
-			info = mailbox_info_move_to_parent(ctx, info);
-			match = IMAP_MATCH_YES;
-		}
-		if (ctx->recurse_level >= 0) {
-			/* no "*" wildcards, keep track of what mailboxes we
-			   have returned so we don't return same parents
-			   multiple times. */
-			bool created;
-
-			(void)mailbox_tree_get(ctx->mailbox_tree,
-					       info->name, &created);
-			if (!created)
-				match = IMAP_MATCH_NO;
-		}
-	} while (match != IMAP_MATCH_YES || !info_flags_match(ctx, info));
-
-	return info;
+	return ilist->module_ctx.super.iter_next(ctx->backend_ctx);
 }
 
 static int
@@ -374,31 +361,14 @@ index_mailbox_list_iter_deinit(struct ma
 		mailbox_list_index_iterate_deinit(&ctx->iter_ctx);
 	if (ctx->info_pool != NULL)
 		pool_unref(ctx->info_pool);


More information about the dovecot-cvs mailing list