]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
dbox bugfixes.
authorTimo Sirainen <tss@iki.fi>
Fri, 20 Mar 2009 22:22:59 +0000 (18:22 -0400)
committerTimo Sirainen <tss@iki.fi>
Fri, 20 Mar 2009 22:22:59 +0000 (18:22 -0400)
--HG--
branch : HEAD

src/lib-storage/index/dbox/dbox-file.c
src/lib-storage/index/dbox/dbox-mail.c
src/lib-storage/index/dbox/dbox-map-private.h
src/lib-storage/index/dbox/dbox-map.c
src/lib-storage/index/dbox/dbox-map.h
src/lib-storage/index/dbox/dbox-storage-rebuild.c
src/lib-storage/index/dbox/dbox-storage.c
src/lib-storage/index/dbox/dbox-sync-rebuild.c
src/lib-storage/index/dbox/dbox-sync.c

index dab9049c66f55a3a889d735cb984e6f2817aa4ba..7e5f02e1de9bb17abfc8691b6ba2ee439118aef0 100644 (file)
@@ -612,6 +612,7 @@ dbox_file_seek_next_at_metadata(struct dbox_file *file, uoff_t *offset)
        const char *line;
        int ret;
 
+       i_stream_seek(file->input, *offset);
        if ((ret = dbox_file_metadata_skip_header(file)) <= 0)
                return ret;
 
@@ -636,22 +637,20 @@ int dbox_file_seek_next(struct dbox_file *file, uoff_t *offset_r, bool *last_r)
                /* first mail */
                offset = file->file_header_size;
        } else {
-               offset = file->cur_offset + file->cur_physical_size;
+               offset = file->cur_offset + file->msg_header_size +
+                       file->cur_physical_size;
                if ((ret = dbox_file_seek_next_at_metadata(file, &offset)) <= 0)
                        return ret;
        }
        *offset_r = offset;
-       *last_r = FALSE;
-
-       ret = dbox_file_get_mail_stream(file, offset, &size, NULL, &expunged);
-       if (ret <= 0)
-               return ret;
 
-       if (expunged) {
+       if (file->input != NULL && i_stream_is_eof(file->input)) {
                *last_r = TRUE;
                return 0;
        }
-       return 1;
+       *last_r = FALSE;
+
+       return dbox_file_get_mail_stream(file, offset, &size, NULL, &expunged);
 }
 
 static int
