]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-index: Added support for undeleting a deleted index.
authorTimo Sirainen <tss@iki.fi>
Tue, 9 Feb 2010 02:08:31 +0000 (04:08 +0200)
committerTimo Sirainen <tss@iki.fi>
Tue, 9 Feb 2010 02:08:31 +0000 (04:08 +0200)
--HG--
branch : HEAD

12 files changed:
src/doveadm/doveadm-dump-log.c
src/lib-index/mail-index-sync-update.c
src/lib-index/mail-index-sync.c
src/lib-index/mail-index-transaction-export.c
src/lib-index/mail-index-transaction-private.h
src/lib-index/mail-index-transaction-update.c
src/lib-index/mail-index-transaction.c
src/lib-index/mail-index.c
src/lib-index/mail-index.h
src/lib-index/mail-transaction-log-file.c
src/lib-index/mail-transaction-log-private.h
src/lib-index/mail-transaction-log.h

index 1c483584ddd5dcdce16051b4bb01bfdf6a9fb72d..0e619594434f995d0541b27838d1f5f3ba964aea 100644 (file)
@@ -112,6 +112,9 @@ static const char *log_record_type(unsigned int type)
        case MAIL_TRANSACTION_INDEX_DELETED:
                name = "index-deleted";
                break;
+       case MAIL_TRANSACTION_INDEX_UNDELETED:
+               name = "index-undeleted";
+               break;
        default:
                name = t_strdup_printf("unknown: %x", type);
                break;
@@ -415,6 +418,7 @@ static void log_record_print(const struct mail_transaction_header *hdr,
                break;
        }
        case MAIL_TRANSACTION_INDEX_DELETED:
+       case MAIL_TRANSACTION_INDEX_UNDELETED:
                break;
        default:
                break;
index 6cd4680e1625dc2e96cec74d9fe21f904f488009..8efaef7da9ef86ee40314ff9a530ee7d3d29f609 100644 (file)
@@ -819,11 +819,12 @@ int mail_index_sync_record(struct mail_index_sync_map_ctx *ctx,
                        /* next sync finishes the deletion */
                        ctx->view->index->index_delete_requested = TRUE;
                } else {
-                       /* transaction log syncing should have already
-                          set this */
-                       i_assert(ctx->view->index->index_deleted);
+                       /* transaction log reading handles this */
                }
                break;
