]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
automatically fix broken/missing transaction log files on the fly
authorTimo Sirainen <tss@iki.fi>
Sat, 1 May 2004 15:32:24 +0000 (18:32 +0300)
committerTimo Sirainen <tss@iki.fi>
Sat, 1 May 2004 15:32:24 +0000 (18:32 +0300)
--HG--
branch : HEAD

src/lib-index/mail-index-sync.c
src/lib-index/mail-index-view-sync.c
src/lib-index/mail-transaction-log-view.c
src/lib-index/mail-transaction-log.c
src/lib-index/mail-transaction-log.h

index d78336ec51cfd6365ada9c9327fead9bf57a6dc0..fc0543cb270d1fae73203d2c4d338a601258d854 100644 (file)
@@ -399,6 +399,7 @@ int mail_index_sync_have_more(struct mail_index_sync_ctx *ctx)
 
 int mail_index_sync_end(struct mail_index_sync_ctx *ctx)
 {
+       const struct mail_index_header *hdr;
        uint32_t seq;
        uoff_t offset;
        int ret = 0;
@@ -408,12 +409,14 @@ int mail_index_sync_end(struct mail_index_sync_ctx *ctx)
 
        mail_transaction_log_get_head(ctx->index->log, &seq, &offset);
 
-       if (mail_transaction_log_view_set(ctx->view->log_view,
-                                         ctx->index->hdr->log_file_seq,
-                                         ctx->index->hdr->log_file_offset,
-                                         seq, offset,
-                                         MAIL_TRANSACTION_TYPE_MASK) < 0)
-               ret = -1;
+       if (ret == 0) {
+               hdr = ctx->index->hdr;
+               mail_transaction_log_view_unset(ctx->view->log_view);
+               if (mail_transaction_log_view_set(ctx->view->log_view,
+                               hdr->log_file_seq, hdr->log_file_offset,
+                               seq, offset, MAIL_TRANSACTION_TYPE_MASK) < 0)
+                       ret = -1;
+       }
 
        if (ret == 0) {
                mail_index_sync_read_and_sort(ctx, TRUE);
@@ -423,9 +426,8 @@ int mail_index_sync_end(struct mail_index_sync_ctx *ctx)
 
        mail_index_unlock(ctx->index, ctx->lock_id);
        mail_transaction_log_sync_unlock(ctx->index->log);
+       mail_index_view_close(ctx->view);
 
-       if (ctx->view != NULL)
-               mail_index_view_close(ctx->view);
        if (ctx->expunges_buf != NULL)
                buffer_free(ctx->expunges_buf);
        if (ctx->updates_buf != NULL)
index bf72d808a21cd36f984ca8edbb870692b425b42a..633c50580fbfe409558be017530a9f9a5e43165c 100644 (file)
@@ -50,6 +50,7 @@ view_sync_get_expunges(struct mail_index_view *view, buffer_t **expunges_r)
                buffer_append(*expunges_r, &exp->seq1, sizeof(exp->seq1));
                buffer_append(*expunges_r, &exp->seq2, sizeof(exp->seq2));
        }
+        mail_transaction_log_view_unset(view->log_view);
        return 0;
 }
 
@@ -315,6 +316,8 @@ void mail_index_view_sync_end(struct mail_index_view_sync_ctx *ctx)
        mail_index_unmap(view->index, view->map);
        view->map = ctx->sync_map;
 
+        mail_transaction_log_view_unset(view->log_view);
+
        if (ctx->expunges != NULL)
                buffer_free(ctx->expunges);
 
index 7f51ea7d73937946ea79f171b5a83770ce024bec..630b8de7cd71ec3ec0611fa72e8b675ca707e322 100644 (file)
@@ -34,6 +34,7 @@ mail_transaction_log_view_open(struct mail_transaction_log *log)
 
        view = i_new(struct mail_transaction_log_view, 1);
        view->log = log;
+       view->broken = TRUE;
        view->expunges_buf =
                buffer_create_dynamic(default_pool, 512, (size_t)-1);
 
@@ -42,24 +43,9 @@ mail_transaction_log_view_open(struct mail_transaction_log *log)
        return view;
 }
 