index 984fbae7df27f5ad3a39400762cc8fc0ac16f6d3..252fe2aa791ebc7469613d9320bbaa1d14d50fec 100644 (file)
@@ -69,14 +69,28 @@ static int dbox_mail_open(struct dbox_mail *mail,
                if (map_uid == 0) {
                        mail->open_file =
                                dbox_file_init_single(mbox, _mail->uid);
-               } else {
-                       ret = dbox_map_lookup(mbox->storage->map, map_uid,
-                                             &file_id, &mail->offset);
-                       if (ret <= 0) {
-                               if (ret == 0)
-                                       mail_set_expunged(_mail);
+               } else if ((ret = dbox_map_lookup(mbox->storage->map,
+                                                 map_uid, &file_id,
+                                                 &mail->offset)) <= 0) {
+                       if (ret < 0)
+                               return -1;
+
+                       /* map_uid doesn't exist anymore. either it
+                          got just expunged or the map index is
+                          corrupted. see if the message still exists
+                          in the mailbox index. */
+                       (void)mail_index_refresh(mbox->ibox.index);
+                       if (mail_index_is_expunged(mbox->ibox.view,
+                                                  _mail->seq)) {
+                               mail_set_expunged(_mail);
                                return -1;
                        }
+
+                       dbox_map_set_corrupted(mbox->storage->map,
+                               "Unexpectedly lost map_uid=%u", map_uid);
+                       mbox->storage->sync_rebuild = TRUE;
+                       return -1;
+               } else {
                        mail->open_file =
                                dbox_file_init_multi(mbox->storage, file_id);
                }
index 39cf86433a302657df2f4eb57b302f53930b28d8..f95f3cc0da4a361609fc690146d169f3221d24f1 100644 (file)
@@ -43,6 +43,7 @@ struct dbox_map_append_context {
        unsigned int committed:1;
 };
 
+int dbox_map_open(struct dbox_map *map);
 int dbox_map_refresh(struct dbox_map *map);
 int dbox_map_view_lookup_rec(struct dbox_map *map, struct mail_index_view *view,
                             uint32_t seq, struct dbox_mail_lookup_rec *rec_r);
index 68dd2d1b4215c27f10e777d36c75a929f5cb5382..af7d7a843446617f175f62087f7760d911c343dc 100644 (file)
@@ -58,7 +58,7 @@ void dbox_map_deinit(struct dbox_map **_map)
        i_free(map);
 }
 
-static int dbox_map_open(struct dbox_map *map)
+int dbox_map_open(struct dbox_map *map)
 {
        struct mail_storage *storage = &map->storage->storage;
        enum mail_index_open_flags open_flags;
@@ -265,6 +265,24 @@ dbox_map_transaction_begin(struct dbox_map *map)
        return ctx;
 }
 
+static void
+dbox_map_sync_handle(struct dbox_map *map, struct mail_index_sync_ctx *sync_ctx)
+{
+       struct mail_index_sync_rec sync_rec;
+       uint32_t seq1, seq2;
+       uoff_t offset1, offset2;
+
+       mail_index_sync_get_offsets(sync_ctx, &seq1, &offset1, &seq2, &offset2);
+       if (offset1 != offset2 || seq1 != seq2) {
+               /* something had crashed. need a full resync. */
+               i_warning("dbox %s: Inconsistency in map index",
+                         map->storage->storage_dir);
+               map->storage->sync_rebuild = TRUE;
+       } else {
+               while (mail_index_sync_next(sync_ctx, &sync_rec)) ;
+       }
+}
+
 int dbox_map_transaction_commit(struct dbox_map_transaction_context **_ctx)
 {
        struct dbox_map_transaction_context *ctx = *_ctx;
@@ -272,17 +290,15 @@ int dbox_map_transaction_commit(struct dbox_map_transaction_context **_ctx)
        struct mail_index_sync_ctx *sync_ctx;
        struct mail_index_view *view;
        struct mail_index_transaction *sync_trans, *trans = ctx->trans;
-       uint32_t seq1, seq2;
-       uoff_t offset1, offset2;
        int ret;
 
        *_ctx = NULL;
-       i_free(ctx);
-
        if (!ctx->changed) {
                mail_index_transaction_rollback(&trans);
+               i_free(ctx);
                return 0;
        }
+       i_free(ctx);
 
        /* use syncing to lock the transaction log, so that we always see
           log's head_offset = tail_offset */
@@ -295,14 +311,7 @@ int dbox_map_transaction_commit(struct dbox_map_transaction_context **_ctx)
                mail_index_transaction_rollback(&trans);
                return -1;
        }
-
-       mail_index_sync_get_offsets(sync_ctx, &seq1, &offset1, &seq2, &offset2);
-       if (offset1 != offset2 || seq1 != seq2) {
-               /* something had crashed. need a full resync. */
-               i_warning("dbox %s: Inconsistency in map index",
-                         map->storage->storage_dir);
-               map->storage->sync_rebuild = TRUE;
-       }
+       dbox_map_sync_handle(map, sync_ctx);
 
        if (mail_index_transaction_commit(&trans) < 0 ||
            mail_index_sync_commit(&sync_ctx) < 0) {
@@ -351,37 +360,45 @@ int dbox_map_update_refcounts(struct dbox_map_transaction_context *ctx,
        return 0;
 }
 
-int dbox_map_remove_file_id(struct dbox_map_transaction_context *ctx,
-                           uint32_t file_id)
+int dbox_map_remove_file_id(struct dbox_map *map, uint32_t file_id)
 {
-       struct dbox_map *map = ctx->map;
+       struct dbox_map_transaction_context *map_trans;
        const struct mail_index_header *hdr;
        const struct dbox_mail_index_map_record *rec;
        const void *data;
        bool expunged;
        uint32_t seq;
+       int ret = 0;
 
        /* make sure the map is refreshed, otherwise we might be expunging
           messages that have already been moved to other files. */
        if (dbox_map_refresh(map) < 0)
                return -1;
 
+       /* we need a per-file transaction, otherwise we can't refresh the map */
+       map_trans = dbox_map_transaction_begin(map);
+
        hdr = mail_index_get_header(map->view);
        for (seq = 1; seq <= hdr->messages_count; seq++) {
                mail_index_lookup_ext(map->view, seq, map->map_ext_id,
                                      &data, &expunged);
                if (data == NULL) {
                        dbox_map_set_corrupted(map, "missing map extension");
-                       return -1;
+                       ret = -1;
+                       break;
                }
 
                rec = data;
                if (rec->file_id == file_id) {
-                       ctx->changed = TRUE;
-                       mail_index_expunge(ctx->trans, seq);
+                       map_trans->changed = TRUE;
+                       mail_index_expunge(map_trans->trans, seq);
                }
        }
-       return 0;
+       if (ret < 0)
+               dbox_map_transaction_rollback(&map_trans);
+       else
+               (void)dbox_map_transaction_commit(&map_trans);
+       return ret;
 }
 
 struct dbox_map_append_context *
@@ -709,8 +726,7 @@ 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, seq1, seq2;
-       uoff_t offset1, offset2;
+       uint32_t first_file_id, file_id;
        int ret;
 
        /* start the syncing. we'll need it even if there are no file ids to
@@ -723,15 +739,7 @@ static int dbox_map_assign_file_ids(struct dbox_map_append_context *ctx,
                mail_index_reset_error(ctx->map->index);
                return -1;
        }
-
-       mail_index_sync_get_offsets(ctx->sync_ctx, &seq1, &offset1,
-                                   &seq2, &offset2);
-       if (offset1 != offset2 || seq1 != seq2) {
-               /* something had crashed. need a full resync. */
-               i_warning("dbox %s: Inconsistency in map index",
-                         ctx->map->storage->storage_dir);
-               ctx->map->storage->sync_rebuild = TRUE;
-       }
+       dbox_map_sync_handle(ctx->map, ctx->sync_ctx);
 
        if (dbox_map_get_next_file_id(ctx->map, ctx->sync_view, &file_id) < 0) {
                mail_index_sync_rollback(&ctx->sync_ctx);
index 49af4f26cad3499b4730255f55fe7d05225650c7..0d9369ac1851d8cf1dbcddb4b96860d8e7615c94 100644 (file)
@@ -45,8 +45,7 @@ void dbox_map_transaction_rollback(struct dbox_map_transaction_context **ctx);
 
 int dbox_map_update_refcounts(struct dbox_map_transaction_context *ctx,
                              const ARRAY_TYPE(seq_range) *map_uids, int diff);
-int dbox_map_remove_file_id(struct dbox_map_transaction_context *ctx,
-                           uint32_t file_id);
+int dbox_map_remove_file_id(struct dbox_map *map, uint32_t file_id);
 
 /* Return all files containing messages with zero refcount. */
 const ARRAY_TYPE(seq_range) *dbox_map_get_zero_ref_files(struct dbox_map *map);
index d1efd1ee88c7705cf2b8cb2a6a610698037ec10c..207d8ed589cb41717dbc5a27c742fbabfc06a90e 100644 (file)
@@ -229,7 +229,7 @@ static int rebuild_apply_map(struct dbox_storage_rebuild_context *ctx)
 {
        struct dbox_map *map = ctx->storage->map;
        const struct mail_index_header *hdr;
-       struct dbox_rebuild_msg **msgs, *pos;
+       struct dbox_rebuild_msg **msgs, **pos;
        struct dbox_rebuild_msg search_msg, *search_msgp = &search_msg;
        struct dbox_mail_lookup_rec rec;
        uint32_t seq;
@@ -254,8 +254,8 @@ static int rebuild_apply_map(struct dbox_storage_rebuild_context *ctx)
                        /* map record points to non-existing message. */
                        mail_index_expunge(ctx->trans, seq);
                } else {
-                       pos->map_uid = rec.map_uid;
-                       pos->seen_zero_ref_in_map = rec.refcount == 0;
+                       (*pos)->map_uid = rec.map_uid;
+                       (*pos)->seen_zero_ref_in_map = rec.refcount == 0;
                }
        }
        rebuild_add_missing_map_uids(ctx, hdr->next_uid);
@@ -271,13 +271,14 @@ rebuild_lookup_map_uid(struct dbox_storage_rebuild_context *ctx,
                       uint32_t map_uid)
 {
        struct dbox_rebuild_msg search_msg, *search_msgp = &search_msg;
-       struct dbox_rebuild_msg *const *msgs;
+       struct dbox_rebuild_msg *const *msgs, **pos;
        unsigned int count;
 
        search_msg.map_uid = map_uid;
        msgs = array_get(&ctx->msgs, &count);
-       return bsearch(&search_msgp, msgs, count, sizeof(*msgs),
-                      dbox_rebuild_msg_uid_cmp);
+       pos = bsearch(&search_msgp, msgs, count, sizeof(*msgs),
+                     dbox_rebuild_msg_uid_cmp);
+       return pos == NULL ? NULL : *pos;
 }
 
 static void
@@ -334,7 +335,7 @@ rebuild_mailbox_multi(struct dbox_storage_rebuild_context *ctx,
                        /* everything was ok */
                }
 
-               if (rec != NULL) {
+               if (rec != NULL) T_BEGIN {
                        /* keep this message */
                        rec->refcount++;
 
@@ -344,10 +345,10 @@ rebuild_mailbox_multi(struct dbox_storage_rebuild_context *ctx,
                                                         NULL, new_seq, uid);
 
                        new_dbox_rec.map_uid = rec->map_uid;
-                       mail_index_update_ext(ctx->trans, new_seq,
+                       mail_index_update_ext(trans, new_seq,
                                              mbox->dbox_ext_id,
                                              &new_dbox_rec, NULL);
-               }
+               } T_END;
        }
 }
 
