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;
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);
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)
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;
}
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);
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);
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);
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 &&
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,
{
va_list va;
+ if (!view->broken)
+ mail_transaction_log_view_unset(view);
+
view->broken = TRUE;
va_start(va, fmt);
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;
*p = next;
}
}
+
+ if (log->tail == NULL)
+ log->head = NULL;
}
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;
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;
}
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;
}
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. */