-static void
-mail_transaction_log_view_close_files(struct mail_transaction_log_view *view)
-{
-       struct mail_transaction_log_file *file;
-
-       for (file = view->log->tail; file != NULL; file = file->next) {
-               if (file->hdr.file_seq > view->max_file_seq)
-                       break;
-               if (file->hdr.file_seq >= view->min_file_seq)
-                       file->refcount--;
-       }
-
-       mail_transaction_logs_clean(view->log);
-}
-
 void mail_transaction_log_view_close(struct mail_transaction_log_view *view)
 {
-       mail_transaction_log_view_close_files(view);
+       mail_transaction_log_view_unset(view);
        if (view->data_buf != NULL)
                buffer_free(view->data_buf);
        buffer_free(view->expunges_buf);
@@ -79,14 +65,11 @@ mail_transaction_log_view_set(struct mail_transaction_log_view *view,
        uoff_t end_offset;
        int ret;
 
+       i_assert(view->broken);
        i_assert(min_file_seq <= max_file_seq);
        i_assert(min_file_offset >= sizeof(struct mail_transaction_log_header));
        i_assert(max_file_offset >= sizeof(struct mail_transaction_log_header));
 
-       view->broken = TRUE;
-
-        mail_transaction_log_view_close_files(view);
-
        ret = mail_transaction_log_file_find(view->log, min_file_seq, &file);
        if (ret <= 0) {
                if (ret == 0 &&
@@ -161,6 +144,24 @@ mail_transaction_log_view_set(struct mail_transaction_log_view *view,
        return 0;
 }
 
+void mail_transaction_log_view_unset(struct mail_transaction_log_view *view)
+{
+       struct mail_transaction_log_file *file;
+
+       if (view->broken)
+               return;
+
+       view->broken = TRUE;
+       for (file = view->log->tail; file != NULL; file = file->next) {
+               if (file->hdr.file_seq > view->max_file_seq)
+                       break;
+               if (file->hdr.file_seq >= view->min_file_seq)
+                       file->refcount--;
+       }
+
+       mail_transaction_logs_clean(view->log);
+}
+
 void
 mail_transaction_log_view_get_prev_pos(struct mail_transaction_log_view *view,
                                       uint32_t *file_seq_r,
@@ -176,6 +177,9 @@ mail_transaction_log_view_set_corrupted(struct mail_transaction_log_view *view,
 {
        va_list va;
 
+       if (!view->broken)
+               mail_transaction_log_view_unset(view);
+
        view->broken = TRUE;
 
        va_start(va, fmt);
index fdbff0b89c95cb9f6ccf0cfbddebdf4dc0be3ae8..45d9c4ca61954cd5b88efd5e4f3a5e51daafc814 100644 (file)
@@ -419,8 +419,14 @@ mail_transaction_log_file_fd_open(struct mail_transaction_log *log,
                return NULL;
        }
 
-       for (p = &log->tail; *p != NULL; p = &(*p)->next)
-               ;
+       for (p = &log->tail; *p != NULL; p = &(*p)->next) {
+               if ((*p)->hdr.file_seq >= file->hdr.file_seq) {
+                       /* log replaced with file having same sequence as
+                          previous one. shouldn't happen unless previous
+                          log file was corrupted.. */
+                       break;
+               }
+       }
        *p = file;
 
        return file;
@@ -461,6 +467,9 @@ void mail_transaction_logs_clean(struct mail_transaction_log *log)
                        *p = next;
                }
        }
+
+       if (log->tail == NULL)
+               log->head = NULL;
 }
 
 static int mail_transaction_log_rotate(struct mail_transaction_log *log)
@@ -500,6 +509,24 @@ static int mail_transaction_log_rotate(struct mail_transaction_log *log)
        return 0;
 }
 
+static int mail_transaction_log_recreate(struct mail_transaction_log *log)
+{
+       unsigned int lock_id;
+       int ret;
+
+       if (mail_index_lock_shared(log->index, TRUE, &lock_id) < 0)
+               return -1;
+
+       ret = mail_transaction_log_rotate(log);
+       mail_index_unlock(log->index, lock_id);
+
+       if (ret == 0) {
+               if (mail_transaction_log_file_lock(log->head, F_UNLCK) < 0)
+                       return -1;
+       }
+       return ret;
+}
+
 static int mail_transaction_log_refresh(struct mail_transaction_log *log)
 {
         struct mail_transaction_log_file *file;
@@ -511,6 +538,10 @@ static int mail_transaction_log_refresh(struct mail_transaction_log *log)
                           MAIL_TRANSACTION_LOG_PREFIX, NULL);
        if (stat(path, &st) < 0) {
                mail_index_file_set_syscall_error(log->index, path, "stat()");
+               if (errno == ENOENT && log->head->lock_type == F_WRLCK) {
+                       /* lost? */
+                       return mail_transaction_log_recreate(log);
+               }
                return -1;
        }
 
@@ -519,6 +550,10 @@ static int mail_transaction_log_refresh(struct mail_transaction_log *log)
            log->head->st_dev == st.st_dev) {
                /* same file */
                ret = mail_transaction_log_file_read_hdr(log->head, &st);
+               if (ret == 0 && log->head->lock_type == F_WRLCK) {
+                       /* corrupted, recreate */
+                       return mail_transaction_log_recreate(log);
+               }
                return ret <= 0 ? -1 : 0;
        }
 
index aa9de233b2a9f2faae0d2a240241b25bf806bd56..d99d3f1a791d41ff6d10b6dbe155e9603403c55b 100644 (file)
@@ -67,6 +67,8 @@ mail_transaction_log_view_set(struct mail_transaction_log_view *view,
                              uint32_t min_file_seq, uoff_t min_file_offset,
                              uint32_t max_file_seq, uoff_t max_file_offset,
                              enum mail_transaction_type type_mask);
+/* Unset view, freeing all it's used resources. */
+void mail_transaction_log_view_unset(struct mail_transaction_log_view *view);
 
 /* Read next transaction record from current position. The position is updated.
    Returns -1 if error, 0 if we're at end of the view, 1 if ok. */