changeset 8876:88aeadb32151 HEAD

Added maildir_very_dirty_syncs setting.
author Timo Sirainen <tss@iki.fi>
date Mon, 30 Mar 2009 20:27:14 -0400
parents 629004d13ec4
children e5658894cd13
files src/lib-storage/index/maildir/maildir-keywords.c src/lib-storage/index/maildir/maildir-keywords.h src/lib-storage/index/maildir/maildir-storage.c src/lib-storage/index/maildir/maildir-storage.h src/lib-storage/index/maildir/maildir-sync-index.c src/lib-storage/index/maildir/maildir-sync.c src/lib-storage/index/maildir/maildir-uidlist.c src/lib-storage/index/maildir/maildir-uidlist.h src/lib-storage/index/maildir/maildir-util.c src/master/mail-process.c src/master/master-settings-defs.c src/master/master-settings.c src/master/master-settings.h
diffstat 13 files changed, 150 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-storage/index/maildir/maildir-keywords.c	Mon Mar 30 20:27:02 2009 -0400
+++ b/src/lib-storage/index/maildir/maildir-keywords.c	Mon Mar 30 20:27:14 2009 -0400
@@ -47,6 +47,7 @@
 	const ARRAY_TYPE(keywords) *keywords;
 	ARRAY_DEFINE(idx_to_chr, char);
 	unsigned int chridx_to_idx[MAILDIR_MAX_KEYWORDS];
+	bool readonly;
 };
 
 struct maildir_keywords *maildir_keywords_init(struct maildir_mailbox *mbox)
@@ -404,6 +405,17 @@
 	return ctx;
 }
 
+struct maildir_keywords_sync_ctx *
+maildir_keywords_sync_init_readonly(struct maildir_keywords *mk,
+				    struct mail_index *index)
+{
+	struct maildir_keywords_sync_ctx *ctx;
+
+	ctx = maildir_keywords_sync_init(mk, index);
+	ctx->readonly = TRUE;
+	return ctx;
+}
+
 void maildir_keywords_sync_deinit(struct maildir_keywords_sync_ctx **_ctx)
 {
 	struct maildir_keywords_sync_ctx *ctx = *_ctx;
@@ -455,13 +467,17 @@
 	const char *const *name_p;
 	char *chr_p;
 	unsigned int chridx;
+	int ret;
 
 	chr_p = array_idx_modifiable(&ctx->idx_to_chr, idx);
 	if (*chr_p != '\0')
 		return *chr_p;
 
 	name_p = array_idx(ctx->keywords, idx);
-	if (maildir_keywords_lookup_or_create(ctx->mk, *name_p, &chridx) <= 0)
+	ret = !ctx->readonly ?
+		maildir_keywords_lookup_or_create(ctx->mk, *name_p, &chridx) :
+		maildir_keywords_lookup(ctx->mk, *name_p, &chridx);
+	if (ret <= 0)
 		return '\0';
 
 	*chr_p = chridx + MAILDIR_KEYWORD_FIRST;
--- a/src/lib-storage/index/maildir/maildir-keywords.h	Mon Mar 30 20:27:02 2009 -0400
+++ b/src/lib-storage/index/maildir/maildir-keywords.h	Mon Mar 30 20:27:14 2009 -0400
@@ -19,6 +19,10 @@
 struct maildir_keywords_sync_ctx *
 maildir_keywords_sync_init(struct maildir_keywords *mk,
 			   struct mail_index *index);
+/* Don't try to add any nonexisting keywords */
+struct maildir_keywords_sync_ctx *
+maildir_keywords_sync_init_readonly(struct maildir_keywords *mk,
+				    struct mail_index *index);
 void maildir_keywords_sync_deinit(struct maildir_keywords_sync_ctx **ctx);
 
 /* Returns keyword index. */
--- a/src/lib-storage/index/maildir/maildir-storage.c	Mon Mar 30 20:27:02 2009 -0400
+++ b/src/lib-storage/index/maildir/maildir-storage.c	Mon Mar 30 20:27:14 2009 -0400
@@ -442,6 +442,7 @@
 	index = index_storage_alloc(&storage->storage, name, flags,
 				    MAILDIR_INDEX_PREFIX);
 	mbox->ibox.index = index;
+	mbox->very_dirty_syncs = getenv("MAILDIR_VERY_DIRTY_SYNCS") != NULL;
 
 	/* for shared mailboxes get the create mode from the
 	   permissions of dovecot-shared file. */
@@ -869,6 +870,8 @@
 		timeout_remove(&mbox->keep_lock_to);
 	}
 