@@ -411,7 +412,10 @@ static int rebuild_mailboxes(struct dbox_storage_rebuild_context *ctx)
        while ((info = mailbox_list_iter_next(iter)) != NULL) {
                if ((info->flags & (MAILBOX_NONEXISTENT |
                                    MAILBOX_NOSELECT)) == 0) {
-                       if (rebuild_mailbox(ctx, info->name) < 0) {
+                       T_BEGIN {
+                               ret = rebuild_mailbox(ctx, info->name);
+                       } T_END;
+                       if (ret < 0) {
                                ret = -1;
                                break;
                        }
@@ -621,6 +625,9 @@ static int dbox_storage_rebuild_scan(struct dbox_storage_rebuild_context *ctx)
        unsigned int dir_len;
        int ret = 0;
 
+       if (dbox_map_open(ctx->storage->map) < 0)
+               return -1;
+
        /* begin by locking the map, so that other processes can't try to
           rebuild at the same time. */
        ret = mail_index_sync_begin(ctx->storage->map->index, &ctx->sync_ctx,
@@ -649,7 +656,7 @@ static int dbox_storage_rebuild_scan(struct dbox_storage_rebuild_context *ctx)
                        str_truncate(path, dir_len);
                        str_append(path, d->d_name);
                        T_BEGIN {
-                               ret = rebuild_add_file(ctx, d->d_name);
+                               ret = rebuild_add_file(ctx, str_c(path));
                        } T_END;
                        if (ret < 0) {
                                ret = -1;
index c92423a1eb5165157e200faa11ecb02b7957b03c..bc017e200126dee7916bba0b17dfbca9dfdd74a4 100644 (file)
@@ -12,6 +12,7 @@
 #include "dbox-map.h"
 #include "dbox-file.h"
 #include "dbox-sync.h"
+#include "dbox-storage-rebuild.h"
 #include "dbox-storage.h"
 
 #include <stdio.h>
@@ -202,6 +203,11 @@ static void dbox_destroy(struct mail_storage *_storage)
 {
        struct dbox_storage *storage = (struct dbox_storage *)_storage;
 
+       if (storage->sync_rebuild) {
+               if (dbox_storage_rebuild(storage) < 0)
+                       return;
+       }
+
        dbox_sync_cleanup(storage);
        dbox_files_free(storage);
        dbox_map_deinit(&storage->map);
index bf3925c638a007872fa78b0d3134975c43f840b8..e39d306eba91b7245fa77dc3e4e18d5faa452740 100644 (file)
@@ -181,7 +181,9 @@ static int dbox_sync_add_file_index(struct dbox_sync_rebuild_context *ctx,
        }
 
        mail_index_append(ctx->trans, file->uid, &seq);
-       dbox_sync_rebuild_index_metadata(ctx, file, seq, file->uid);
+       T_BEGIN {
+               dbox_sync_rebuild_index_metadata(ctx, file, seq, file->uid);
+       } T_END;
        return 0;
 }
 
@@ -406,7 +408,7 @@ dbox_sync_index_rebuild_init(struct dbox_mailbox *mbox,
 #endif
                open_flags |= MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE;
        if (mail_index_open(ctx->backup_index, open_flags,
-                           box->storage->lock_method) < 0)
+                           box->storage->lock_method) <= 0)
                mail_index_free(&ctx->backup_index);
        else
                ctx->backup_view = mail_index_view_open(ctx->backup_index);
@@ -477,6 +479,6 @@ int dbox_sync_index_rebuild(struct dbox_mailbox *mbox)
        mail_index_view_close(&view);
 
        if (ret == 0)
-               ctx->mbox->storage->sync_rebuild = FALSE;
+               mbox->storage->sync_rebuild = FALSE;
        return ret;
 }
index 808669c2787bbdede392ac66c803d89e56fd3afc..3433152eb08ac625a2914f16922e1e58a7ad4d29 100644 (file)
@@ -136,6 +136,7 @@ static int dbox_sync_index(struct dbox_sync_context *ctx)
        hdr = mail_index_get_header(ctx->sync_view);
        if (hdr->uid_validity == 0) {
                /* newly created index file */
+               i_warning("FIXME: newly created");
                return 0;
        }
 
@@ -152,9 +153,7 @@ static int dbox_sync_index(struct dbox_sync_context *ctx)
                                       dbox_sync_file_entry_hash,
                                       dbox_sync_file_entry_cmp);
 
-       for (;;) {
-               if (!mail_index_sync_next(ctx->index_sync_ctx, &sync_rec))
-                       break;
+       while (mail_index_sync_next(ctx->index_sync_ctx, &sync_rec)) {
                if ((ret = dbox_sync_add(ctx, &sync_rec)) <= 0)
                        break;
        }
@@ -171,8 +170,10 @@ static int dbox_sync_index(struct dbox_sync_context *ctx)
                hash_table_iterate_deinit(&iter);
        }
 
-       if (ret == 0)
-               ret = dbox_map_transaction_commit(&ctx->map_trans);
+       if (ret > 0 && ctx->map_trans != NULL) {
+               if (dbox_map_transaction_commit(&ctx->map_trans) < 0)
+                       ret = -1;
+       }
 
        if (box->v.sync_notify != NULL)
                box->v.sync_notify(box, 0, 0);
@@ -196,7 +197,8 @@ static int dbox_refresh_header(struct dbox_mailbox *mbox)
                if (data_size != 0 && data_size != 4) {
                        i_warning("dbox %s: Invalid dbox header size",
                                  mbox->path);
-               }
+               } else
+                       i_warning("FIXME: initial sync");
                return -1;
        }
        hdr = data;
