From: Timo Sirainen Date: Sat, 1 May 2004 15:32:24 +0000 (+0300) Subject: automatically fix broken/missing transaction log files on the fly X-Git-Tag: 1.1.alpha1~4165 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7888a9d2008eab9985096c46e1da9ee985c22a2a;p=thirdparty%2Fdovecot%2Fcore.git automatically fix broken/missing transaction log files on the fly --HG-- branch : HEAD --- diff --git a/src/lib-index/mail-index-sync.c b/src/lib-index/mail-index-sync.c index d78336ec51..fc0543cb27 100644 --- a/src/lib-index/mail-index-sync.c +++ b/src/lib-index/mail-index-sync.c @@ -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) diff --git a/src/lib-index/mail-index-view-sync.c b/src/lib-index/mail-index-view-sync.c index bf72d808a2..633c50580f 100644 --- a/src/lib-index/mail-index-view-sync.c +++ b/src/lib-index/mail-index-view-sync.c @@ -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); diff --git a/src/lib-index/mail-transaction-log-view.c b/src/lib-index/mail-transaction-log-view.c index 7f51ea7d73..630b8de7cd 100644 --- a/src/lib-index/mail-transaction-log-view.c +++ b/src/lib-index/mail-transaction-log-view.c @@ -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); diff --git a/src/lib-index/mail-transaction-log.c b/src/lib-index/mail-transaction-log.c index fdbff0b89c..45d9c4ca61 100644 --- a/src/lib-index/mail-transaction-log.c +++ b/src/lib-index/mail-transaction-log.c @@ -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; } diff --git a/src/lib-index/mail-transaction-log.h b/src/lib-index/mail-transaction-log.h index aa9de233b2..d99d3f1a79 100644 --- a/src/lib-index/mail-transaction-log.h +++ b/src/lib-index/mail-transaction-log.h @@ -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. */