[dovecot-cvs] dovecot/src/lib-storage/index/maildir maildir-copy.c, 1.31, 1.32 maildir-save.c, 1.37, 1.38 maildir-storage.c, 1.82, 1.83 maildir-storage.h, 1.26, 1.27 maildir-transaction.c, 1.2, 1.3

cras at dovecot.org cras at dovecot.org
Sun Aug 22 12:17:11 EEST 2004


Update of /home/cvs/dovecot/src/lib-storage/index/maildir
In directory talvi:/tmp/cvs-serv2400/lib-storage/index/maildir

Modified Files:
	maildir-copy.c maildir-save.c maildir-storage.c 
	maildir-storage.h maildir-transaction.c 
Log Message:
Changed mail saving API to be nonblocking.



Index: maildir-copy.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/maildir/maildir-copy.c,v
retrieving revision 1.31
retrieving revision 1.32
diff -u -d -r1.31 -r1.32
--- maildir-copy.c	20 Jun 2004 03:25:33 -0000	1.31
+++ maildir-copy.c	22 Aug 2004 09:17:08 -0000	1.32
@@ -3,7 +3,7 @@
 #include "lib.h"
 #include "ioloop.h"
 #include "maildir-storage.h"
-#include "mail-save.h"
+#include "mail-copy.h"
 
 #include <stdlib.h>
 #include <unistd.h>
@@ -100,13 +100,13 @@
 	return ctx;
 }
 
-int maildir_copy_commit(struct maildir_copy_context *ctx)
+int maildir_transaction_copy_commit(struct maildir_copy_context *ctx)
 {
 	pool_unref(ctx->pool);
 	return 0;
 }
 
-void maildir_copy_rollback(struct maildir_copy_context *ctx)
+void maildir_transaction_copy_rollback(struct maildir_copy_context *ctx)
 {
         struct rollback *rb;
 

Index: maildir-save.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/maildir/maildir-save.c,v
retrieving revision 1.37
retrieving revision 1.38
diff -u -d -r1.37 -r1.38
--- maildir-save.c	15 Aug 2004 03:40:32 -0000	1.37
+++ maildir-save.c	22 Aug 2004 09:17:08 -0000	1.38
@@ -6,7 +6,6 @@
 #include "str.h"
 #include "maildir-storage.h"
 #include "maildir-uidlist.h"
-#include "mail-save.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -21,6 +20,7 @@
 };
 
 struct maildir_save_context {
+	struct mail_save_context ctx;
 	pool_t pool;
 
 	struct index_mailbox *ibox;
@@ -29,49 +29,16 @@
 
 	const char *tmpdir, *newdir, *curdir;
 	struct maildir_filename *files;
-};
 
-static const char *
-maildir_read_into_tmp(struct index_mailbox *ibox, const char *dir,
-		      struct istream *input)
-{
-	const char *path, *fname;
+	struct istream *input;
 	struct ostream *output;
-	int fd, crlf;
-
-	fd = maildir_create_tmp(ibox, dir, ibox->mail_create_mode, &path);
-	if (fd == -1)
-		return NULL;
-
-	fname = strrchr(path, '/');
-	i_assert(fname != NULL);
-	fname++;
-
-	output = o_stream_create_file(fd, pool_datastack_create(), 0, FALSE);
-
-	crlf = getenv("MAIL_SAVE_CRLF") != NULL;
-	if (mail_storage_save(ibox->box.storage, path, input, output,
-			      crlf, crlf, NULL, NULL) < 0)
-		fname = NULL;
-
-	o_stream_unref(output);
-	/* FIXME: when saving multiple messages, we could get better
-	   performance if we left the fd open and fsync()ed it later */
-	if (fsync(fd) < 0) {
-		mail_storage_set_critical(ibox->box.storage,
-					  "fsync() failed for %s: %m", path);
-		fname = NULL;
-	}
-	if (close(fd) < 0) {
-		mail_storage_set_critical(ibox->box.storage,
-					  "close() failed for %s: %m", path);
-		fname = NULL;
-	}
+	int fd;
+	time_t received_date;
+	uint32_t seq;
 
-	if (fname == NULL)
-		(void)unlink(path);
-	return fname;
-}
+	unsigned int save_crlf:1;
+	unsigned int failed:1;
+};
 
 static int maildir_file_move(struct maildir_save_context *ctx,
 			     const char *basename, const char *dest)
@@ -112,7 +79,7 @@
 }
 
 static struct maildir_save_context *