@@ -259,6 +261,7 @@ int dbox_sync_begin(struct dbox_mailbox *mbox, enum dbox_sync_flags flags,
                                return dbox_sync_begin(mbox, flags, ctx_r);
                        }
                        ret = 0;
+                       i_warning("FIXME: poop");
                } else {
                        if ((ret = dbox_sync_index(ctx)) > 0)
                                break;
@@ -274,6 +277,8 @@ int dbox_sync_begin(struct dbox_mailbox *mbox, enum dbox_sync_flags flags,
                                ret = -1;
                        } else {
                                /* do a full resync and try again. */
+                               i_warning("dbox %s: Rebuilding index",
+                                         ctx->mbox->path);
                                ret = dbox_sync_index_rebuild(mbox);
                        }
                }
@@ -343,15 +348,12 @@ dbox_storage_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
 void dbox_sync_cleanup(struct dbox_storage *storage)
 {
        const ARRAY_TYPE(seq_range) *ref0_file_ids;
-       struct dbox_map_transaction_context *map_trans;
        struct dbox_file *file;
        struct seq_range_iter iter;
        unsigned int i = 0;
        uint32_t file_id;
        bool deleted;
 
-       map_trans = dbox_map_transaction_begin(storage->map);
-
        ref0_file_ids = dbox_map_get_zero_ref_files(storage->map);
        seq_range_array_iter_init(&iter, ref0_file_ids); i = 0;
        while (seq_range_array_iter_nth(&iter, i++, &file_id)) T_BEGIN {
@@ -359,9 +361,7 @@ void dbox_sync_cleanup(struct dbox_storage *storage)
                if (dbox_file_open_or_create(file, &deleted) > 0 && !deleted)
                        (void)dbox_sync_file_cleanup(file);
                else
-                       dbox_map_remove_file_id(map_trans, file_id);
+                       dbox_map_remove_file_id(storage->map, file_id);
                dbox_file_unref(&file);
        } T_END;
-
-       (void)dbox_map_transaction_commit(&map_trans);
 }