+	if (mbox->flags_view != NULL)
+		mail_index_view_close(&mbox->flags_view);
 	if (mbox->keywords != NULL)
 		maildir_keywords_deinit(&mbox->keywords);
 	maildir_uidlist_deinit(&mbox->uidlist);
--- a/src/lib-storage/index/maildir/maildir-storage.h	Mon Mar 30 20:27:02 2009 -0400
+++ b/src/lib-storage/index/maildir/maildir-storage.h	Mon Mar 30 20:27:14 2009 -0400
@@ -82,6 +82,7 @@
 struct maildir_mailbox {
 	struct index_mailbox ibox;
 	struct maildir_storage *storage;
+	struct mail_index_view *flags_view;
 
 	const char *path;
 	struct timeout *keep_lock_to;
@@ -94,6 +95,7 @@
 	uint32_t maildir_ext_id;
 
 	unsigned int syncing_commit:1;
+	unsigned int very_dirty_syncs:1;
 };
 
 struct maildir_transaction_context {
--- a/src/lib-storage/index/maildir/maildir-sync-index.c	Mon Mar 30 20:27:02 2009 -0400
+++ b/src/lib-storage/index/maildir/maildir-sync-index.c	Mon Mar 30 20:27:14 2009 -0400
@@ -387,6 +387,8 @@
 	uint32_t first_uid;
 	unsigned int changes = 0;
 	int ret = 0;
+	time_t time_before_sync;
+	struct stat st;
 	bool expunged, full_rescan = FALSE;
 
 	i_assert(!mbox->syncing_commit);
@@ -412,6 +414,7 @@
 	}
 	hdr_next_uid = hdr->next_uid;
 
+	time_before_sync = time(NULL);
 	mbox->syncing_commit = TRUE;
 	seq = prev_uid = 0; first_recent_uid = I_MAX(hdr->first_recent_uid, 1);
 	t_array_init(&ctx->keywords, MAILDIR_MAX_KEYWORDS);
@@ -560,8 +563,12 @@
 	if (mbox->ibox.box.v.sync_notify != NULL)
 		mbox->ibox.box.v.sync_notify(&mbox->ibox.box, 0, 0);
 
-	if (ctx->changed)
-		mbox->maildir_hdr.cur_mtime = time(NULL);
+	if (stat(t_strconcat(mbox->path, "/cur", NULL), &st) == 0) {
+		mbox->maildir_hdr.new_check_time =
+			I_MAX(st.st_mtime, time_before_sync);
+		mbox->maildir_hdr.cur_mtime = st.st_mtime;
+		mbox->maildir_hdr.cur_mtime_nsecs = ST_MTIME_NSEC(st);
+	}
 
 	if (uid_validity == 0) {
 		uid_validity = hdr->uid_validity != 0 ? hdr->uid_validity :
--- a/src/lib-storage/index/maildir/maildir-sync.c	Mon Mar 30 20:27:02 2009 -0400
+++ b/src/lib-storage/index/maildir/maildir-sync.c	Mon Mar 30 20:27:14 2009 -0400
@@ -500,10 +500,23 @@
 	}
 
 	if (dir_changed) {
-		if (new_dir)
-			ctx->mbox->maildir_hdr.new_mtime = now;
-		else
-			ctx->mbox->maildir_hdr.cur_mtime = now;
+		/* save the exact new times. the new mtimes should be >=
+		   "now", but just in case something weird happens and mtime
+		   doesn't update, use "now". */
+		if (stat(ctx->new_dir, &st) == 0) {
+			ctx->mbox->maildir_hdr.new_check_time =
+				I_MAX(st.st_mtime, now);
+			ctx->mbox->maildir_hdr.new_mtime = st.st_mtime;
+			ctx->mbox->maildir_hdr.new_mtime_nsecs =
+				ST_MTIME_NSEC(st);
+		}
+		if (stat(ctx->cur_dir, &st) == 0) {
+			ctx->mbox->maildir_hdr.new_check_time =
+				I_MAX(st.st_mtime, now);
+			ctx->mbox->maildir_hdr.cur_mtime = st.st_mtime;
+			ctx->mbox->maildir_hdr.cur_mtime_nsecs =
+				ST_MTIME_NSEC(st);
+		}
 	}
 
 	return ret < 0 ? -1 :