-mailbox_save_init(struct maildir_transaction_context *t)
+maildir_transaction_save_init(struct maildir_transaction_context *t)
 {
         struct index_mailbox *ibox = t->ictx.ibox;
 	struct maildir_save_context *ctx;
@@ -120,6 +87,7 @@
 
 	pool = pool_alloconly_create("maildir_save_context", 4096);
 	ctx = p_new(pool, struct maildir_save_context, 1);
+	ctx->ctx.box = &ibox->box;
 	ctx->pool = pool;
 	ctx->ibox = ibox;
 	ctx->trans = t->ictx.trans;
@@ -129,30 +97,50 @@
 	ctx->tmpdir = p_strconcat(pool, ibox->path, "/tmp", NULL);
 	ctx->newdir = p_strconcat(pool, ibox->path, "/new", NULL);
 	ctx->curdir = p_strconcat(pool, ibox->path, "/cur", NULL);
+
+	ctx->save_crlf = getenv("MAIL_SAVE_CRLF") != NULL;
 	return ctx;
 }
 
-int maildir_save(struct mailbox_transaction_context *_t,
-		 const struct mail_full_flags *flags,
-		 time_t received_date, int timezone_offset __attr_unused__,
-		 const char *from_envelope __attr_unused__,
-		 struct istream *data, struct mail **mail_r)
+struct mail_save_context *
+maildir_save_init(struct mailbox_transaction_context *_t,
+		  const struct mail_full_flags *flags,
+		  time_t received_date, int timezone_offset __attr_unused__,
+		  const char *from_envelope __attr_unused__,
+		  struct istream *input, int want_mail __attr_unused__)
 {
 	struct maildir_transaction_context *t =
 		(struct maildir_transaction_context *)_t;
 	struct maildir_save_context *ctx;
 	struct index_mailbox *ibox = t->ictx.ibox;
 	struct maildir_filename *mf;
-        struct utimbuf buf;
-	const char *fname, *dest_fname, *tmp_path;
+	const char *fname, *dest_fname, *path;
 	enum mail_flags mail_flags;
 	keywords_mask_t keywords;
-	uint32_t seq;
+
+	t_push();
 
 	if (t->save_ctx == NULL)
-		t->save_ctx = mailbox_save_init(t);
+		t->save_ctx = maildir_transaction_save_init(t);
 	ctx = t->save_ctx;
 
+	/* create a new file in tmp/ directory */
+	ctx->fd = maildir_create_tmp(ibox, ctx->tmpdir, ibox->mail_create_mode,
+				     &path);
+	if (ctx->fd == -1) {
+		ctx->failed = TRUE;
+		t_pop();
+		return &ctx->ctx;
+	}
+
+	fname = strrchr(path, '/');
+	i_assert(fname != NULL);
+	fname++;
+
+	ctx->received_date = received_date;
+	ctx->input = input;
+	ctx->output = o_stream_create_file(ctx->fd, system_pool, 0, FALSE);
+
 	mail_flags = (flags->flags & ~MAIL_RECENT) |
 		(ibox->keep_recent ? MAIL_RECENT : 0);
 	/*FIXME:if (!index_mailbox_fix_keywords(ibox, &mail_flags,
@@ -160,29 +148,6 @@
 					    flags->keywords_count))
 		return FALSE;*/
 
-	t_push();
-
-	/* create the file into tmp/ directory */
-	fname = maildir_read_into_tmp(ibox, ctx->tmpdir, data);
-	if (fname == NULL) {
-		t_pop();
-		return -1;
-	}
-
-	tmp_path = t_strconcat(ctx->tmpdir, "/", fname, NULL);
-
-	if (received_date != (time_t)-1) {
-		/* set the received_date by modifying mtime */
-		buf.actime = ioloop_time;
-		buf.modtime = received_date;
-		if (utime(tmp_path, &buf) < 0) {
-			mail_storage_set_critical(ibox->box.storage,
-				"utime(%s) failed: %m", tmp_path);
-			t_pop();
-			return -1;
-		}
-	}
-
 	/* now, we want to be able to rollback the whole append session,
 	   so we'll just store the name of this temp file and move it later
 	   into new/ or cur/. if dest_fname is NULL, it's moved to new/,
@@ -200,20 +165,113 @@
 	memset(keywords, 0, INDEX_KEYWORDS_BYTE_COUNT);
 	// FIXME: set keywords
 
-	mail_index_append(t->ictx.trans, 0, &seq);
-	mail_index_update_flags(t->ictx.trans, seq, MODIFY_REPLACE,
+	mail_index_append(t->ictx.trans, 0, &ctx->seq);
+	mail_index_update_flags(t->ictx.trans, ctx->seq, MODIFY_REPLACE,
 				mail_flags, keywords);
 	t_pop();
 
+	ctx->failed = FALSE;
+	return &ctx->ctx;
+}
+
+int maildir_save_continue(struct mail_save_context *_ctx)
+{
+	struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
+
+	if (ctx->failed)
+		return -1;
+
+	if (o_stream_send_istream(ctx->output, ctx->input) < 0) {
+		ctx->failed = TRUE;
+		return -1;
+	}
+	return 0;
+}
+
+int maildir_save_finish(struct mail_save_context *_ctx, struct mail **mail_r)
+{
+	struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
+	struct utimbuf buf;
+	const char *path;
+
+	if (ctx->failed && ctx->fd == -1) {
+		/* tmp file creation failed */
+		return -1;
+	}
+
+	t_push();
+	path = t_strconcat(ctx->tmpdir, "/", ctx->files->basename, NULL);
+
+	if (ctx->received_date != (time_t)-1) {
+		/* set the received_date by modifying mtime */
+		buf.actime = ioloop_time;
+		buf.modtime = ctx->received_date;
+
+		if (utime(path, &buf) < 0) {
+			ctx->failed = TRUE;
+			mail_storage_set_critical(ctx->ibox->box.storage,
+						  "utime(%s) failed: %m", path);
+		}
+	}
+
+	o_stream_unref(ctx->output);
+	ctx->output = NULL;
+
+	/* FIXME: when saving multiple messages, we could get better
+	   performance if we left the fd open and fsync()ed it later */
+	if (fsync(ctx->fd) < 0) {
+		mail_storage_set_critical(ctx->ibox->box.storage,
+					  "fsync(%s) failed: %m", path);
+		ctx->failed = TRUE;
+	}
+	if (close(ctx->fd) < 0) {
+		mail_storage_set_critical(ctx->ibox->box.storage,
+					  "close(%s) failed: %m", path);
+		ctx->failed = TRUE;
+	}
+	ctx->fd = -1;
+
+	if (ctx->failed) {
+		/* delete the tmp file */
+		if (unlink(path) < 0 && errno != ENOENT) {
+			mail_storage_set_critical(ctx->ibox->box.storage,
+				"unlink(%s) failed: %m", path);
+		}
+
+		errno = ctx->output->stream_errno;
+		if (ENOSPACE(errno)) {
+			mail_storage_set_error(ctx->ibox->box.storage,
+					       "Not enough disk space");
+		} else if (errno != 0) {
+			mail_storage_set_critical(ctx->ibox->box.storage,
+				"write(%s) failed: %m", ctx->ibox->path);
+		}
+
+		ctx->files = ctx->files->next;
+		t_pop();
+		return -1;
+	}
+
 	if (mail_r != NULL) {
-		if (index_mail_next(&ctx->mail, seq) < 0)
+		i_assert(ctx->seq != 0);
+
+		if (index_mail_next(&ctx->mail, ctx->seq) < 0)
 			return -1;
 		*mail_r = &ctx->mail.mail;
 	}
 
