diff -r b7d13ee51aa4 src/lib-index/mail-transaction-log-append.c --- a/src/lib-index/mail-transaction-log-append.c Fri Dec 03 04:25:06 2010 +0000 +++ b/src/lib-index/mail-transaction-log-append.c Fri Dec 03 04:39:43 2010 +0000 @@ -32,6 +32,7 @@ buffer_append(ctx->output, data, size); mail_transaction_update_modseq(&hdr, data, &ctx->new_highest_modseq); + ctx->transaction_count++; } static int @@ -60,8 +61,6 @@ static int log_buffer_write(struct mail_transaction_log_append_ctx *ctx) { struct mail_transaction_log_file *file = ctx->log->head; - struct mail_transaction_header *hdr; - uint32_t first_size; if (ctx->output->used == 0) return 0; @@ -77,15 +76,8 @@ } /* size will be written later once everything is in disk */ - hdr = buffer_get_space_unsafe(ctx->output, 0, sizeof(*hdr)); - first_size = hdr->size; - i_assert(first_size != 0); - hdr->size = 0; - - if (pwrite_full(file->fd, ctx->output->data, ctx->output->used, - file->sync_offset) < 0) { + if (write_full(file->fd, ctx->output->data, ctx->output->used) < 0) { /* write failure, fallback to in-memory indexes. */ - hdr->size = first_size; mail_index_file_set_syscall_error(ctx->log->index, file->filepath, "pwrite_full()"); @@ -96,18 +88,6 @@ file->sync_offset + ctx->output->used == file->max_tail_offset); - /* now that the whole transaction has been written, rewrite the first - record's size so the transaction becomes visible */ - hdr->size = first_size; - if (pwrite_full(file->fd, &first_size, sizeof(uint32_t), - file->sync_offset + - offsetof(struct mail_transaction_header, size)) < 0) { - mail_index_file_set_syscall_error(ctx->log->index, - file->filepath, - "pwrite_full()"); - return log_buffer_move_to_memory(ctx); - } - if ((ctx->want_fsync && file->log->index->fsync_mode != FSYNC_MODE_NEVER) || file->log->index->fsync_mode == FSYNC_MODE_ALWAYS) { @@ -177,6 +157,7 @@ mail_transaction_log_append_locked(struct mail_transaction_log_append_ctx *ctx) { struct mail_transaction_log_file *file = ctx->log->head; + struct mail_transaction_boundary *boundary; if (file->sync_offset < file->last_size) { /* there is some garbage at the end of the transaction log @@ -192,6 +173,21 @@ } } + /* don't include log_file_tail_offset update in the transaction */ + boundary = buffer_get_space_unsafe(ctx->output, + sizeof(struct mail_transaction_header), + sizeof(*boundary)); + boundary->size = ctx->output->used; + + if (ctx->transaction_count <= 2) { + /* 0-1 changes. don't bother with the boundary */ + unsigned int boundary_size = + sizeof(struct mail_transaction_header) + + sizeof(*boundary); + + buffer_delete(ctx->output, 0, boundary_size); + } + if (ctx->append_sync_offset) log_append_sync_offset_if_needed(ctx); @@ -205,6 +201,7 @@ struct mail_transaction_log_append_ctx **ctx_r) { struct mail_transaction_log_append_ctx *ctx; + struct mail_transaction_boundary boundary; if (!index->log_sync_locked) { if (mail_transaction_log_lock_head(index->log) < 0) @@ -215,6 +212,10 @@ ctx->output = buffer_create_dynamic(default_pool, 1024); ctx->external = external; + memset(&boundary, 0, sizeof(boundary)); + mail_transaction_log_append_add(ctx, MAIL_TRANSACTION_BOUNDARY, + &boundary, sizeof(boundary)); + *ctx_r = ctx; return 0; } diff -r b7d13ee51aa4 src/lib-index/mail-transaction-log-file.c --- a/src/lib-index/mail-transaction-log-file.c Fri Dec 03 04:25:06 2010 +0000 +++ b/src/lib-index/mail-transaction-log-file.c Fri Dec 03 04:39:43 2010 +0000 @@ -596,6 +596,9 @@ int fd, ret; bool rename_existing; + if (fcntl(new_fd, F_SETFL, O_APPEND) < 0) + return log_file_set_syscall_error(file, "fcntl(O_APPEND)"); + if (file->log->nfs_flush) { /* although we check also mtime and file size below, it's done only to fix broken log files. we don't bother flushing @@ -625,7 +628,7 @@ rename_existing = TRUE; } else { /* recreated. use the file if its header is ok */ - fd = nfs_safe_open(file->filepath, O_RDWR); + fd = nfs_safe_open(file->filepath, O_RDWR | O_APPEND); if (fd == -1) { if (errno != ENOENT) { log_file_set_syscall_error(file, "open()"); @@ -765,7 +768,7 @@ int ret; for (i = 0;; i++) { - file->fd = nfs_safe_open(file->filepath, O_RDWR); + file->fd = nfs_safe_open(file->filepath, O_RDWR | O_APPEND); if (file->fd == -1) { if (errno == ENOENT) return 0; @@ -1280,18 +1283,11 @@ /* There's more data than we could sync at the moment. If the last record's size wasn't valid, we can't know if it will be updated unless we've locked the log. */ - if (trans_size != 0) { - /* pread()s or the above fstat() check for mmaps should - have guaranteed that this doesn't happen */ - mail_transaction_log_file_set_corrupted(file, - "hdr.size too large (%u)", trans_size); - return -1; - } else if (file->locked) { + if (file->locked) { mail_transaction_log_file_set_corrupted(file, "Unexpected garbage at EOF"); return -1; } - /* The size field will be updated soon */ mail_index_flush_read_cache(file->log->index, file->filepath, file->fd, file->locked); diff -r b7d13ee51aa4 src/lib-index/mail-transaction-log.h --- a/src/lib-index/mail-transaction-log.h Fri Dec 03 04:25:06 2010 +0000 +++ b/src/lib-index/mail-transaction-log.h Fri Dec 03 04:39:43 2010 +0000 @@ -167,6 +167,8 @@ buffer_t *output; uint64_t new_highest_modseq; + unsigned int transaction_count; + unsigned int external:1; unsigned int append_sync_offset:1; unsigned int sync_includes_this:1;