@@ -564,7 +577,7 @@
 
 	/* try to avoid stat()ing by first checking delayed changes */
 	if (DIR_DELAYED_REFRESH(hdr, new) ||
-	    DIR_DELAYED_REFRESH(hdr, cur)) {
+	    (DIR_DELAYED_REFRESH(hdr, cur) && !mbox->very_dirty_syncs)) {
 		/* refresh index and try again */
 		if (maildir_sync_header_refresh(mbox) < 0)
 			return -1;
@@ -572,7 +585,7 @@
 
 		if (DIR_DELAYED_REFRESH(hdr, new))
 			*new_changed_r = TRUE;
-		if (DIR_DELAYED_REFRESH(hdr, cur))
+		if (DIR_DELAYED_REFRESH(hdr, cur) && !mbox->very_dirty_syncs)
 			*cur_changed_r = TRUE;
 		if (*new_changed_r && *cur_changed_r)
 			return 0;
@@ -901,6 +914,32 @@
 		}
 	}
 
+	if (mbox->very_dirty_syncs) {
+		struct mail_index_view_sync_ctx *sync_ctx;
+		bool b;
+
+		if (mbox->flags_view == NULL) {
+			mbox->flags_view =
+				mail_index_view_open(mbox->ibox.index);
+		}
+		sync_ctx = mail_index_view_sync_begin(mbox->flags_view,
+				MAIL_INDEX_VIEW_SYNC_FLAG_FIX_INCONSISTENT);
+		if (mail_index_view_sync_commit(&sync_ctx, &b) < 0) {
+			mail_storage_set_index_error(&mbox->ibox);
+			ret = -1;
+		}
+		/* make sure the map stays in private memory */
+		if (mbox->flags_view->map->refcount > 1) {
+			struct mail_index_map *map;
+
+			map = mail_index_map_clone(mbox->flags_view->map);
+			mail_index_unmap(&mbox->flags_view->map);
+			mbox->flags_view->map = map;
+		}
+		mail_index_record_map_move_to_private(mbox->flags_view->map);
+		mail_index_map_move_to_memory(mbox->flags_view->map);
+		maildir_uidlist_set_all_nonsynced(mbox->uidlist);
+	}
 	return index_mailbox_sync_init(box, flags, ret < 0);
 }
 
--- a/src/lib-storage/index/maildir/maildir-uidlist.c	Mon Mar 30 20:27:02 2009 -0400
+++ b/src/lib-storage/index/maildir/maildir-uidlist.c	Mon Mar 30 20:27:14 2009 -0400
@@ -1338,6 +1338,11 @@
 	return 1;
 }
 
+void maildir_uidlist_set_all_nonsynced(struct maildir_uidlist *uidlist)
+{
+	maildir_uidlist_mark_all(uidlist, TRUE);
+}
+
 int maildir_uidlist_sync_init(struct maildir_uidlist *uidlist,
 			      enum maildir_uidlist_sync_flags sync_flags,
 			      struct maildir_uidlist_sync_ctx **sync_ctx_r)
--- a/src/lib-storage/index/maildir/maildir-uidlist.h	Mon Mar 30 20:27:02 2009 -0400
+++ b/src/lib-storage/index/maildir/maildir-uidlist.h	Mon Mar 30 20:27:14 2009 -0400
@@ -93,6 +93,7 @@
    maildir_uidlist_set_ext() */
 int maildir_uidlist_update(struct maildir_uidlist *uidlist);
 