+       case MAIL_TRANSACTION_INDEX_UNDELETED:
+               ctx->view->index->index_delete_requested = FALSE;
+               break;
        default:
                mail_index_sync_set_corrupted(ctx,
                        "Unknown transaction record type 0x%x",
index 75a4bac10069fd2a24e55ed27effe413c2ff4165..e6aa104b0ad21b1fb366012081f220bf43106794 100644 (file)
@@ -389,6 +389,13 @@ mail_index_sync_begin_init(struct mail_index *index,
                return 0;
        }
 
+       if (index->index_deleted) {
+               /* index is already deleted. we can't sync. */
+               if (locked)
+                       mail_transaction_log_sync_unlock(index->log);
+               return -1;
+       }
+
        if (!locked) {
                /* it looks like we have something to sync. lock the file and
                   check again. */
@@ -482,11 +489,6 @@ int mail_index_sync_begin_to(struct mail_index *index,
 
        index->syncing = TRUE;
 
-       if (index->index_delete_requested) {
-               /* finish this sync by marking the index deleted */
-               mail_index_set_deleted(ctx->ext_trans);
-       }
-
        *ctx_r = ctx;
        *view_r = ctx->view;
        *trans_r = ctx->ext_trans;
@@ -536,6 +538,8 @@ static bool mail_index_sync_view_have_any(struct mail_index_view *view,
                case MAIL_TRANSACTION_FLAG_UPDATE:
                case MAIL_TRANSACTION_KEYWORD_UPDATE:
                case MAIL_TRANSACTION_KEYWORD_RESET:
+               case MAIL_TRANSACTION_INDEX_DELETED:
+               case MAIL_TRANSACTION_INDEX_UNDELETED:
                        return TRUE;
                default:
                        break;
@@ -770,9 +774,15 @@ int mail_index_sync_commit(struct mail_index_sync_ctx **_ctx)
         struct mail_index_sync_ctx *ctx = *_ctx;
        struct mail_index *index = ctx->index;
        uint32_t next_uid;
-       bool want_rotate;
+       bool want_rotate, index_undeleted;
        int ret = 0;
 
+       index_undeleted = ctx->ext_trans->index_undeleted;
+       if (index->index_delete_requested && !index_undeleted) {
+               /* finish this sync by marking the index deleted */
+               mail_index_set_deleted(ctx->ext_trans);
+       }
+
        mail_index_sync_update_mailbox_offset(ctx);
        if (mail_cache_need_compress(index->cache)) {
                /* if cache compression fails, we don't really care.
@@ -796,6 +806,13 @@ int mail_index_sync_commit(struct mail_index_sync_ctx **_ctx)
                return -1;
        }
 
+       if (index_undeleted) {
+               index->index_deleted = FALSE;
+               index->index_delete_requested = FALSE;
+       }
+       if (index->index_delete_requested)
+               index->index_deleted = TRUE;
+
        /* refresh the mapping with newly committed external transactions
           and the synced expunges. sync using file handler here so that the
           expunge handlers get called. */
index a125e2db790a959180d0c788d007f68c235581ad..b94fd3f12e9be029ecf615dce5de7383c7b57252 100644 (file)
@@ -394,6 +394,7 @@ mail_index_transaction_export_new_uids(struct mail_index_export_context *ctx,
 void mail_index_transaction_export(struct mail_index_transaction *t,
                                   struct mail_transaction_log_append_ctx *append_ctx)
 {
+       static uint8_t null4[4] = { 0, 0, 0, 0 };
        enum mail_index_sync_type change_mask = 0;
        struct mail_index_export_context ctx;
 
@@ -401,6 +402,12 @@ void mail_index_transaction_export(struct mail_index_transaction *t,
        ctx.trans = t;
        ctx.append_ctx = append_ctx;
 
+       if (t->index_undeleted) {
+               i_assert(!t->index_deleted);
+               mail_transaction_log_append_add(ctx.append_ctx,
+                       MAIL_TRANSACTION_INDEX_UNDELETED, &null4, 4);
+       }
+
        /* send all extension introductions and resizes before appends
           to avoid resize overhead as much as possible */
         mail_transaction_log_append_ext_intros(&ctx);
@@ -456,7 +463,7 @@ void mail_index_transaction_export(struct mail_index_transaction *t,
        }
 
        if (t->index_deleted) {
-               static uint8_t null4[4] = { 0, 0, 0, 0 };
+               i_assert(!t->index_undeleted);
                mail_transaction_log_append_add(ctx.append_ctx,
                                                MAIL_TRANSACTION_INDEX_DELETED,
                                                &null4, 4);
index 038627860f82ac857bae2638b21a5d3badccd6b6..eeb85515c49c66e6118d3fc6697dd7d55ff75edd 100644 (file)
@@ -86,6 +86,7 @@ struct mail_index_transaction {
        unsigned int post_hdr_changed:1;
        unsigned int reset:1;
        unsigned int index_deleted:1;
+       unsigned int index_undeleted:1;
        /* non-extension updates. flag updates don't change this because
           they may be added and removed, so be sure to check that the updates
           array is non-empty also. */
@@ -96,7 +97,8 @@ struct mail_index_transaction {
 
 #define MAIL_INDEX_TRANSACTION_HAS_CHANGES(t) \
        ((t)->log_updates || (t)->log_ext_updates || \
-        (array_is_created(&(t)->updates) && array_count(&(t)->updates) > 0))
+        (array_is_created(&(t)->updates) && array_count(&(t)->updates) > 0) || \
+        (t)->index_deleted || (t)->index_undeleted)
 
 extern void (*hook_mail_index_transaction_created)
                (struct mail_index_transaction *t);
index 0abede6273a65decc001a050ffc279faca7a30b6..277866c9a1c80df4f6fafd282c7306e09f09f7dc 100644 (file)
@@ -98,6 +98,7 @@ void mail_index_transaction_reset_v(struct mail_index_transaction *t)
        t->post_hdr_changed = FALSE;
        t->reset = FALSE;
        t->index_deleted = FALSE;
+       t->index_undeleted = FALSE;
        t->log_updates = FALSE;
        t->log_ext_updates = FALSE;
 }
@@ -1172,9 +1173,18 @@ void mail_index_reset(struct mail_index_transaction *t)
 
 void mail_index_set_deleted(struct mail_index_transaction *t)
 {
+       i_assert(!t->index_undeleted);
+
        t->index_deleted = TRUE;
 }
 
+void mail_index_set_undeleted(struct mail_index_transaction *t)
+{
+       i_assert(!t->index_deleted);
+
+       t->index_undeleted = TRUE;
+}
+
 void mail_index_transaction_set_max_modseq(struct mail_index_transaction *t,
                                           uint64_t max_modseq,
                                           ARRAY_TYPE(seq_range) *seqs)
index 64506359b55592c608e5b8bb271b71df891aa490..38f2d58383ce6760728e65e51e3d111f55eb47f7 100644 (file)
@@ -208,20 +208,33 @@ int mail_index_transaction_commit_full(struct mail_index_transaction **_t,
                                       struct mail_index_transaction_commit_result *result_r)
 {
        struct mail_index_transaction *t = *_t;
+       struct mail_index *index = t->view->index;
+       bool index_undeleted = t->index_undeleted;
 
        if (mail_index_view_is_inconsistent(t->view)) {
                mail_index_transaction_rollback(_t);
                return -1;
        }
-       if (t->view->index->index_deleted) {
-               /* no further changes allowed */
-               mail_index_transaction_rollback(_t);
-               return -1;
+       if (!index_undeleted) {
+               if (t->view->index->index_deleted ||
+                   (t->view->index->index_delete_requested &&
+                    !t->view->index->syncing)) {
+                       /* no further changes allowed */
+                       mail_index_transaction_rollback(_t);
+                       return -1;
+               }
        }
 
        *_t = NULL;
        memset(result_r, 0, sizeof(*result_r));
-       return t->v.commit(t, result_r);
+       if (t->v.commit(t, result_r) < 0)
+               return -1;
+
+       if (index_undeleted) {
+               index->index_deleted = FALSE;
+               index->index_delete_requested = FALSE;
+       }
+       return 0;
 }
 
 void mail_index_transaction_rollback(struct mail_index_transaction **_t)
index 2d91da02b54af41ea6a7d6d01ec4c1d2b95620e2..97b6118c825bbd5b390af1cd6bacbeba43b765fe 100644 (file)
@@ -748,7 +748,7 @@ void mail_index_mark_corrupted(struct mail_index *index)
 
 bool mail_index_is_deleted(struct mail_index *index)
 {
-       return index->index_deleted;
+       return index->index_delete_requested || index->index_deleted;
 }
 
 void mail_index_fchown(struct mail_index *index, int fd, const char *path)
index 4e8a9128267cbbf5513fc0784809b36d37334526..f2c857cae37dc70555e4fd4b9159c4db1311d8c4 100644 (file)
@@ -449,6 +449,8 @@ void mail_index_reset(struct mail_index_transaction *t);
 /* Mark index deleted. No further changes will be possible after the
    transaction has been committed. */
 void mail_index_set_deleted(struct mail_index_transaction *t);
+/* Mark a deleted index as undeleted. Afterwards index can be changed again. */
+void mail_index_set_undeleted(struct mail_index_transaction *t);
 /* Returns TRUE if index has been set deleted. This gets set only after
    index has been opened/refreshed and the transaction has been seen. */
 bool mail_index_is_deleted(struct mail_index *index);
index bfabc64d9536bf7962d74f262aae1cab0e458420..32db86889d5ee64fe8481adca4eea319631abd02 100644 (file)
@@ -72,7 +72,6 @@ mail_transaction_log_file_alloc(struct mail_transaction_log *log,
        file->log = log;
        file->filepath = i_strdup(path);
        file->fd = -1;
-       file->index_deleted_offset = (uoff_t)-1;
        return file;
 }
 
@@ -1112,9 +1111,18 @@ log_file_track_sync(struct mail_transaction_log_file *file,
                        return ret < 0 ? -1 : 0;
                break;
        case MAIL_TRANSACTION_INDEX_DELETED:
+               if (file->sync_offset < file->index_undeleted_offset)
+                       break;
                file->log->index->index_deleted = TRUE;
                file->index_deleted_offset = file->sync_offset + trans_size;
                break;
+       case MAIL_TRANSACTION_INDEX_UNDELETED:
+               if (file->sync_offset < file->index_deleted_offset)
+                       break;
+               file->log->index->index_deleted = FALSE;
+               file->log->index->index_delete_requested = FALSE;
+               file->index_undeleted_offset = file->sync_offset + trans_size;
+               break;
        }
 
        if (file->max_tail_offset == file->sync_offset) {
@@ -1139,10 +1147,6 @@ mail_transaction_log_file_sync(struct mail_transaction_log_file *file)
 
        data = buffer_get_data(file->buffer, &size);
        while (file->sync_offset - file->buffer_offset + sizeof(*hdr) <= size) {
-               if (unlikely(file->index_deleted_offset == file->sync_offset)) {
-                       /* ignore everything that comes after _INDEX_DELETED */
-                       break;
-               }
                hdr = CONST_PTR_OFFSET(data, file->sync_offset -
                                       file->buffer_offset);
                trans_size = mail_index_offset_to_uint32(hdr->size);
index 96eac19a5a8d3c451fa86fe7104f46fcfd7733d8..c92c2758ff6a3a10be7d23fa3f3e6a2fa6027b02 100644 (file)
@@ -65,9 +65,9 @@ struct mail_transaction_log_file {
           sync_offset is less than this. */
        uoff_t saved_tail_sync_offset;
 
-       /* if we've seen _INDEX_DELETED transaction in this file, this is the
-          offset. otherwise (uoff_t)-1 */
-       uoff_t index_deleted_offset;
+       /* if we've seen _INDEX_[UN9DELETED transaction in this file,
+          this is the offset. otherwise (uoff_t)-1 */
+       uoff_t index_deleted_offset, index_undeleted_offset;
 
        struct modseq_cache modseq_cache[LOG_FILE_MODSEQ_CACHE_SIZE];
 
index 2e4a3157139d9d01df880874cdba95beb67046a3..686b24cb5343568f183f9471d420f7620012e460 100644 (file)
@@ -43,6 +43,7 @@ enum mail_transaction_type {
        MAIL_TRANSACTION_MODSEQ_UPDATE          = 0x00008000,
        MAIL_TRANSACTION_EXT_HDR_UPDATE32       = 0x00010000,
        MAIL_TRANSACTION_INDEX_DELETED          = 0x00020000,
+       MAIL_TRANSACTION_INDEX_UNDELETED        = 0x00040000,
 
        MAIL_TRANSACTION_TYPE_MASK              = 0x000fffff,