[dovecot-cvs] dovecot/src/lib-index/maildir maildir-expunge.c,NONE,1.1 maildir-update-flags.c,NONE,1.1 Makefile.am,1.6,1.7 maildir-build.c,1.22,1.23 maildir-index.c,1.29,1.30 maildir-index.h,1.20,1.21 maildir-open.c,1.15,1.16 maildir-sync.c,1.39,1.40 maildir-uidlist.c,1.4,1.5

cras at procontrol.fi cras at procontrol.fi
Sun May 18 16:26:08 EEST 2003


Update of /home/cvs/dovecot/src/lib-index/maildir
In directory danu:/tmp/cvs-serv23020/lib-index/maildir

Modified Files:
	Makefile.am maildir-build.c maildir-index.c maildir-index.h 
	maildir-open.c maildir-sync.c maildir-uidlist.c 
Added Files:
	maildir-expunge.c maildir-update-flags.c 
Log Message:
Maildir syncing updates: it's now faster, it handles read-only folders, it
handles many out of disk space conditions (uidlist doesn't) and all commands
finally handle the condition when maildir filename was renamed after
our syncing but before we had the chance to open it.



--- NEW FILE: maildir-expunge.c ---
/* Copyright (C) 2002 Timo Sirainen */

#include "lib.h"
#include "maildir-index.h"
#include "mail-index-util.h"

#include <unistd.h>

static int maildir_expunge_mail_file(struct mail_index *index,
				     struct mail_index_record *rec,
				     const char **fname)
{
	const char *path;

	*fname = maildir_get_location(index, rec);
	if (*fname == NULL)
		return -1;

	if ((rec->index_flags & INDEX_MAIL_FLAG_MAILDIR_NEW) != 0) {
		/* probably in new/ dir */
		path = t_strconcat(index->mailbox_path, "/new/", *fname, NULL);
		if (unlink(path) == 0)
			return 1;

		if (errno == EACCES)
			return -1;
		if (errno != ENOENT) {
			index_set_error(index, "unlink(%s) failed: %m", path);
			return -1;
		}
	}

	path = t_strconcat(index->mailbox_path, "/cur/", *fname, NULL);
	if (unlink(path) == 0)
		return 1;

	if (errno == EACCES)
		return -1;

	if (errno != ENOENT) {
		index_set_error(index, "unlink(%s) failed: %m", path);
		return -1;
	}

	return 0;
}

int maildir_expunge_mail(struct mail_index *index,
			 struct mail_index_record *rec)
{
	const char *fname;
	int i, ret, found;

	for (i = 0;; i++) {
		ret = maildir_expunge_mail_file(index, rec, &fname);
		if (ret > 0)
			return TRUE;
		if (ret < 0)
			return FALSE;

		if (i == 10) {
			index_set_error(index, "Filename keeps changing, "
					"expunge failed: %s", fname);
			return FALSE;
		}

		if (!maildir_index_sync_readonly(index, fname, &found))
			return FALSE;

		if (!found) {
			/* syncing didn't find it, it's already deleted */
			return TRUE;
		}
	}
}

--- NEW FILE: maildir-update-flags.c ---
/* Copyright (C) 2002 Timo Sirainen */

#include "lib.h"
#include "maildir-index.h"
#include "mail-index-util.h"

#include <stdio.h>

static int handle_error(struct mail_index *index,
			const char *path, const char *new_path)
{
	if (errno == ENOENT)
		return 0;

	if (ENOSPACE(errno)) {
		index->nodiskspace = TRUE;
		return -2;
	}

	if (errno == EPERM)
		index->mailbox_readonly = TRUE;
	else {
		index_set_error(index, "rename(%s, %s) failed: %m",
				path, new_path);
	}

	return -1;
}

static int maildir_rename_mail_file(struct mail_index *index,
				    struct mail_index_record *rec,
				    const char *old_fname, const char *new_path)
{
	const char *path;

	if ((rec->index_flags & INDEX_MAIL_FLAG_MAILDIR_NEW) != 0) {
		/* probably in new/ dir */
		path = t_strconcat(index->mailbox_path, "/new/",
				   old_fname, NULL);
		if (rename(path, new_path) == 0)
			return 1;

		if (errno != ENOENT)
			return handle_error(index, path, new_path);
	}

	path = t_strconcat(index->mailbox_path, "/cur/", old_fname, NULL);
	if (rename(path, new_path) == 0)
		return 1;

	return handle_error(index, path, new_path);
}

static int maildir_rename_mail(struct mail_index *index,
			       struct mail_index_record *rec,
			       enum mail_flags flags, const char **new_fname_r)
{
	const char *old_fname, *new_fname, *new_path;
	int i, ret, found;

	new_fname = new_path = NULL;

	i = 0;
	do {
		/* we need to update the flags in the file name */
		old_fname = maildir_get_location(index, rec);
		if (old_fname == NULL)
			return FALSE;

		if (new_path == NULL) {
			new_fname = maildir_filename_set_flags(old_fname,
							       flags);
                        *new_fname_r = new_fname;
			new_path = t_strconcat(index->mailbox_path,
					       "/cur/", new_fname, NULL);
		}

		if (strcmp(old_fname, new_fname) == 0)
			ret = 1;
		else {
			ret = maildir_rename_mail_file(index, rec, old_fname,
						       new_path);
			if (ret == -1)
				return FALSE;

			if (ret == 1 && index->maildir_keep_new) {
				/* looks like we have some more space again,
				   see if we could move mails from new/ to
				   cur/ again */
				index->maildir_keep_new = FALSE;
			}

		}
		if (ret == 0) {
			if (!maildir_index_sync_readonly(index, old_fname,
							 &found))
				return FALSE;
			if (!found)
				break;
		}

		i++;
	} while (i < 10 && ret == 0);

	if (ret != 1) {
		/* we couldn't actually rename() the file now.
		   leave it's flags dirty so they get changed later. */
		rec->index_flags |= INDEX_MAIL_FLAG_DIRTY;
	}
	return TRUE;
}

int maildir_index_update_flags(struct mail_index *index,
			       struct mail_index_record *rec, unsigned int seq,
			       enum mail_flags flags, int external_change)
{
	struct mail_index_update *update;
	const char *new_fname;
	int ret;

	t_push();
	if (!maildir_rename_mail(index, rec, flags, &new_fname)) {
		t_pop();
		return FALSE;
	}

	/* update the filename in index */
	update = index->update_begin(index, rec);
	index->update_field(update, DATA_FIELD_LOCATION, new_fname, 0);

	if (!index->update_end(update))
		ret = FALSE;
	else if (!mail_index_update_flags(index, rec, seq, flags,
					  external_change))
		ret = FALSE;
	else
		ret = TRUE;
	t_pop();

	return ret;
}

Index: Makefile.am
===================================================================
RCS file: /home/cvs/dovecot/src/lib-index/maildir/Makefile.am,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- Makefile.am	12 May 2003 06:14:50 -0000	1.6
+++ Makefile.am	18 May 2003 12:26:06 -0000	1.7
@@ -10,10 +10,12 @@
 	maildir-index.c \
 	maildir-build.c \
 	maildir-clean.c \
+	maildir-expunge.c \
 	maildir-open.c \
 	maildir-rebuild.c \
 	maildir-sync.c \
-	maildir-uidlist.c
+	maildir-uidlist.c \
+	maildir-update-flags.c
 
 noinst_HEADERS = \
 	maildir-index.h \

Index: maildir-build.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-index/maildir/maildir-build.c,v
retrieving revision 1.22
retrieving revision 1.23
diff -u -d -r1.22 -r1.23
--- maildir-build.c	8 May 2003 18:59:38 -0000	1.22
+++ maildir-build.c	18 May 2003 12:26:06 -0000	1.23
@@ -31,7 +31,7 @@
 }
 
 static int maildir_index_append_fd(struct mail_index *index,
-				   int fd, const char *fname)
+				   int fd, const char *fname, int new_dir)
 {
 	struct mail_index_record *rec;
 	struct mail_index_update *update;
@@ -79,6 +79,8 @@
 	}
 
 	/* set the location */