+	t_pop();
 	return 0;
 }
 
+void maildir_save_cancel(struct mail_save_context *_ctx)
+{
+	struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
+
+	ctx->failed = TRUE;
+	(void)maildir_save_finish(_ctx, NULL);
+}
+
 static void maildir_save_commit_abort(struct maildir_save_context *ctx,
 				      struct maildir_filename *pos)
 {
@@ -235,10 +293,10 @@
 	ctx->files = pos;
 	t_pop();
 
-	maildir_save_rollback(ctx);
+	maildir_transaction_save_rollback(ctx);
 }
 
-int maildir_save_commit(struct maildir_save_context *ctx)
+int maildir_transaction_save_commit(struct maildir_save_context *ctx)
 {
 	struct maildir_uidlist_sync_ctx *sync_ctx;
 	struct maildir_filename *mf;
@@ -247,6 +305,8 @@
 	const char *fname;
 	int ret = 0;
 
+	i_assert(ctx->output == NULL);
+
 	ret = maildir_uidlist_lock(ctx->ibox->uidlist);
 	if (ret <= 0) {
 		/* error or timeout - our transaction is broken */
@@ -284,11 +344,13 @@
 	return ret;
 }
 
-void maildir_save_rollback(struct maildir_save_context *ctx)
+void maildir_transaction_save_rollback(struct maildir_save_context *ctx)
 {
 	struct maildir_filename *mf;
 	string_t *str;
 
+	i_assert(ctx->output == NULL);
+
 	t_push();
 	str = t_str_new(1024);
 

Index: maildir-storage.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/maildir/maildir-storage.c,v
retrieving revision 1.82
retrieving revision 1.83
diff -u -d -r1.82 -r1.83
--- maildir-storage.c	22 Jul 2004 21:20:01 -0000	1.82
+++ maildir-storage.c	22 Aug 2004 09:17:08 -0000	1.83
@@ -805,7 +805,10 @@
 	index_storage_search_init,
 	index_storage_search_deinit,
 	index_storage_search_next,
-	maildir_save,
+	maildir_save_init,
+	maildir_save_continue,
+	maildir_save_finish,
+	maildir_save_cancel,
 	maildir_copy,
 	index_storage_is_inconsistent
 };

Index: maildir-storage.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/maildir/maildir-storage.h,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -d -r1.26 -r1.27
--- maildir-storage.h	22 Jul 2004 21:20:01 -0000	1.26
+++ maildir-storage.h	22 Aug 2004 09:17:08 -0000	1.27
@@ -48,18 +48,23 @@
 int maildir_transaction_commit(struct mailbox_transaction_context *t);
 void maildir_transaction_rollback(struct mailbox_transaction_context *t);
 
-int maildir_save(struct mailbox_transaction_context *t,
-		 const struct mail_full_flags *flags,
-		 time_t received_date, int timezone_offset,
-		 const char *from_envelope, struct istream *data,
-		 struct mail **mail_r);
-int maildir_save_commit(struct maildir_save_context *ctx);
-void maildir_save_rollback(struct maildir_save_context *ctx);
+struct mail_save_context *
+maildir_save_init(struct mailbox_transaction_context *_t,
+		  const struct mail_full_flags *flags,
+		  time_t received_date, int timezone_offset,
+		  const char *from_envelope, struct istream *input,
+		  int want_mail);
+int maildir_save_continue(struct mail_save_context *ctx);
+int maildir_save_finish(struct mail_save_context *ctx, struct mail **mail_r);
+void maildir_save_cancel(struct mail_save_context *ctx);
+
+int maildir_transaction_save_commit(struct maildir_save_context *ctx);
+void maildir_transaction_save_rollback(struct maildir_save_context *ctx);
 
 int maildir_copy(struct mailbox_transaction_context *t, struct mail *mail,
 		 struct mail **dest_mail_r);
-int maildir_copy_commit(struct maildir_copy_context *ctx);
-void maildir_copy_rollback(struct maildir_copy_context *ctx);
+int maildir_transaction_copy_commit(struct maildir_copy_context *ctx);
+void maildir_transaction_copy_rollback(struct maildir_copy_context *ctx);
 
 const char *maildir_get_path(struct index_storage *storage, const char *name);
 

Index: maildir-transaction.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/maildir/maildir-transaction.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- maildir-transaction.c	22 Jun 2004 07:36:33 -0000	1.2
+++ maildir-transaction.c	22 Aug 2004 09:17:08 -0000	1.3
@@ -22,11 +22,11 @@
 	int ret = 0;
 
 	if (t->save_ctx != NULL) {
-		if (maildir_save_commit(t->save_ctx) < 0)
+		if (maildir_transaction_save_commit(t->save_ctx) < 0)
 			ret = -1;
 	}
 	if (t->copy_ctx != NULL) {
-		if (maildir_copy_commit(t->copy_ctx) < 0)
+		if (maildir_transaction_copy_commit(t->copy_ctx) < 0)
 			ret = -1;
 	}
 
@@ -42,8 +42,8 @@
 		(struct maildir_transaction_context *)_t;
 
 	if (t->save_ctx != NULL)
-		maildir_save_rollback(t->save_ctx);
+		maildir_transaction_save_rollback(t->save_ctx);
 	if (t->copy_ctx != NULL)
-		maildir_copy_rollback(t->copy_ctx);
+		maildir_transaction_copy_rollback(t->copy_ctx);
 	index_transaction_rollback(_t);
 }



More information about the dovecot-cvs mailing list