[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