+	if (new_dir)
+		rec->index_flags |= INDEX_MAIL_FLAG_MAILDIR_NEW;
 	index->update_field(update, DATA_FIELD_LOCATION, fname,
 			    MAILDIR_LOCATION_EXTRA_SPACE);
 
@@ -94,7 +96,7 @@
 }
 
 int maildir_index_append_file(struct mail_index *index, const char *dir,
-			      const char *fname)
+			      const char *fname, int new_dir)
 {
 	const char *path;
 	int fd, ret;
@@ -103,22 +105,25 @@
 
 	if ((index->header->cache_fields & ~DATA_FIELD_LOCATION) == 0) {
 		/* nothing cached, don't bother opening the file */
-		return maildir_index_append_fd(index, -1, fname);
+		return maildir_index_append_fd(index, -1, fname, new_dir);
 	}
 
 	path = t_strconcat(dir, "/", fname, NULL);
 	fd = open(path, O_RDONLY);
 	if (fd == -1) {
-		/* open() failed - treat it as error unless the error was
-		   "file doesn't exist" in which case someone just managed
-		   to delete it before we saw it */
-		if (errno == EEXIST)
-			return TRUE;
+		if (errno == ENOENT) {
+			/* it's not found because it's deleted or renamed.
+			   don't try to handle any error cases here, just
+			   save the thing and let the syncing handle it
+			   later */
+			return maildir_index_append_fd(index, -1,
+						       fname, new_dir);
+		}
 
 		return index_file_set_syscall_error(index, path, "open()");
 	}
 
-	ret = maildir_index_append_fd(index, fd, fname);
+	ret = maildir_index_append_fd(index, fd, fname, new_dir);
 	if (close(fd) < 0)
 		return index_file_set_syscall_error(index, path, "close()");
 	return ret;

Index: maildir-index.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-index/maildir/maildir-index.c,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -d -r1.29 -r1.30
--- maildir-index.c	17 May 2003 13:09:55 -0000	1.29
+++ maildir-index.c	18 May 2003 12:26:06 -0000	1.30
@@ -2,6 +2,7 @@
 
 #include "lib.h"
 #include "ioloop.h"
+#include "hash.h"
 #include "hostpid.h"
 #include "str.h"
 #include "maildir-index.h"
@@ -25,13 +26,20 @@
 const char *maildir_get_location(struct mail_index *index,
 				 struct mail_index_record *rec)
 {
-	const char *fname;
+	const char *fname, *new_fname;
 
 	fname = index->lookup_field(index, rec, DATA_FIELD_LOCATION);
 	if (fname == NULL) {
 		index_data_set_corrupted(index->data,
 			"Missing location field for record %u", rec->uid);
 	}
+
+	if (index->new_filenames != NULL) {
+		new_fname = hash_lookup(index->new_filenames, fname);
+		if (new_fname != NULL)
+			return new_fname;
+	}
+
 	return fname;
 }
 
@@ -225,9 +233,15 @@
 
 static void maildir_index_free(struct mail_index *index)
 {
+	if (index->new_filenames != NULL)
+		hash_destroy(index->new_filenames);
+	if (index->new_filename_pool != NULL)
+		pool_unref(index->new_filename_pool);
+
 	mail_index_close(index);
 	i_free(index->dir);
 	i_free(index->mailbox_path);
+	i_free(index->control_dir);
 	i_free(index);
 }
 
@@ -254,53 +268,6 @@
 	}
 
 	return st.st_mtime;
