[dovecot-cvs] dovecot: Write transactions with two pwrite() calls instead of l...

dovecot at dovecot.org dovecot at dovecot.org
Tue May 22 23:01:22 EEST 2007


details:   http://hg.dovecot.org/dovecot/rev/501aab713b0d
changeset: 5655:501aab713b0d
user:      Timo Sirainen <tss at iki.fi>
date:      Tue May 22 23:01:14 2007 +0300
description:
Write transactions with two pwrite() calls instead of lots of tiny ones.

diffstat:

1 file changed, 178 insertions(+), 207 deletions(-)
src/lib-index/mail-transaction-log-append.c |  385 ++++++++++++---------------

diffs (truncated from 504 to 300 lines):

diff -r 29764126e1a6 -r 501aab713b0d src/lib-index/mail-transaction-log-append.c
--- a/src/lib-index/mail-transaction-log-append.c	Tue May 22 22:50:06 2007 +0300
+++ b/src/lib-index/mail-transaction-log-append.c	Tue May 22 23:01:14 2007 +0300
@@ -10,100 +10,103 @@
 #include "mail-index-transaction-private.h"
 #include "mail-transaction-log-private.h"
 
-static int log_append_buffer(struct mail_transaction_log_file *file,
-			     const buffer_t *buf, const buffer_t *hdr_buf,
-			     enum mail_transaction_type type, bool external)
+struct log_append_context {
+	struct mail_transaction_log_file *file;
+	struct mail_index_transaction *trans;
+	buffer_t *output;
+};
+
+static void log_append_buffer(struct log_append_context *ctx,
+			      const buffer_t *buf, const buffer_t *hdr_buf,
+			      enum mail_transaction_type type)
 {
 	struct mail_transaction_header hdr;
-	const void *data, *hdr_data;
-	size_t size, hdr_data_size;
-	uoff_t offset;
 	uint32_t hdr_size;
 
 	i_assert((type & MAIL_TRANSACTION_TYPE_MASK) != 0);
-
-	data = buffer_get_data(buf, &size);
-	if (size == 0)
-		return 0;
-
-	i_assert((size % 4) == 0);
-
-	if (hdr_buf != NULL) {
-		hdr_data = buffer_get_data(hdr_buf, &hdr_data_size);
-		i_assert((hdr_data_size % 4) == 0);
-	} else {
-		hdr_data = NULL;
-		hdr_data_size = 0;
-	}
+	i_assert((buf->used % 4) == 0);
+	i_assert(hdr_buf == NULL || (hdr_buf->used % 4) == 0);
+
+	if (buf->used == 0)
+		return;
 
 	memset(&hdr, 0, sizeof(hdr));
 	hdr.type = type;
 	if (type == MAIL_TRANSACTION_EXPUNGE)
 		hdr.type |= MAIL_TRANSACTION_EXPUNGE_PROT;
-	if (external)
+	if (ctx->trans->external)
 		hdr.type |= MAIL_TRANSACTION_EXTERNAL;
 
-	hdr_size = mail_index_uint32_to_offset(sizeof(hdr) + size +
-					       hdr_data_size);
-	if (!MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
-		do {
-			offset = file->sync_offset;
-			if (file->first_append_size == 0) {
-				/* size will be written later once everything
-				   is in disk */
-				file->first_append_size = hdr_size;
-			} else {
-				hdr.size = hdr_size;
-			}
-			if (pwrite_full(file->fd, &hdr, sizeof(hdr),
-					offset) < 0)
-				break;
-			offset += sizeof(hdr);
-
-			if (hdr_data_size > 0) {
-				if (pwrite_full(file->fd, hdr_data,
-						hdr_data_size, offset) < 0)
-					break;
-				offset += hdr_data_size;
-			}
-
-			if (pwrite_full(file->fd, data, size, offset) < 0)
-				break;
-
-			file->sync_offset = offset + size;
-			return 0;
-		} while (0);
-
-		/* write failure. */
+	hdr_size = mail_index_uint32_to_offset(sizeof(hdr) + buf->used +
+					       (hdr_buf == NULL ? 0 :
+						hdr_buf->used));
+	if (!MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(ctx->file) &&
+	    ctx->file->first_append_size == 0) {
+		/* size will be written later once everything
+		   is in disk */
+		ctx->file->first_append_size = hdr_size;
+	} else {
+		hdr.size = hdr_size;
+	}
+
+	buffer_append(ctx->output, &hdr, sizeof(hdr));
+	if (hdr_buf != NULL)
+		buffer_append(ctx->output, hdr_buf->data, hdr_buf->used);
+	buffer_append(ctx->output, buf->data, buf->used);
+}
+
+static int log_buffer_move_to_memory(struct log_append_context *ctx)
+{
+	struct mail_transaction_log_file *file = ctx->file;
+
+	/* first we need to truncate this latest write so that log syncing
+	   doesn't break */
+	if (ftruncate(file->fd, file->sync_offset) < 0) {
+		mail_index_file_set_syscall_error(file->log->index,
+						  file->filepath,
+						  "ftruncate()");
+	}
+
+	if (mail_index_move_to_memory(file->log->index) < 0)
+		return -1;
+	i_assert(MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file));
+
+	i_assert(file->buffer_offset + file->buffer->used ==
+		 file->sync_offset);
+	buffer_append_buf(file->buffer, ctx->output, 0, (size_t)-1);
+	file->sync_offset = file->buffer_offset + file->buffer->used;
+	return 0;
+}
+
+static int log_buffer_write(struct log_append_context *ctx)
+{
+	struct mail_transaction_log_file *file = ctx->file;
+
+	if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file)) {
+		file->sync_offset = file->buffer_offset + file->buffer->used;
+		return 0;
+	}
+
+	i_assert(file->first_append_size != 0);
+	if (pwrite_full(file->fd, ctx->output->data, ctx->output->used,
+			file->sync_offset) < 0) {
+		/* write failure, fallback to in-memory indexes. */
 		mail_index_file_set_syscall_error(file->log->index,
 						  file->filepath,
 						  "pwrite_full()");
-		if (!ENOSPACE(errno))
-			return -1;
-
-		/* not enough space. fallback to in-memory indexes. first
-		   we need to truncate this latest write so that log syncing
-		   doesn't break */
-		if (ftruncate(file->fd, file->sync_offset) < 0) {
-			mail_index_file_set_syscall_error(file->log->index,
-							  file->filepath,
-							  "ftruncate()");
-			return -1;
-		}
-
-		if (mail_index_move_to_memory(file->log->index) < 0)
-			return -1;
-		i_assert(MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file));
-	}
-
-	hdr.size = hdr_size;
-
-	i_assert(file->buffer_offset + file->buffer->used ==
-		 file->sync_offset);
-	buffer_append(file->buffer, &hdr, sizeof(hdr));
-	buffer_append(file->buffer, hdr_data, hdr_data_size);
-	buffer_append(file->buffer, data, size);
-	file->sync_offset = file->buffer_offset + file->buffer->used;
+		return log_buffer_move_to_memory(ctx);
+	}
+
+	/* now that the whole transaction has been written, rewrite the first
+	   record's size so the transaction becomes visible */
+	if (pwrite_full(file->fd, &file->first_append_size,
+			sizeof(uint32_t), file->sync_offset) < 0) {
+		mail_index_file_set_syscall_error(file->log->index,
+						  file->filepath,
+						  "pwrite_full()");
+		return log_buffer_move_to_memory(ctx);
+	}
+	file->sync_offset += ctx->output->used;
 	return 0;
 }
 