+void maildir_uidlist_set_all_nonsynced(struct maildir_uidlist *uidlist);
 /* Sync uidlist with what's actually on maildir. Returns same as
    maildir_uidlist_lock(). */
 int maildir_uidlist_sync_init(struct maildir_uidlist *uidlist,
--- a/src/lib-storage/index/maildir/maildir-util.c	Mon Mar 30 20:27:02 2009 -0400
+++ b/src/lib-storage/index/maildir/maildir-util.c	Mon Mar 30 20:27:14 2009 -0400
@@ -1,11 +1,14 @@
 /* Copyright (c) 2004-2009 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "array.h"
 #include "ioloop.h"
 #include "str.h"
 #include "mkdir-parents.h"
 #include "maildir-storage.h"
 #include "maildir-uidlist.h"
+#include "maildir-keywords.h"
+#include "maildir-filename.h"
 #include "maildir-sync.h"
 
 #include <unistd.h>
@@ -16,35 +19,69 @@
 
 #define MAILDIR_RESYNC_RETRY_COUNT 10
 
+static const char *
+maildir_filename_guess(struct maildir_mailbox *mbox, uint32_t uid,
+		       const char *fname, bool *have_flags_r)
+
+{
+	struct mail_index_view *view = mbox->flags_view;
+	struct maildir_keywords_sync_ctx *kw_ctx;
+	enum mail_flags flags;
+	ARRAY_TYPE(keyword_indexes) keywords;
+	uint32_t seq;
+
+	if (view == NULL || !mail_index_lookup_seq(view, uid, &seq)) {
+		*have_flags_r = FALSE;
+		return fname;
+	}
+
+	t_array_init(&keywords, 32);
+	mail_index_lookup_view_flags(view, seq, &flags, &keywords);
+	if (array_count(&keywords) == 0) {
+		*have_flags_r = (flags & MAIL_FLAGS_NONRECENT) != 0;
+		fname = maildir_filename_set_flags(NULL, fname, flags, NULL);
+	} else {
+		*have_flags_r = TRUE;
+		kw_ctx = maildir_keywords_sync_init_readonly(mbox->keywords,
+							     mbox->ibox.index);
+		fname = maildir_filename_set_flags(kw_ctx, fname,
+						   flags, &keywords);
+		maildir_keywords_sync_deinit(&kw_ctx);
+	}
+	return fname;
+}
+
 static int maildir_file_do_try(struct maildir_mailbox *mbox, uint32_t uid,
 			       maildir_file_do_func *callback, void *context)
 {
-	const char *fname;
-        enum maildir_uidlist_rec_flag flags;
+	const char *path, *fname;
+	enum maildir_uidlist_rec_flag flags;
+	bool have_flags;
 	int ret;
 
 	fname = maildir_uidlist_lookup(mbox->uidlist, uid, &flags);
 	if (fname == NULL)
 		return -2; /* expunged */
 
+	if ((flags & MAILDIR_UIDLIST_REC_FLAG_NONSYNCED) != 0) {
+		/* let's see if we can guess the filename based on index */
+		fname = maildir_filename_guess(mbox, uid, fname, &have_flags);
+		if (have_flags) {
+			/* don't even bother looking into new/ dir */
+			flags &= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR;
+		}
+	}
+
 	if ((flags & MAILDIR_UIDLIST_REC_FLAG_NEW_DIR) != 0) {
 		/* probably in new/ dir */
-		T_BEGIN {
-			const char *path;
-
-			path = t_strconcat(mbox->path, "/new/", fname, NULL);
-			ret = callback(mbox, path, context);
-		} T_END;
+		path = t_strconcat(mbox->path, "/new/", fname, NULL);
+		ret = callback(mbox, path, context);
 		if (ret != 0)
 			return ret;
 	}
 
-	T_BEGIN {
-		const char *path;
-
-		path = t_strconcat(mbox->path, "/cur/", fname, NULL);
-		ret = callback(mbox, path, context);
-	} T_END;
+	path = t_strconcat(mbox->path, "/cur/", fname, NULL);
+	ret = callback(mbox, path, context);
 	return ret;
 }
 