-}
-
-static int maildir_index_update_flags(struct mail_index *index,
-				      struct mail_index_record *rec,
-				      unsigned int seq, enum mail_flags flags,
-				      int external_change)
-{
-	struct mail_index_update *update;
-	const char *old_fname, *new_fname;
-	const char *old_path, *new_path;
-
-	/* we need to update the flags in the file name */
-	old_fname = maildir_get_location(index, rec);
-	if (old_fname == NULL)
-		return FALSE;
-
-	new_fname = maildir_filename_set_flags(old_fname, flags);
-
-	if (strcmp(old_fname, new_fname) != 0) {
-		old_path = t_strconcat(index->mailbox_path,
-				       "/cur/", old_fname, NULL);
-		new_path = t_strconcat(index->mailbox_path,
-				       "/cur/", new_fname, NULL);
-
-		/* minor problem: new_path is overwritten if it exists.. */
-		if (rename(old_path, new_path) < 0) {
-			if (ENOSPACE(errno))
-				index->nodiskspace = TRUE;
-
-			index_set_error(index, "maildir flags update: "
-					"rename(%s, %s) failed: %m",
-					old_path, new_path);
-			return FALSE;
-		}
-
-		/* update the filename in index */
-		update = index->update_begin(index, rec);
-		index->update_field(update, DATA_FIELD_LOCATION, new_fname, 0);
-
-		if (!index->update_end(update))
-			return FALSE;
-	}
-
-	if (!mail_index_update_flags(index, rec, seq, flags, external_change))
-		return FALSE;
-
-	return TRUE;
 }
 
 struct mail_index maildir_index = {

Index: maildir-index.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib-index/maildir/maildir-index.h,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -d -r1.20 -r1.21
--- maildir-index.h	17 May 2003 13:09:55 -0000	1.20
+++ maildir-index.h	18 May 2003 12:26:06 -0000	1.21
@@ -25,15 +25,23 @@
 				       enum mail_flags flags);
 
 int maildir_index_rebuild(struct mail_index *index);