@@ -140,10 +143,10 @@ log_get_hdr_update_buffer(struct mail_in
 	return buf;
 }
 
-static int log_append_ext_intro(struct mail_transaction_log_file *file,
-				struct mail_index_transaction *t,
-				uint32_t ext_id, uint32_t reset_id)
-{
+static void log_append_ext_intro(struct log_append_context *ctx,
+				 uint32_t ext_id, uint32_t reset_id)
+{
+	struct mail_index_transaction *t = ctx->trans;
 	const struct mail_index_registered_ext *rext;
         struct mail_transaction_ext_intro *intro;
 	buffer_t *buf;
@@ -198,14 +201,13 @@ static int log_append_ext_intro(struct m
 	if ((buf->used % 4) != 0)
 		buffer_append_zero(buf, 4 - (buf->used % 4));
 
-	return log_append_buffer(file, buf, NULL, MAIL_TRANSACTION_EXT_INTRO,
-				 t->external);
-}
-
-static int
-mail_transaction_log_append_ext_intros(struct mail_transaction_log_file *file,
-				       struct mail_index_transaction *t)
-{
+	log_append_buffer(ctx, buf, NULL, MAIL_TRANSACTION_EXT_INTRO);
+}
+
+static void
+mail_transaction_log_append_ext_intros(struct log_append_context *ctx)
+{
+	struct mail_index_transaction *t = ctx->trans;
         const struct mail_transaction_ext_intro *resize;
 	struct mail_transaction_ext_reset ext_reset;
 	unsigned int update_count, resize_count, reset_count, ext_count;
@@ -249,24 +251,18 @@ mail_transaction_log_append_ext_intros(s
 		if ((ext_id < resize_count && resize[ext_id].name_size) ||
 		    (ext_id < update_count &&
 		     array_is_created(&update[ext_id])) ||
-		    ext_reset.new_reset_id != 0) {
-			if (log_append_ext_intro(file, t, ext_id, 0) < 0)
-				return -1;
-		}
+		    ext_reset.new_reset_id != 0)
+			log_append_ext_intro(ctx, ext_id, 0);
 		if (ext_reset.new_reset_id != 0) {
-			if (log_append_buffer(file, buf, NULL,
-					      MAIL_TRANSACTION_EXT_RESET,
-					      t->external) < 0)
-				return -1;
-		}
-	}
-
-	return 0;
-}
-
-static int log_append_ext_rec_updates(struct mail_transaction_log_file *file,
-				      struct mail_index_transaction *t)
-{
+			log_append_buffer(ctx, buf, NULL,
+					  MAIL_TRANSACTION_EXT_RESET);
+		}
+	}
+}
+
+static void log_append_ext_rec_updates(struct log_append_context *ctx)
+{
+	struct mail_index_transaction *t = ctx->trans;
 	ARRAY_TYPE(seq_array) *updates;
 	const uint32_t *reset;
 	unsigned int ext_id, count, reset_count;
@@ -292,20 +288,15 @@ static int log_append_ext_rec_updates(st
 
 		reset_id = ext_id < reset_count && reset[ext_id] != 0 ?
 			reset[ext_id] : 0;
-		if (log_append_ext_intro(file, t, ext_id, reset_id) < 0)
-			return -1;
-
-		if (log_append_buffer(file, updates[ext_id].arr.buffer, NULL,
-				      MAIL_TRANSACTION_EXT_REC_UPDATE,
-				      t->external) < 0)
-			return -1;
-	}
-	return 0;
-}
-
-static int
-log_append_keyword_update(struct mail_transaction_log_file *file,
-			  struct mail_index_transaction *t,
+		log_append_ext_intro(ctx, ext_id, reset_id);
+
+		log_append_buffer(ctx, updates[ext_id].arr.buffer, NULL,
+				  MAIL_TRANSACTION_EXT_REC_UPDATE);
+	}
+}
+
+static void
+log_append_keyword_update(struct log_append_context *ctx,
 			  buffer_t *hdr_buf, enum modify_type modify_type,
 			  const char *keyword, const buffer_t *buffer)
 {
@@ -321,12 +312,11 @@ log_append_keyword_update(struct mail_tr
 	if ((hdr_buf->used % 4) != 0)
 		buffer_append_zero(hdr_buf, 4 - (hdr_buf->used % 4));
 
-	return log_append_buffer(file, buffer, hdr_buf,
-				 MAIL_TRANSACTION_KEYWORD_UPDATE, t->external);
-}
-
-static int log_append_keyword_updates(struct mail_transaction_log_file *file,
-				      struct mail_index_transaction *t)
+	log_append_buffer(ctx, buffer, hdr_buf,


More information about the dovecot-cvs mailing list