@@ -71,7 +108,9 @@
 {
 	int i, ret;
 
-	ret = maildir_file_do_try(mbox, uid, callback, context);
+	T_BEGIN {
+		ret = maildir_file_do_try(mbox, uid, callback, context);
+	} T_END;
 	for (i = 0; i < MAILDIR_RESYNC_RETRY_COUNT && ret == 0; i++) {
 		/* file is either renamed or deleted. sync the maildir and
 		   see which one. if file appears to be renamed constantly,
@@ -79,11 +118,14 @@
 		if (maildir_storage_sync_force(mbox, uid) < 0)
 			return -1;
 
-		ret = maildir_file_do_try(mbox, uid, callback, context);
+		T_BEGIN {
+			ret = maildir_file_do_try(mbox, uid, callback, context);
+		} T_END;
 	}
 
-	if (i == MAILDIR_RESYNC_RETRY_COUNT)
+	if (i == MAILDIR_RESYNC_RETRY_COUNT) T_BEGIN {
 		ret = maildir_file_do_try(mbox, uid, do_racecheck, context);
+	} T_END;
 
 	return ret == -2 ? 0 : ret;
 }
--- a/src/master/mail-process.c	Mon Mar 30 20:27:02 2009 -0400
+++ b/src/master/mail-process.c	Mon Mar 30 20:27:14 2009 -0400
@@ -366,6 +366,8 @@
 		env_put("MAILDIR_COPY_WITH_HARDLINKS=1");
 	if (set->maildir_copy_preserve_filename)
 		env_put("MAILDIR_COPY_PRESERVE_FILENAME=1");
+	if (set->maildir_very_dirty_syncs)
+		env_put("MAILDIR_VERY_DIRTY_SYNCS=1");
 	if (set->mail_debug)
 		env_put("DEBUG=1");
 	if (set->mail_full_filesystem_access)
--- a/src/master/master-settings-defs.c	Mon Mar 30 20:27:02 2009 -0400
+++ b/src/master/master-settings-defs.c	Mon Mar 30 20:27:14 2009 -0400
@@ -87,6 +87,7 @@
 	DEF_BOOL(maildir_stat_dirs),
 	DEF_BOOL(maildir_copy_with_hardlinks),
 	DEF_BOOL(maildir_copy_preserve_filename),
+	DEF_BOOL(maildir_very_dirty_syncs),
 	DEF_STR(mbox_read_locks),
 	DEF_STR(mbox_write_locks),
 	DEF_INT(mbox_lock_timeout),
--- a/src/master/master-settings.c	Mon Mar 30 20:27:02 2009 -0400
+++ b/src/master/master-settings.c	Mon Mar 30 20:27:14 2009 -0400
@@ -253,6 +253,7 @@
 	MEMBER(maildir_stat_dirs) FALSE,
 	MEMBER(maildir_copy_with_hardlinks) TRUE,
 	MEMBER(maildir_copy_preserve_filename) FALSE,
+	MEMBER(maildir_very_dirty_syncs) FALSE,
 	MEMBER(mbox_read_locks) "fcntl",
 	MEMBER(mbox_write_locks) "dotlock fcntl",
 	MEMBER(mbox_lock_timeout) 300,
--- a/src/master/master-settings.h	Mon Mar 30 20:27:02 2009 -0400
+++ b/src/master/master-settings.h	Mon Mar 30 20:27:14 2009 -0400
@@ -99,6 +99,7 @@
 	bool maildir_stat_dirs;
 	bool maildir_copy_with_hardlinks;
 	bool maildir_copy_preserve_filename;
+	bool maildir_very_dirty_syncs;
 	const char *mbox_read_locks;
 	const char *mbox_write_locks;
 	unsigned int mbox_lock_timeout;