dovecot: Moved index syncing code to its own file.

dovecot at dovecot.org dovecot at dovecot.org
Mon Jul 9 05:44:43 EEST 2007


details:   http://hg.dovecot.org/dovecot/rev/00c5e3cbeaf0
changeset: 5920:00c5e3cbeaf0
user:      Timo Sirainen <tss at iki.fi>
date:      Sun Jul 08 23:28:22 2007 +0300
description:
Moved index syncing code to its own file.

diffstat:

5 files changed, 509 insertions(+), 490 deletions(-)
src/lib-storage/index/maildir/Makefile.am          |    1 
src/lib-storage/index/maildir/maildir-save.c       |    2 
src/lib-storage/index/maildir/maildir-sync-index.c |  493 ++++++++++++++++++++
src/lib-storage/index/maildir/maildir-sync.c       |  491 -------------------
src/lib-storage/index/maildir/maildir-sync.h       |   12 

diffs (truncated from 1091 to 300 lines):

diff -r cc439e4e99cb -r 00c5e3cbeaf0 src/lib-storage/index/maildir/Makefile.am
--- a/src/lib-storage/index/maildir/Makefile.am	Sun Jul 08 23:20:34 2007 +0300
+++ b/src/lib-storage/index/maildir/Makefile.am	Sun Jul 08 23:28:22 2007 +0300
@@ -16,6 +16,7 @@ libstorage_maildir_a_SOURCES = \
 	maildir-save.c \
 	maildir-storage.c \
 	maildir-sync.c \
+	maildir-sync-index.c \
 	maildir-transaction.c \
 	maildir-uidlist.c \
 	maildir-util.c
diff -r cc439e4e99cb -r 00c5e3cbeaf0 src/lib-storage/index/maildir/maildir-save.c
--- a/src/lib-storage/index/maildir/maildir-save.c	Sun Jul 08 23:20:34 2007 +0300
+++ b/src/lib-storage/index/maildir/maildir-save.c	Sun Jul 08 23:28:22 2007 +0300
@@ -604,7 +604,7 @@ int maildir_transaction_save_commit_pre(
 	}
 
 	/* Start syncing so that keywords_sync_ctx gets set.. */
