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