Mercurial > dovecot > core-2.2
changeset 8926:be17526a165d HEAD
dbox: Store message sizes to map index and use them. Some other save optimizations.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 25 Feb 2009 12:23:30 -0500 |
parents | a1d920a81adc |
children | a48605408d18 |
files | src/lib-storage/index/dbox/dbox-file.c src/lib-storage/index/dbox/dbox-file.h src/lib-storage/index/dbox/dbox-map.c src/lib-storage/index/dbox/dbox-map.h src/lib-storage/index/dbox/dbox-save.c |
diffstat | 5 files changed, 92 insertions(+), 47 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-storage/index/dbox/dbox-file.c Wed Feb 25 12:22:33 2009 -0500 +++ b/src/lib-storage/index/dbox/dbox-file.c Wed Feb 25 12:23:30 2009 -0500 @@ -658,32 +658,45 @@ } static int -dbox_file_seek_append_pos(struct dbox_file *file, uoff_t last_msg_offset) +dbox_file_seek_append_pos(struct dbox_file *file, + uoff_t last_msg_offset, uoff_t last_msg_size) { uoff_t offset, size; + struct stat st; bool last; int ret; - if ((ret = dbox_file_read_header(file)) <= 0) - return ret; - if (file->file_version != DBOX_VERSION || file->msg_header_size != sizeof(struct dbox_message_header)) { /* created by an incompatible version, can't append */ return 0; } + if (last_msg_size > 0) { + /* if last_msg_offset + last_msg_size points to EOF, + we can safely use it without reading the last message. */ + if (fstat(file->fd, &st) < 0) { + dbox_file_set_syscall_error(file, "fstat()"); + return -1; + } + } else { + st.st_size = -1; + } offset = last_msg_offset; - ret = dbox_file_seek_next(file, &offset, &size, &last); - if (ret <= 0) - return ret; - if (!last) { - /* not end of file? previous write probably crashed. */ - if (ftruncate(file->fd, offset) < 0) { - dbox_file_set_syscall_error(file, "ftruncate()"); - return -1; + if (st.st_size == (off_t)(last_msg_offset + last_msg_size)) { + offset += last_msg_size; + } else { + ret = dbox_file_seek_next(file, &offset, &size, &last); + if (ret <= 0) + return ret; + if (!last) { + /* not end of file? previous write probably crashed. */ + if (ftruncate(file->fd, offset) < 0) { + dbox_file_set_syscall_error(file, "ftruncate()"); + return -1; + } + i_stream_sync(file->input); } - i_stream_sync(file->input); } file->output = o_stream_create_fd_file(file->fd, 0, FALSE); @@ -692,7 +705,7 @@ } int dbox_file_get_append_stream(struct dbox_file *file, uoff_t last_msg_offset, - struct ostream **stream_r) + uoff_t last_msg_size, struct ostream **stream_r) { bool deleted; int ret; @@ -711,7 +724,8 @@ if (file->output == NULL) { i_assert(file->lock != NULL || last_msg_offset == 0); - ret = dbox_file_seek_append_pos(file, last_msg_offset); + ret = dbox_file_seek_append_pos(file, last_msg_offset, + last_msg_size); if (ret <= 0) return ret; }
--- a/src/lib-storage/index/dbox/dbox-file.h Wed Feb 25 12:22:33 2009 -0500 +++ b/src/lib-storage/index/dbox/dbox-file.h Wed Feb 25 12:23:30 2009 -0500 @@ -158,6 +158,7 @@ 1 if ok, 0 if file can't be appended to (old file version or corruption) or -1 if error. */ int dbox_file_get_append_stream(struct dbox_file *file, uoff_t last_msg_offset, + uoff_t last_msg_size, struct ostream **stream_r); /* Returns the next offset for append a message. dbox_file_get_append_stream() must have been called for this file already at least once. */
--- a/src/lib-storage/index/dbox/dbox-map.c Wed Feb 25 12:22:33 2009 -0500 +++ b/src/lib-storage/index/dbox/dbox-map.c Wed Feb 25 12:23:30 2009 -0500 @@ -16,6 +16,7 @@ struct dbox_mail_index_map_record { uint32_t file_id; uint32_t offset; + uint32_t size; }; struct dbox_map { @@ -28,7 +29,7 @@ struct dbox_map_append { struct dbox_file *file; - uoff_t offset; + uoff_t offset, size; }; struct dbox_map_append_context { @@ -118,7 +119,8 @@ } static int dbox_map_lookup_seq(struct dbox_map *map, uint32_t seq, - uint32_t *file_id_r, uoff_t *offset_r) + uint32_t *file_id_r, uoff_t *offset_r, + uoff_t *size_r) { const struct dbox_mail_index_map_record *rec; const void *data; @@ -138,6 +140,7 @@ *file_id_r = rec->file_id; *offset_r = rec->offset; + *size_r = rec->size; return 0; } @@ -145,6 +148,7 @@ uint32_t *file_id_r, uoff_t *offset_r) { uint32_t seq; + uoff_t size; int ret; if ((ret = dbox_map_open(map, FALSE)) <= 0) { @@ -160,7 +164,7 @@ return 0; } - if (dbox_map_lookup_seq(map, seq, file_id_r, offset_r) < 0) + if (dbox_map_lookup_seq(map, seq, file_id_r, offset_r, &size) < 0) return 0; return 1; } @@ -209,35 +213,36 @@ static bool dbox_map_file_try_append(struct dbox_map_append_context *ctx, - uint32_t file_id, time_t stamp, - uoff_t mail_size, uoff_t last_msg_offset, + uint32_t file_id, time_t stamp, uoff_t mail_size, + uoff_t last_msg_offset, uoff_t last_msg_size, struct dbox_file **file_r, struct ostream **output_r, bool *retry_later_r) { struct dbox_map *map = ctx->map; + struct dbox_storage *storage = map->storage; const struct mail_index_header *hdr; struct dbox_file *file; struct stat st; uint32_t seq, tmp_file_id; - uoff_t tmp_offset; + uoff_t tmp_offset, tmp_size; bool deleted, file_too_old = FALSE; int ret; *file_r = NULL; *retry_later_r = FALSE; - file = dbox_file_init_multi(map->storage, file_id); + file = dbox_file_init_multi(storage, file_id); if (dbox_file_open_or_create(file, &deleted) <= 0) return TRUE; if (deleted) return TRUE; if (fstat(file->fd, &st) < 0) { - mail_storage_set_critical(&map->storage->storage, + mail_storage_set_critical(&storage->storage, "fstat(%s) failed: %m", file->current_path); - } else if (I_MIN(st.st_mtime, st.st_ctime) < stamp) + } else if (file->create_time < stamp) file_too_old = TRUE; - else if (st.st_size + mail_size > map->storage->rotate_size) { + else if (st.st_size + mail_size > storage->rotate_size) { /* file too large */ } else if ((ret = dbox_file_try_lock(file)) <= 0) { /* locking failed */ @@ -248,18 +253,20 @@ hdr = mail_index_get_header(map->view); seq = ctx->orig_msg_count + 1; for (; seq <= hdr->messages_count; seq++) { - if (dbox_map_lookup_seq(map, seq, - &tmp_file_id, &tmp_offset) < 0) + if (dbox_map_lookup_seq(map, seq, &tmp_file_id, + &tmp_offset, &tmp_size) < 0) break; if (tmp_file_id == file->file_id) { i_assert(last_msg_offset < tmp_offset); last_msg_offset = tmp_offset; + last_msg_size = tmp_size; } } if (seq > hdr->messages_count && + last_msg_offset + last_msg_size > storage->rotate_size && dbox_file_get_append_stream(file, last_msg_offset, - output_r) > 0) { + last_msg_size, output_r) > 0) { /* success */ *file_r = file; return TRUE; @@ -298,7 +305,7 @@ const struct mail_index_header *hdr; unsigned int i, count, backwards_lookup_count; uint32_t seq, file_id, min_seen_file_id; - uoff_t offset, append_offset; + uoff_t offset, append_offset, size; time_t stamp; bool retry_later, updated_retry_seq_min; @@ -310,9 +317,14 @@ /* first try to use files already used in this append */ files = array_get(&ctx->files, &count); for (i = count; i > ctx->files_nonappendable_count; i--) { + if (files[i-1]->output == NULL) { + /* we already decided we can't append to this */ + continue; + } + append_offset = dbox_file_get_next_append_offset(files[i-1]); if (append_offset + mail_size <= map->storage->rotate_size && - dbox_file_get_append_stream(files[i-1], append_offset, + dbox_file_get_append_stream(files[i-1], 0, 0, output_r) > 0) { *file_r = files[i-1]; *existing_r = TRUE; @@ -343,16 +355,20 @@ seq = ctx->retry_seq_min + 1; continue; } - if (dbox_map_lookup_seq(map, seq, &file_id, &offset) < 0) + if (dbox_map_lookup_seq(map, seq, &file_id, &offset, &size) < 0) return -1; if (file_id >= min_seen_file_id) continue; min_seen_file_id = file_id; - /* first lookup: this doesn't really tell us if we're going - to exceed the rotate size, it just potentially reduces - how many files we have to open. */ - if (offset + mail_size >= map->storage->rotate_size) + if (++backwards_lookup_count > MAX_BACKWARDS_LOOKUPS) { + /* we've wasted enough time here */ + break; + } + + /* first lookup: this should be enough usually, but we can't + be sure until after locking */ + if (offset + size + mail_size >= map->storage->rotate_size) continue; if (dbox_map_is_appending(ctx, file_id)) { @@ -360,14 +376,9 @@ continue; } - if (++backwards_lookup_count > MAX_BACKWARDS_LOOKUPS) { - /* we've wasted enough time here */ - break; - } - - if (!dbox_map_file_try_append(ctx, file_id, stamp, - mail_size, offset, - file_r, output_r, &retry_later)) { + if (!dbox_map_file_try_append(ctx, file_id, stamp, mail_size, + offset, size, file_r, output_r, + &retry_later)) { /* file is too old. the rest of the files are too. */ break; } @@ -410,7 +421,7 @@ file = ctx->map->storage->rotate_size == 0 ? dbox_file_init_single(ctx->mbox, 0) : dbox_file_init_multi(ctx->map->storage, 0); - ret = dbox_file_get_append_stream(file, 0, output_r); + ret = dbox_file_get_append_stream(file, 0, 0, output_r); if (ret <= 0) { i_assert(ret < 0); (void)unlink(file->current_path); @@ -423,6 +434,7 @@ append = array_append_space(&ctx->appends); append->file = file; append->offset = (*output_r)->offset; + append->size = (uint32_t)-1; } if (!existing) { i_assert(file->output != NULL); @@ -432,6 +444,17 @@ return 0; } +void dbox_map_append_finish_mail(struct dbox_map_append_context *ctx) +{ + struct dbox_map_append *appends; + unsigned int count; + + appends = array_get_modifiable(&ctx->appends, &count); + i_assert(count > 0 && appends[count-1].size == (uint32_t)-1); + appends[count-1].size = appends[count-1].file->output->offset - + appends[count-1].offset; +} + static int dbox_map_get_next_file_id(struct dbox_map *map, struct mail_index_view *view, uint32_t *file_id_r) @@ -534,8 +557,12 @@ ref16 = 1; appends = array_get(&ctx->appends, &count); for (i = 0; i < count; i++) { + i_assert(appends[i].offset <= (uint32_t)-1); + i_assert(appends[i].size <= (uint32_t)-1); + rec.file_id = appends[i].file->file_id; rec.offset = appends[i].offset; + rec.size = appends[i].size; mail_index_append(trans, 0, &seq); mail_index_update_ext(trans, seq, ctx->map->map_ext_id,
--- a/src/lib-storage/index/dbox/dbox-map.h Wed Feb 25 12:22:33 2009 -0500 +++ b/src/lib-storage/index/dbox/dbox-map.h Wed Feb 25 12:23:30 2009 -0500 @@ -13,11 +13,13 @@ struct dbox_map_append_context * dbox_map_append_begin(struct dbox_mailbox *mbox); -/* Request file for saving a new message with given size. If an existing file - can be used, the record is locked and updated in index. Returns 0 if ok, - -1 if error. */ +/* Request file for saving a new message with given size (if available). If an + existing file can be used, the record is locked and updated in index. + Returns 0 if ok, -1 if error. */ int dbox_map_append_next(struct dbox_map_append_context *ctx, uoff_t mail_size, struct dbox_file **file_r, struct ostream **output_r); +/* Finished saving the last mail. Saves the message size. */ +void dbox_map_append_finish_mail(struct dbox_map_append_context *ctx); /* Assign map UIDs to all appended msgs to multi-files. */ int dbox_map_append_assign_map_uids(struct dbox_map_append_context *ctx, uint32_t *first_map_uid_r,
--- a/src/lib-storage/index/dbox/dbox-save.c Wed Feb 25 12:22:33 2009 -0500 +++ b/src/lib-storage/index/dbox/dbox-save.c Wed Feb 25 12:23:30 2009 -0500 @@ -272,6 +272,7 @@ return -1; } + dbox_map_append_finish_mail(ctx->append_ctx); if (save_mail->file->single_mbox != NULL) { dbox_file_close(save_mail->file); ctx->single_count++;