-	if (maildir_sync_index_begin(ctx->mbox, &ctx->sync_ctx) < 0) {
+	if (maildir_sync_index_begin(ctx->mbox, NULL, &ctx->sync_ctx) < 0) {
 		maildir_transaction_save_rollback(ctx);
 		return -1;
 	}
diff -r cc439e4e99cb -r 00c5e3cbeaf0 src/lib-storage/index/maildir/maildir-sync-index.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-storage/index/maildir/maildir-sync-index.c	Sun Jul 08 23:28:22 2007 +0300
@@ -0,0 +1,493 @@
+/* Copyright (C) 2007 Timo Sirainen */
+
+#include "lib.h"
+#include "ioloop.h"
+#include "array.h"
+#include "maildir-storage.h"
+#include "index-sync-changes.h"
+#include "maildir-uidlist.h"
+#include "maildir-keywords.h"
+#include "maildir-filename.h"
+#include "maildir-sync.h"
+
+#include <stdio.h>
+#include <unistd.h>
+
+struct maildir_index_sync_context {
+        struct maildir_mailbox *mbox;
+	struct maildir_sync_context *maildir_sync_ctx;
+
+	struct mail_index_view *view;
+	struct mail_index_sync_ctx *sync_ctx;
+        struct maildir_keywords_sync_ctx *keywords_sync_ctx;
+	struct mail_index_transaction *trans;
+
+	struct index_sync_changes_context *sync_changes;
+	enum mail_flags flags;
+	ARRAY_TYPE(keyword_indexes) keywords;
+
+	uint32_t seq, uid;
+
+	bool changed;
+};
+
+struct maildir_keywords_sync_ctx *
+maildir_sync_get_keywords_sync_ctx(struct maildir_index_sync_context *ctx)
+{
+	return ctx->keywords_sync_ctx;
+}
+
+static int maildir_expunge(struct maildir_mailbox *mbox, const char *path,
+			   struct maildir_index_sync_context *ctx)
+{
+	struct mailbox *box = &mbox->ibox.box;
+
+	if (unlink(path) == 0) {
+		if (box->v.sync_notify != NULL) {
+			box->v.sync_notify(box, ctx->uid,
+					   MAILBOX_SYNC_TYPE_EXPUNGE);
+		}
+		mail_index_expunge(ctx->trans, ctx->seq);
+		ctx->changed = TRUE;
+		return 1;
+	}
+	if (errno == ENOENT)
+		return 0;
+
+	mail_storage_set_critical(&mbox->storage->storage,
+				  "unlink(%s) failed: %m", path);
+	return -1;
+}
+
+static int maildir_sync_flags(struct maildir_mailbox *mbox, const char *path,
+			      struct maildir_index_sync_context *ctx)
+{
+	struct mailbox *box = &mbox->ibox.box;
+	const char *dir, *fname, *newfname, *newpath;
+	enum mailbox_sync_type sync_type = 0;
+	uint8_t flags8;
+
+	fname = strrchr(path, '/');
+	i_assert(fname != NULL);
+	fname++;
+	dir = t_strdup_until(path, fname);
+
+	/* get the current flags and keywords */
+	maildir_filename_get_flags(ctx->keywords_sync_ctx,
+				   fname, &ctx->flags, &ctx->keywords);
+
+	/* apply changes */
+	flags8 = ctx->flags;
+	index_sync_changes_apply(ctx->sync_changes, NULL,
+				 &flags8, &ctx->keywords, &sync_type);
+	ctx->flags = flags8;
+
+	/* and try renaming with the new name */
+	newfname = maildir_filename_set_flags(ctx->keywords_sync_ctx, fname,
+					      ctx->flags, &ctx->keywords);
+	newpath = t_strconcat(dir, newfname, NULL);
+	if (rename(path, newpath) == 0) {
+		if (box->v.sync_notify != NULL)
+			box->v.sync_notify(box, ctx->uid, sync_type);
+
+		ctx->changed = TRUE;
+		return 1;
+	}
+	if (errno == ENOENT)
+		return 0;
+
+	if (!ENOSPACE(errno) && errno != EACCES) {
+		mail_storage_set_critical(&mbox->storage->storage,
+			"rename(%s, %s) failed: %m", path, newpath);
+	}
+	return -1;
+}
+
+int maildir_sync_index_begin(struct maildir_mailbox *mbox,
+			     struct maildir_sync_context *maildir_sync_ctx,
+			     struct maildir_index_sync_context **ctx_r)
+{
+	struct maildir_index_sync_context *ctx;
+	struct mail_index_sync_ctx *sync_ctx;
+	struct mail_index_view *view;
+	struct mail_index_transaction *trans;
+
+	if (mail_index_sync_begin(mbox->ibox.index, &sync_ctx, &view, &trans,
+				  (uint32_t)-1, (uoff_t)-1, 0) <= 0) {
+		mail_storage_set_index_error(&mbox->ibox);
+		return -1;
+	}
+
+	ctx = i_new(struct maildir_index_sync_context, 1);
+	ctx->mbox = mbox;
+	ctx->maildir_sync_ctx = maildir_sync_ctx;
+	ctx->sync_ctx = sync_ctx;
+	ctx->view = view;
+	ctx->trans = trans;
+	ctx->keywords_sync_ctx =
+		maildir_keywords_sync_init(mbox->keywords, mbox->ibox.index);
+
+	ctx->sync_changes = index_sync_changes_init(&mbox->ibox, ctx->sync_ctx,
+						    ctx->view, ctx->trans,
+						    mbox->ibox.readonly);
+
+	*ctx_r = ctx;
+	return 0;
+}
+
+int maildir_sync_index_finish(struct maildir_index_sync_context **_ctx,
+			      bool failed, bool cancel)
+{
+	struct maildir_index_sync_context *ctx = *_ctx;
+	struct maildir_mailbox *mbox = ctx->mbox;
+	int ret = failed ? -1 : 0;
+
+	*_ctx = NULL;
+
+	if (ret < 0 || cancel)
+		mail_index_sync_rollback(&ctx->sync_ctx);
+	else {
+		/* Set syncing_commit=TRUE so that if any sync callbacks try
+		   to access mails which got lost (eg. expunge callback trying
+		   to open the file which was just unlinked) we don't try to
+		   start a second index sync and crash. */
+		mbox->syncing_commit = TRUE;
+		if (mail_index_sync_commit(&ctx->sync_ctx) < 0) {
+			mail_storage_set_index_error(&mbox->ibox);
+			ret = -1;
+		} else {
+			mbox->ibox.commit_log_file_seq = 0;
+			mbox->ibox.commit_log_file_offset = 0;
+		}
+		mbox->syncing_commit = FALSE;
+	}
+
+	maildir_keywords_sync_deinit(ctx->keywords_sync_ctx);
+        ctx->keywords_sync_ctx = NULL;
+
+	index_sync_changes_deinit(&ctx->sync_changes);
+	i_free(ctx);
+	return ret;
+}
+
+int maildir_sync_index(struct maildir_index_sync_context *ctx,
+		       bool partial)
+{
+	struct maildir_mailbox *mbox = ctx->mbox;
+	struct mail_index_view *view = ctx->view;
+	struct maildir_uidlist_iter_ctx *iter;
+	struct mail_index_transaction *trans = ctx->trans;
+	const struct mail_index_header *hdr;
+	struct mail_index_header empty_hdr;
+	const struct mail_index_record *rec;
+	uint32_t seq, uid, prev_uid;
+        enum maildir_uidlist_rec_flag uflags;
+	const char *filename;
+	ARRAY_TYPE(keyword_indexes) idx_keywords;
+	uint32_t uid_validity, next_uid;
+	uint64_t value;
+	unsigned int changes = 0;
+	int ret = 0;
+	bool expunged, full_rescan = FALSE;
+
+	i_assert(!mbox->syncing_commit);
+	i_assert(maildir_uidlist_is_locked(ctx->mbox->uidlist));
+
+	hdr = mail_index_get_header(view);
+	uid_validity = maildir_uidlist_get_uid_validity(mbox->uidlist);
+	if (uid_validity != hdr->uid_validity &&
+	    uid_validity != 0 && hdr->uid_validity != 0) {
+		/* uidvalidity changed and mailbox isn't being initialized,
+		   reset mailbox so we can add all messages as new */
+		i_warning("Maildir %s: UIDVALIDITY changed (%u -> %u)",
+			  mbox->path, hdr->uid_validity, uid_validity);
+		mail_index_reset(trans);
+
+		memset(&empty_hdr, 0, sizeof(empty_hdr));
+		empty_hdr.next_uid = 1;
+		hdr = &empty_hdr;
+	}
+
+	mbox->syncing_commit = TRUE;
+	seq = prev_uid = 0;
+	t_array_init(&ctx->keywords, MAILDIR_MAX_KEYWORDS);
+	t_array_init(&idx_keywords, MAILDIR_MAX_KEYWORDS);
+	iter = maildir_uidlist_iter_init(mbox->uidlist);
+	while (maildir_uidlist_iter_next(iter, &uid, &uflags, &filename)) {
+		maildir_filename_get_flags(ctx->keywords_sync_ctx, filename,
+					   &ctx->flags, &ctx->keywords);
+
+		i_assert(uid > prev_uid);
+		prev_uid = uid;
+
+		/* the private flags are kept only in indexes. don't use them
+		   at all even for newly seen mails */
+		ctx->flags &= ~mbox->private_flags_mask;
+
+		if ((uflags & MAILDIR_UIDLIST_REC_FLAG_RECENT) != 0 &&
+		    (uflags & MAILDIR_UIDLIST_REC_FLAG_NEW_DIR) != 0 &&
+		    (uflags & MAILDIR_UIDLIST_REC_FLAG_MOVED) == 0) {
+			/* mail is recent for next session as well */
+			ctx->flags |= MAIL_RECENT;
+		}
+
+	__again:
+		ctx->seq = ++seq;
+		ctx->uid = uid;
+
+		if (seq > hdr->messages_count) {
+			if (uid < hdr->next_uid) {
+				/* most likely a race condition: we read the
+				   maildir, then someone else expunged messages
+				   and committed changes to index. so, this
+				   message shouldn't actually exist. mark it
+				   racy and check in next sync.
+
+				   the difference between this and the later
+				   check is that this one happens when messages
+				   are expunged from the end */
+				if ((uflags &
+				    MAILDIR_UIDLIST_REC_FLAG_NONSYNCED) != 0) {
+					/* partial syncing */
+					continue;
+				}
+				if ((uflags &
+				     MAILDIR_UIDLIST_REC_FLAG_RACING) != 0) {
+					mail_storage_set_critical(
+						&mbox->storage->storage,
+						"Maildir %s sync: "
+						"UID < next_uid "
+						"(%u < %u, file = %s)",
+						mbox->path, uid, hdr->next_uid,
+						filename);
+					mail_index_mark_corrupted(
+						mbox->ibox.index);
+					ret = -1;
+					break;
+				}
+				mbox->dirty_cur_time = ioloop_time;
+				maildir_uidlist_add_flags(mbox->uidlist,
+					filename,
+					MAILDIR_UIDLIST_REC_FLAG_RACING);
+
+				seq--;


More information about the dovecot-cvs mailing list