+int maildir_index_sync_readonly(struct mail_index *index,
+				const char *fname, int *found);
 int maildir_index_sync(struct mail_index *index,
 		       enum mail_lock_type lock_type, int *changes);
 
 int maildir_index_append_file(struct mail_index *index, const char *dir,
-			      const char *fname);
+			      const char *fname, int new_dir);
+int maildir_index_update_flags(struct mail_index *index,
+			       struct mail_index_record *rec, unsigned int seq,
+			       enum mail_flags flags, int external_change);
 
 struct istream *maildir_open_mail(struct mail_index *index,
 				  struct mail_index_record *rec,
 				  time_t *internal_date, int *deleted);
+
+int maildir_expunge_mail(struct mail_index *index,
+			 struct mail_index_record *rec);
 
 void maildir_clean_tmp(const char *dir);
 

Index: maildir-open.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-index/maildir/maildir-open.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- maildir-open.c	9 Mar 2003 11:57:35 -0000	1.15
+++ maildir-open.c	18 May 2003 12:26:06 -0000	1.16
@@ -10,13 +10,51 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 
+static int maildir_open_mail_file(struct mail_index *index,
+				  struct mail_index_record *rec,
+				  const char **fname, int *deleted)
+{
+	const char *path;
+	int fd = -1;
+
+	*fname = maildir_get_location(index, rec);
+	if (*fname == NULL)
+		return -1;
+
+	if ((rec->index_flags & INDEX_MAIL_FLAG_MAILDIR_NEW) != 0) {
+		/* probably in new/ dir */
+		path = t_strconcat(index->mailbox_path, "/new/", *fname, NULL);
+		fd = open(path, O_RDONLY);
+		if (fd == -1 && errno != ENOENT) {
+			index_set_error(index, "open(%s) failed: %m", path);
+			return -1;
+		}
+	}
+
+	if (fd == -1) {
+		path = t_strconcat(index->mailbox_path, "/cur/", *fname, NULL);
+		fd = open(path, O_RDONLY);
+		if (fd == -1) {
+			if (errno == ENOENT) {
+				*deleted = TRUE;
+				return -1;
+			}
+
+			index_set_error(index, "open(%s) failed: %m", path);
+			return -1;
+		}
+	}
+
+	return fd;
+}
+
 struct istream *maildir_open_mail(struct mail_index *index,
 				  struct mail_index_record *rec,
 				  time_t *internal_date, int *deleted)
 {
 	struct stat st;
-	const char *fname, *path;
-	int fd;
+	const char *fname;
+	int i, found, fd;
 
 	i_assert(index->lock_type != MAIL_LOCK_UNLOCK);
 
@@ -26,20 +64,24 @@
 	if (index->inconsistent)
 		return NULL;
 
-	fname = maildir_get_location(index, rec);
-	if (fname == NULL)
-		return NULL;
+	fd = maildir_open_mail_file(index, rec, &fname, deleted);
+	for (i = 0; fd == -1 && *deleted && i < 10; i++) {
+		/* file is either renamed or deleted. sync the maildir and
+		   see which one. if file appears to be renamed constantly,
+		   don't try to open it more than 10 times. */
+		if (!maildir_index_sync_readonly(index, fname, &found)) {
+			*deleted = FALSE;
+			return NULL;
+		}
 
-	path = t_strconcat(index->mailbox_path, "/cur/", fname, NULL);
-	fd = open(path, O_RDONLY);
-	if (fd == -1) {
-		if (errno == ENOENT) {
-			*deleted = TRUE;
+		if (!found) {
+			/* syncing didn't find it, it's deleted */
 			return NULL;
 		}
 
-		index_set_error(index, "Error opening mail file %s: %m", path);
-		return NULL;
+		fd = maildir_open_mail_file(index, rec, &fname, deleted);
+		if (fd == -1)
+			return NULL;
 	}
 
 	if (internal_date != NULL) {

Index: maildir-sync.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-index/maildir/maildir-sync.c,v
retrieving revision 1.39
retrieving revision 1.40
diff -u -d -r1.39 -r1.40
--- maildir-sync.c	8 May 2003 18:59:38 -0000	1.39
+++ maildir-sync.c	18 May 2003 12:26:06 -0000	1.40
@@ -1,7 +1,170 @@
 /* Copyright (C) 2002-2003 Timo Sirainen */
 
+/*
+   Here's a description of how we handle Maildir synchronization and
+   it's problems:
+
+   We want to be as efficient as we can. The most efficient way to
+   check if changes have occured is to stat() the new/ and cur/
+   directories and uidlist file - if their mtimes haven't changed,
+   there's no changes and we don't need to do anything.
+
[...1344 lines suppressed...]
+	return ret;
+}
+
+int maildir_index_sync(struct mail_index *index,
+		       enum mail_lock_type data_lock_type __attr_unused__,
+		       int *changes)
+{
+        struct maildir_sync_context *ctx;
+	int ret;
+
+	i_assert(index->lock_type != MAIL_LOCK_SHARED);
+
+	if (changes != NULL)
+		*changes = FALSE;
+
+	ctx = maildir_sync_context_new(index);
+	ret = maildir_index_sync_context(ctx, changes);
+        maildir_index_sync_deinit(ctx);
 	return ret;
 }

Index: maildir-uidlist.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-index/maildir/maildir-uidlist.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- maildir-uidlist.c	17 May 2003 13:09:55 -0000	1.4
+++ maildir-uidlist.c	18 May 2003 12:26:06 -0000	1.5
@@ -83,7 +83,7 @@
 struct maildir_uidlist *maildir_uidlist_open(struct mail_index *index)
 {
 	const char *path, *line;
-        struct maildir_uidlist *uidlist;
+	struct maildir_uidlist *uidlist;
 	unsigned int version;
 	int fd;
 



More information about the dovecot-cvs mailing list