Mercurial > dovecot > core-2.2
changeset 8930:cb37f2732abc HEAD
dbox: Initial support for expunging messages.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 04 Mar 2009 17:40:46 -0500 |
parents | 9c50e7303513 |
children | 9f7b62b814a8 |
files | src/lib-storage/index/dbox/dbox-file.c src/lib-storage/index/dbox/dbox-map.c src/lib-storage/index/dbox/dbox-map.h src/lib-storage/index/dbox/dbox-sync-file.c src/lib-storage/index/dbox/dbox-sync.c src/lib-storage/index/dbox/dbox-sync.h |
diffstat | 6 files changed, 431 insertions(+), 268 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib-storage/index/dbox/dbox-file.c Wed Mar 04 17:40:24 2009 -0500 +++ b/src/lib-storage/index/dbox/dbox-file.c Wed Mar 04 17:40:46 2009 -0500 @@ -489,8 +489,8 @@ void dbox_file_close(struct dbox_file *file) { - i_assert(file->lock == NULL); - + if (file->lock != NULL) + file_lock_free(&file->lock); if (file->input != NULL) i_stream_unref(&file->input); if (file->output != NULL)
--- a/src/lib-storage/index/dbox/dbox-map.c Wed Mar 04 17:40:24 2009 -0500 +++ b/src/lib-storage/index/dbox/dbox-map.c Wed Mar 04 17:40:46 2009 -0500 @@ -25,6 +25,7 @@ struct mail_index_view *view; uint32_t map_ext_id, ref_ext_id; + ARRAY_TYPE(seq_range) ref0_file_ids; }; struct dbox_map_append { @@ -36,6 +37,10 @@ struct dbox_mailbox *mbox; struct dbox_map *map; + struct mail_index_sync_ctx *sync_ctx; + struct mail_index_view *sync_view; + struct mail_index_transaction *trans; + ARRAY_DEFINE(files, struct dbox_file *); ARRAY_DEFINE(appends, struct dbox_map_append); @@ -71,6 +76,8 @@ *_map = NULL; + if (array_is_created(&map->ref0_file_ids)) + array_free(&map->ref0_file_ids); if (map->view != NULL) mail_index_view_close(&map->view); mail_index_free(&map->index); @@ -108,6 +115,11 @@ struct mail_index_view_sync_ctx *ctx; bool delayed_expunges; + if (mail_index_refresh(map->view->index) < 0) { + mail_storage_set_internal_error(&map->storage->storage); + mail_index_reset_error(map->index); + return -1; + } ctx = mail_index_view_sync_begin(map->view, MAIL_INDEX_VIEW_SYNC_FLAG_FIX_INCONSISTENT); if (mail_index_view_sync_commit(&ctx, &delayed_expunges) < 0) { @@ -144,11 +156,9 @@ return 0; } -int dbox_map_lookup(struct dbox_map *map, uint32_t map_uid, - uint32_t *file_id_r, uoff_t *offset_r) +static int +dbox_map_get_seq(struct dbox_map *map, uint32_t map_uid, uint32_t *seq_r) { - uint32_t seq; - uoff_t size; int ret; if ((ret = dbox_map_open(map, FALSE)) <= 0) { @@ -156,19 +166,141 @@ return ret; } - if (!mail_index_lookup_seq(map->view, map_uid, &seq)) { + if (!mail_index_lookup_seq(map->view, map_uid, seq_r)) { /* not found - try again after a refresh */ if (dbox_map_refresh(map) < 0) return -1; - if (!mail_index_lookup_seq(map->view, map_uid, &seq)) + if (!mail_index_lookup_seq(map->view, map_uid, seq_r)) return 0; } + return 1; +} + +int dbox_map_lookup(struct dbox_map *map, uint32_t map_uid, + uint32_t *file_id_r, uoff_t *offset_r) +{ + uint32_t seq; + uoff_t size; + int ret; + + if ((ret = dbox_map_get_seq(map, map_uid, &seq)) <= 0) + return ret; if (dbox_map_lookup_seq(map, seq, file_id_r, offset_r, &size) < 0) return 0; return 1; } +int dbox_map_get_file_msgs(struct dbox_map *map, uint32_t file_id, + ARRAY_TYPE(dbox_map_file_msg) *recs) +{ + const struct mail_index_header *hdr; + struct dbox_map_file_msg msg; + const struct dbox_mail_index_map_record *rec; + const uint16_t *ref16_p; + unsigned int seq; + const void *data; + bool expunged; + + (void)dbox_map_refresh(map); + hdr = mail_index_get_header(map->view); + + memset(&msg, 0, sizeof(msg)); + for (seq = 1; seq <= hdr->messages_count; seq++) { + mail_index_lookup_uid(map->view, seq, &msg.map_uid); + + mail_index_lookup_ext(map->view, seq, map->map_ext_id, + &data, &expunged); + if (data == NULL) { + // FIXME + break; + } + rec = data; + if (rec->file_id != file_id) + continue; + + msg.offset = rec->offset; + mail_index_lookup_ext(map->view, seq, map->ref_ext_id, + &data, &expunged); + if (data == NULL) { + // FIXME + break; + } + ref16_p = data; + msg.refcount = *ref16_p; + + array_append(recs, &msg, 1); + } + return 0; +} + +const ARRAY_TYPE(seq_range) *dbox_map_get_zero_ref_files(struct dbox_map *map) +{ + const struct mail_index_header *hdr; + const struct dbox_mail_index_map_record *rec; + const uint16_t *ref16_p; + const void *data; + uint32_t seq; + bool expunged; + + (void)dbox_map_refresh(map); + + if (array_is_created(&map->ref0_file_ids)) + array_clear(&map->ref0_file_ids); + else + i_array_init(&map->ref0_file_ids, 64); + hdr = mail_index_get_header(map->view); + for (seq = 1; seq <= hdr->messages_count; seq++) { + mail_index_lookup_ext(map->view, seq, map->ref_ext_id, + &data, &expunged); + if (data != NULL && !expunged) { + ref16_p = data; + if (*ref16_p != 0) + continue; + } + + mail_index_lookup_ext(map->view, seq, map->map_ext_id, + &data, &expunged); + if (data != NULL && !expunged) { + rec = data; + seq_range_array_add(&map->ref0_file_ids, 0, seq); + } + } + return &map->ref0_file_ids; +} + +int dbox_map_update_refcounts(struct dbox_map *map, + const ARRAY_TYPE(seq_range) *map_uids, int diff) +{ + struct mail_index_transaction *trans; + struct seq_range_iter iter; + unsigned int i; + uint32_t map_uid, seq; + int ret = 0; + + trans = mail_index_transaction_begin(map->view, 0); + seq_range_array_iter_init(&iter, map_uids); i = 0; + while (seq_range_array_iter_nth(&iter, i++, &map_uid)) { + if ((ret = dbox_map_get_seq(map, map_uid, &seq)) <= 0) { + if (ret < 0) + break; + } else { + mail_index_atomic_inc_ext(trans, seq, + map->ref_ext_id, diff); + } + } + if (ret < 0) { + mail_index_transaction_rollback(&trans); + return -1; + } else { + uint32_t log_seq; + uoff_t log_offset; + + return mail_index_transaction_commit(&trans, &log_seq, + &log_offset); + } +} + struct dbox_map_append_context * dbox_map_append_begin(struct dbox_mailbox *mbox) { @@ -235,6 +367,12 @@ return TRUE; if (deleted) return TRUE; + if (file->lock != NULL) { + /* already locked, we're possibly in the middle of cleaning + it up in which case we really don't want to write there. */ + dbox_file_unref(&file); + return TRUE; + } if (file->create_time < stamp) file_too_old = TRUE; @@ -475,19 +613,75 @@ return 0; } +static int dbox_map_assign_file_ids(struct dbox_map_append_context *ctx) +{ + struct dbox_file *const *files; + unsigned int i, count; + uint32_t first_file_id, file_id; + int ret; + + /* start the syncing. we'll need it even if there are no file ids to + be assigned. */ + ret = mail_index_sync_begin(ctx->map->index, &ctx->sync_ctx, + &ctx->sync_view, &ctx->trans, 0); + if (ret <= 0) { + i_assert(ret != 0); + mail_storage_set_internal_error(&ctx->map->storage->storage); + mail_index_reset_error(ctx->map->index); + return -1; + } + + if (dbox_map_get_next_file_id(ctx->map, ctx->sync_view, &file_id) < 0) { + mail_index_sync_rollback(&ctx->sync_ctx); + return -1; + } + + /* assign file_ids for newly created multi-files */ + first_file_id = file_id; + files = array_get(&ctx->files, &count); + for (i = 0; i < count; i++) { + if (files[i]->single_mbox != NULL) + continue; + + if (files[i]->output != NULL) { + if (dbox_file_flush_append(files[i]) < 0) { + ret = -1; + break; + } + } + + if (files[i]->file_id == 0) { + if (dbox_file_assign_id(files[i], file_id++) < 0) { + ret = -1; + break; + } + } + } + + if (ret < 0) { + /* FIXME: we have to rollback the changes we made */ + mail_index_sync_rollback(&ctx->sync_ctx); + return -1; + } + + /* update the highest used file_id */ + if (first_file_id != file_id) { + file_id--; + mail_index_update_header_ext(ctx->trans, ctx->map->map_ext_id, + 0, &file_id, sizeof(file_id)); + } + return 0; +} + int dbox_map_append_assign_map_uids(struct dbox_map_append_context *ctx, uint32_t *first_map_uid_r, uint32_t *last_map_uid_r) { - struct dbox_file *const *files; const struct dbox_map_append *appends; - struct mail_index_sync_ctx *sync_ctx; - struct mail_index_view *sync_view; - struct mail_index_transaction *trans; const struct mail_index_header *hdr; struct dbox_mail_index_map_record rec; unsigned int i, count; - uint32_t seq, first_uid, next_uid, first_file_id, file_id; + uint32_t seq, first_uid, next_uid; uint16_t ref16; int ret = 0; @@ -497,55 +691,8 @@ return 0; } - ret = mail_index_sync_begin(ctx->map->index, &sync_ctx, &sync_view, - &trans, 0); - if (ret <= 0) { - i_assert(ret != 0); - mail_storage_set_internal_error(&ctx->map->storage->storage); - mail_index_reset_error(ctx->map->index); - return -1; - } - - if (dbox_map_get_next_file_id(ctx->map, sync_view, &file_id) < 0) { - mail_index_sync_rollback(&sync_ctx); + if (dbox_map_assign_file_ids(ctx) < 0) return -1; - } - - /* assign file_ids for newly created multi-files */ - files = array_get(&ctx->files, &count); - first_file_id = file_id; - for (i = 0; i < count; i++) { - if (files[i]->single_mbox != NULL) - continue; - - if (files[i]->single_mbox == NULL && files[i]->output != NULL) { - if (dbox_file_flush_append(files[i]) < 0) { - ret = -1; - break; - } - } - - if (files[i]->file_id != 0) - continue; - - if (dbox_file_assign_id(files[i], file_id++) < 0) { - ret = -1; - break; - } - } - - if (ret < 0) { - /* FIXME: we have to rollback the changes we made */ - mail_index_sync_rollback(&sync_ctx); - return -1; - } - - /* update the highest used file_id */ - if (first_file_id != file_id) { - file_id--; - mail_index_update_header_ext(trans, ctx->map->map_ext_id, - 0, &file_id, sizeof(file_id)); - } /* append map records to index */ memset(&rec, 0, sizeof(rec)); @@ -559,28 +706,28 @@ 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, + mail_index_append(ctx->trans, 0, &seq); + mail_index_update_ext(ctx->trans, seq, ctx->map->map_ext_id, &rec, NULL); - mail_index_update_ext(trans, seq, ctx->map->ref_ext_id, + mail_index_update_ext(ctx->trans, seq, ctx->map->ref_ext_id, &ref16, NULL); } /* assign map UIDs for appended records */ - hdr = mail_index_get_header(sync_view); + hdr = mail_index_get_header(ctx->sync_view); first_uid = hdr->next_uid; - mail_index_append_assign_uids(trans, first_uid, &next_uid); + mail_index_append_assign_uids(ctx->trans, first_uid, &next_uid); i_assert(next_uid - first_uid == count); if (hdr->uid_validity == 0) { /* we don't really care about uidvalidity, but it can't be 0 */ uint32_t uid_validity = ioloop_time; - mail_index_update_header(trans, + mail_index_update_header(ctx->trans, offsetof(struct mail_index_header, uid_validity), &uid_validity, sizeof(uid_validity), TRUE); } - if (mail_index_sync_commit(&sync_ctx) < 0) { + if (mail_index_sync_commit(&ctx->sync_ctx) < 0) { mail_storage_set_internal_error(&ctx->map->storage->storage); mail_index_reset_error(ctx->map->index); return -1; @@ -591,6 +738,51 @@ return ret; } +int dbox_map_append_move(struct dbox_map_append_context *ctx, + ARRAY_TYPE(seq_range) *map_uids, + ARRAY_TYPE(seq_range) *expunge_map_uids) +{ + const struct dbox_map_append *appends; + struct dbox_mail_index_map_record rec; + struct seq_range_iter iter; + unsigned int i, j, appends_count; + uint32_t uid, seq; + + if (dbox_map_assign_file_ids(ctx) < 0) + return -1; + + memset(&rec, 0, sizeof(rec)); + appends = array_get(&ctx->appends, &appends_count); + + seq_range_array_iter_init(&iter, map_uids); i = j = 0; + while (seq_range_array_iter_nth(&iter, i++, &uid)) { + i_assert(j < appends_count); + rec.file_id = appends[j].file->file_id; + rec.offset = appends[j].offset; + rec.size = appends[j].size; + j++; + + if (!mail_index_lookup_seq(ctx->sync_view, uid, &seq)) + i_unreached(); + mail_index_update_ext(ctx->trans, seq, ctx->map->map_ext_id, + &rec, NULL); + } + + seq_range_array_iter_init(&iter, expunge_map_uids); i = 0; + while (seq_range_array_iter_nth(&iter, i++, &uid)) { + if (!mail_index_lookup_seq(ctx->sync_view, uid, &seq)) + i_unreached(); + mail_index_expunge(ctx->trans, seq); + } + + if (mail_index_sync_commit(&ctx->sync_ctx) < 0) { + mail_storage_set_internal_error(&ctx->map->storage->storage); + mail_index_reset_error(ctx->map->index); + return -1; + } + return 0; +} + int dbox_map_append_assign_uids(struct dbox_map_append_context *ctx, uint32_t first_uid, uint32_t last_uid) {
--- a/src/lib-storage/index/dbox/dbox-map.h Wed Mar 04 17:40:24 2009 -0500 +++ b/src/lib-storage/index/dbox/dbox-map.h Wed Mar 04 17:40:46 2009 -0500 @@ -5,12 +5,29 @@ struct dbox_file; struct dbox_map_append_context; +struct dbox_map_file_msg { + uint32_t map_uid; + uint32_t offset; + uint32_t refcount; +}; +ARRAY_DEFINE_TYPE(dbox_map_file_msg, struct dbox_map_file_msg); + struct dbox_map *dbox_map_init(struct dbox_storage *storage); void dbox_map_deinit(struct dbox_map **map); int dbox_map_lookup(struct dbox_map *map, uint32_t map_uid, uint32_t *file_id_r, uoff_t *offset_r); +/* Get all messages from file */ +int dbox_map_get_file_msgs(struct dbox_map *map, uint32_t file_id, + ARRAY_TYPE(dbox_map_file_msg) *recs); + +int dbox_map_update_refcounts(struct dbox_map *map, + const ARRAY_TYPE(seq_range) *map_uids, int diff); + +/* Return all files containing messages with zero refcount. */ +const ARRAY_TYPE(seq_range) *dbox_map_get_zero_ref_files(struct dbox_map *map); + struct dbox_map_append_context * dbox_map_append_begin(struct dbox_mailbox *mbox); /* Request file for saving a new message with given size (if available). If an @@ -27,6 +44,11 @@ /* Assign UIDs to all created single-files. */ int dbox_map_append_assign_uids(struct dbox_map_append_context *ctx, uint32_t first_uid, uint32_t last_uid); +/* The appends are existing messages that were simply moved to a new file. + map_uids contains the moved messages' map UIDs. */ +int dbox_map_append_move(struct dbox_map_append_context *ctx, + ARRAY_TYPE(seq_range) *map_uids, + ARRAY_TYPE(seq_range) *expunge_map_uids); /* Returns 0 if ok, -1 if error. */ void dbox_map_append_commit(struct dbox_map_append_context **ctx); void dbox_map_append_rollback(struct dbox_map_append_context **ctx);
--- a/src/lib-storage/index/dbox/dbox-sync-file.c Wed Mar 04 17:40:24 2009 -0500 +++ b/src/lib-storage/index/dbox/dbox-sync-file.c Wed Mar 04 17:40:46 2009 -0500 @@ -7,8 +7,15 @@ #include "str.h" #include "dbox-storage.h" #include "dbox-file.h" +#include "dbox-map.h" #include "dbox-sync.h" +struct dbox_mail_move { + struct dbox_file *file; + uint32_t offset; +}; +ARRAY_DEFINE_TYPE(dbox_mail_move, struct dbox_mail_move); + static int dbox_sync_file_unlink(struct dbox_file *file) { const char *path, *primary_path; @@ -36,210 +43,133 @@ } static int -dbox_sync_file_expunge(struct dbox_sync_context *ctx, struct dbox_file *file, - const struct dbox_sync_file_entry *entry) +dbox_sync_file_cleanup(struct dbox_sync_context *ctx, struct dbox_file *file) { -#if 0 //FIXME - const struct seq_range *expunges; - struct dbox_file *out_file = NULL; + struct dbox_file *out_file; struct istream *input; - struct ostream *output; - uint32_t file_id, seq, uid; - uoff_t first_offset, offset, physical_size; - const char *out_path; + struct ostream *output = NULL; + struct dbox_metadata_header meta_hdr; + struct dbox_map_append_context *append_ctx; + ARRAY_TYPE(dbox_map_file_msg) msgs_arr; + const struct dbox_map_file_msg *msgs; + ARRAY_TYPE(seq_range) copied_map_uids, expunged_map_uids; unsigned int i, count; + uoff_t physical_size, msg_size; + const unsigned char *data; + size_t size; + const char *line; bool expunged; int ret; - /* FIXME: lock the file first */ + if ((ret = dbox_file_try_lock(file)) <= 0) + return ret; + + append_ctx = dbox_map_append_begin(ctx->mbox); - expunges = array_get(&entry->expunges, &count); - if (!dbox_file_lookup(ctx->mbox, ctx->sync_view, expunges[0].seq1, - &file_id, &first_offset)) - return 0; - i_assert(file_id == file->file_id); - mail_index_expunge(ctx->trans, expunges[0].seq1); - - offset = first_offset; - for (i = 0;;) { - if ((ret = dbox_file_seek_next(file, &offset, - &physical_size)) <= 0) + t_array_init(&msgs_arr, 128); + if (dbox_map_get_file_msgs(ctx->mbox->storage->map, file->file_id, + &msgs_arr) < 0) { + // FIXME + return -1; + } + msgs = array_get(&msgs_arr, &count); + t_array_init(&copied_map_uids, I_MIN(count, 1)); + t_array_init(&expunged_map_uids, I_MIN(count, 1)); + for (i = 0; i < count; i++) { + if (msgs[i].refcount == 0) { + seq_range_array_add(&expunged_map_uids, 0, + msgs[i].map_uid); + continue; + } + ret = dbox_file_get_mail_stream(file, msgs[i].offset, + &physical_size, + NULL, &expunged); + if (ret <= 0) { + /* FIXME: handle corruption? */ + ret = -1; break; - if (physical_size == 0) { - /* EOF */ - break; - } - - if (i < count) { - mail_index_lookup_seq(ctx->sync_view, uid, &seq); - while (seq > expunges[i].seq2) { - if (++i == count) - break; - } - } - if (seq == 0 || (i < count && seq >= expunges[i].seq1 && - seq <= expunges[i].seq2)) { - /* this message gets expunged */ - if (seq != 0) - mail_index_expunge(ctx->trans, seq); - continue; } /* non-expunged message. write it to output file. */ - if (out_file == NULL) { - out_file = dbox_file_init(ctx->mbox, 0); - ret = dbox_file_get_append_stream(out_file, - physical_size, - &output); - if (ret <= 0) - break; + if (dbox_map_append_next(append_ctx, physical_size, + &out_file, &output) < 0) { + // FIXME + ret = -1; + break; + } + i_assert(file->file_id != out_file->file_id); + + i_stream_seek(file->input, msgs[i].offset); + msg_size = file->msg_header_size + physical_size; + input = i_stream_create_limit(file->input, msg_size); + ret = o_stream_send_istream(output, input); + i_stream_unref(&input); + if (ret != (off_t)(file->msg_header_size + physical_size)) { + // FIXME + ret = -1; + break; } - i_stream_seek(file->input, offset); - input = i_stream_create_limit(file->input, - file->msg_header_size + - physical_size); - ret = o_stream_send_istream(output, input) < 0 ? -1 : 0; - i_stream_unref(&input); - if (ret < 0) + /* copy metadata */ + i_stream_seek(file->input, msgs[i].offset + msg_size); + ret = i_stream_read_data(file->input, &data, &size, + sizeof(meta_hdr)); + if (ret <= 0) { + // FIXME + i_assert(ret != -2); + ret = -1; break; - - /* write metadata */ - (void)dbox_file_metadata_seek_mail_offset(file, offset, - &expunged); - if ((ret = dbox_file_metadata_write_to(file, output)) < 0) + } + memcpy(&meta_hdr, data, sizeof(meta_hdr)); + if (memcmp(meta_hdr.magic_post, DBOX_MAGIC_POST, + sizeof(meta_hdr.magic_post)) != 0) { + // FIXME + ret = -1; break; - - mail_index_update_flags(ctx->trans, seq, MODIFY_REMOVE, - (enum mail_flags)MAIL_INDEX_MAIL_FLAG_DIRTY); - } - - out_path = out_file == NULL ? NULL : - dbox_file_get_path(out_file); - if (ret <= 0) { - if (out_file != NULL) { - if (unlink(out_path) < 0) - i_error("unlink(%s) failed: %m", out_path); - o_stream_unref(&output); } - } else if (out_file != NULL) { - /* FIXME: rename out_file and add to index */ - o_stream_unref(&output); - } - - if (ret <= 0) - ; - else if (first_offset == file->file_header_size) { - /* nothing exists in this file anymore */ - ret = dbox_sync_file_unlink(file); - } else { - if (ftruncate(file->fd, first_offset) < 0) { - dbox_file_set_syscall_error(file, "ftruncate()"); + i_stream_skip(file->input, sizeof(meta_hdr)); + o_stream_send(output, &meta_hdr, sizeof(meta_hdr)); + while ((line = i_stream_read_next_line(file->input)) != NULL) { + if (*line == DBOX_METADATA_OLDV1_SPACE || *line == '\0') { + /* end of metadata */ + break; + } + o_stream_send_str(output, line); + o_stream_send(output, "\n", 1); + } + if (line == NULL) { + // FIXME ret = -1; + break; } + o_stream_send(output, "\n", 1); + dbox_map_append_finish_multi_mail(append_ctx); + seq_range_array_add(&copied_map_uids, 0, msgs[i].map_uid); } - if (out_file != NULL) - dbox_file_unref(&out_file); - return ret; -#endif - return -1; -} - -#if 0 -static int -dbox_sync_file_split(struct dbox_sync_context *ctx, struct dbox_file *in_file, - uoff_t offset, uint32_t seq) -{ - static enum dbox_metadata_key maildir_metadata_keys[] = { - DBOX_METADATA_VIRTUAL_SIZE, - DBOX_METADATA_RECEIVED_TIME, - DBOX_METADATA_SAVE_TIME, - DBOX_METADATA_POP3_UIDL - }; - struct dbox_index_append_context *append_ctx; - struct dbox_file *out_file; - struct istream *input; - struct ostream *output; - struct dbox_message_header dbox_msg_hdr; - struct dbox_mail_index_record rec; - const char *out_path, *value; - uoff_t size, append_offset; - unsigned int i; - int ret; - bool expunged; - - /* FIXME: for now we handle only maildir file conversion */ - i_assert(in_file->maildir_file); - - ret = dbox_file_get_mail_stream(in_file, offset, - &size, &input, &expunged); - if (ret <= 0) - return ret; - if (expunged) { - mail_index_expunge(ctx->trans, seq); - return 1; - } - - append_ctx = dbox_index_append_begin(ctx->mbox->dbox_index); - if (dbox_index_append_next(append_ctx, size, &out_file, &output) < 0 || - dbox_file_metadata_seek(out_file, 0, &expunged) < 0) { - dbox_index_append_rollback(&append_ctx); - i_stream_unref(&input); + if (ret < 0) { + dbox_map_append_rollback(&append_ctx); return -1; } - append_offset = output->offset; - dbox_msg_header_fill(&dbox_msg_hdr, size); - /* set static metadata */ - for (i = 0; i < N_ELEMENTS(maildir_metadata_keys); i++) { - value = dbox_file_metadata_get(in_file, - maildir_metadata_keys[i]); - if (value != NULL) { - dbox_file_metadata_set(out_file, - maildir_metadata_keys[i], value); - } + if (output == NULL) { + /* everything expunged in this file, unlink it */ + dbox_map_append_rollback(&append_ctx); + if (dbox_sync_file_unlink(file) < 0) + return -1; + return 0; } - /* copy the message */ - out_path = dbox_file_get_path(out_file); - o_stream_cork(output); - if (o_stream_send(output, &dbox_msg_hdr, sizeof(dbox_msg_hdr)) < 0 || - o_stream_send_istream(output, input) < 0 || - dbox_file_metadata_write_to(out_file, output) < 0 || - o_stream_flush(output) < 0) { - mail_storage_set_critical(&ctx->mbox->storage->storage, - "write(%s) failed: %m", out_path); - ret = -1; - } else { - dbox_file_finish_append(out_file); - out_file->last_append_uid = uid; - - ret = dbox_index_append_assign_file_ids(append_ctx); + /* assign new file_id + offset to moved messages */ + if (dbox_map_append_move(append_ctx, &copied_map_uids, + &expunged_map_uids) < 0) { + // FIXME + return -1; } - - if (ret < 0) - dbox_index_append_rollback(&append_ctx); - else - ret = dbox_index_append_commit(&append_ctx); - i_stream_unref(&input); - - if (ret == 0) { - /* update message position in index file */ - memset(&rec, 0, sizeof(rec)); - if ((rec.file_id & DBOX_FILE_ID_FLAG_UID) == 0) { - rec.file_id = out_file->file_id; - rec.offset = append_offset; - } - mail_index_update_ext(ctx->trans, seq, ctx->mbox->dbox_ext_id, - &rec, NULL); - - /* when everything is done, unlink the old file */ - ret = dbox_sync_file_unlink(in_file); - } - return ret < 0 ? -1 : 1; + dbox_map_append_commit(&append_ctx); + (void)dbox_sync_file_unlink(file); + return 1; } -#endif static void dbox_sync_file_move_if_needed(struct dbox_file *file, @@ -256,21 +186,21 @@ } static void -dbox_sync_mark_single_file_expunged(struct dbox_sync_context *ctx, - const struct dbox_sync_file_entry *entry) +dbox_sync_mark_expunges(struct dbox_sync_context *ctx, + const ARRAY_TYPE(seq_range) *seqs) { struct mailbox *box = &ctx->mbox->ibox.box; - const struct seq_range *expunges; - unsigned int count; - uint32_t uid; + struct seq_range_iter iter; + unsigned int i; + uint32_t seq, uid; - expunges = array_get(&entry->expunges, &count); - i_assert(count == 1 && expunges[0].seq1 == expunges[0].seq2); - mail_index_expunge(ctx->trans, expunges[0].seq1); - - if (box->v.sync_notify != NULL) { - mail_index_lookup_uid(ctx->sync_view, expunges[0].seq1, &uid); - box->v.sync_notify(box, uid, MAILBOX_SYNC_TYPE_EXPUNGE); + seq_range_array_iter_init(&iter, seqs); i = 0; + while (seq_range_array_iter_nth(&iter, i++, &seq)) { + mail_index_expunge(ctx->trans, seq); + if (box->v.sync_notify != NULL) { + mail_index_lookup_uid(ctx->sync_view, seq, &uid); + box->v.sync_notify(box, uid, MAILBOX_SYNC_TYPE_EXPUNGE); + } } } @@ -284,20 +214,27 @@ file = entry->file_id != 0 ? dbox_file_init_multi(ctx->mbox->storage, entry->file_id) : dbox_file_init_single(ctx->mbox, entry->uid); - if (entry->uid != 0 && array_is_created(&entry->expunges)) { + if (!array_is_created(&entry->expunge_map_uids)) { + /* no expunges - we want to move it */ + dbox_sync_file_move_if_needed(file, entry); + } else if (entry->uid != 0) { /* fast path to expunging the whole file */ if ((ret = dbox_sync_file_unlink(file)) == 0) { /* file was lost, delete it */ - dbox_sync_mark_single_file_expunged(ctx, entry); + dbox_sync_mark_expunges(ctx, &entry->expunge_seqs); ret = 1; } } else { + if (dbox_map_update_refcounts(ctx->mbox->storage->map, + &entry->expunge_map_uids, -1) < 0) + return -1; + + dbox_sync_mark_expunges(ctx, &entry->expunge_seqs); + + /* FIXME: do this cleanup later */ ret = dbox_file_open_or_create(file, &deleted); - if (ret > 0 && !deleted) { - dbox_sync_file_move_if_needed(file, entry); - if (array_is_created(&entry->expunges)) - ret = dbox_sync_file_expunge(ctx, file, entry); - } + if (ret > 0 && !deleted) + ret = dbox_sync_file_cleanup(ctx, file); } dbox_file_unref(&file); return ret;
--- a/src/lib-storage/index/dbox/dbox-sync.c Wed Mar 04 17:40:24 2009 -0500 +++ b/src/lib-storage/index/dbox/dbox-sync.c Wed Mar 04 17:40:46 2009 -0500 @@ -67,11 +67,14 @@ } if (sync_rec->type == MAIL_INDEX_SYNC_TYPE_EXPUNGE) { - if (!array_is_created(&entry->expunges)) { - p_array_init(&entry->expunges, ctx->pool, + if (!array_is_created(&entry->expunge_map_uids)) { + p_array_init(&entry->expunge_map_uids, ctx->pool, + lookup_entry.uid != 0 ? 1 : 3); + p_array_init(&entry->expunge_seqs, ctx->pool, lookup_entry.uid != 0 ? 1 : 3); } - seq_range_array_add(&entry->expunges, 0, seq); + seq_range_array_add(&entry->expunge_seqs, 0, seq); + seq_range_array_add(&entry->expunge_map_uids, 0, map_uid); } else { if ((sync_rec->add_flags & DBOX_INDEX_FLAG_ALT) != 0) entry->move_to_alt = TRUE; @@ -311,3 +314,11 @@ return index_mailbox_sync_init(box, flags, ret < 0); } + +void dbox_sync_cleanup(struct dbox_storage *storage) +{ + const ARRAY_TYPE(seq_range) *ref0_file_ids; + unsigned int i = 0; + + ref0_file_ids = dbox_map_get_zero_ref_files(storage->map); +}
--- a/src/lib-storage/index/dbox/dbox-sync.h Wed Mar 04 17:40:24 2009 -0500 +++ b/src/lib-storage/index/dbox/dbox-sync.h Wed Mar 04 17:40:46 2009 -0500 @@ -8,7 +8,8 @@ unsigned int move_from_alt:1; unsigned int move_to_alt:1; - ARRAY_TYPE(seq_range) expunges; + ARRAY_TYPE(seq_range) expunge_seqs; + ARRAY_TYPE(seq_range) expunge_map_uids; }; struct dbox_sync_context {