From 8872e5c991430f96138a46e36b7f3c2c40d8e5c2 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Tue, 9 Feb 2010 04:08:31 +0200 Subject: [PATCH] lib-index: Added support for undeleting a deleted index. --HG-- branch : HEAD --- src/doveadm/doveadm-dump-log.c | 4 +++ src/lib-index/mail-index-sync-update.c | 7 +++-- src/lib-index/mail-index-sync.c | 29 +++++++++++++++---- src/lib-index/mail-index-transaction-export.c | 9 +++++- .../mail-index-transaction-private.h | 4 ++- src/lib-index/mail-index-transaction-update.c | 10 +++++++ src/lib-index/mail-index-transaction.c | 23 +++++++++++---- src/lib-index/mail-index.c | 2 +- src/lib-index/mail-index.h | 2 ++ src/lib-index/mail-transaction-log-file.c | 14 +++++---- src/lib-index/mail-transaction-log-private.h | 6 ++-- src/lib-index/mail-transaction-log.h | 1 + 12 files changed, 86 insertions(+), 25 deletions(-) diff --git a/src/doveadm/doveadm-dump-log.c b/src/doveadm/doveadm-dump-log.c index 1c483584dd..0e61959443 100644 --- a/src/doveadm/doveadm-dump-log.c +++ b/src/doveadm/doveadm-dump-log.c @@ -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; diff --git a/src/lib-index/mail-index-sync-update.c b/src/lib-index/mail-index-sync-update.c index 6cd4680e16..8efaef7da9 100644 --- a/src/lib-index/mail-index-sync-update.c +++ b/src/lib-index/mail-index-sync-update.c @@ -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", diff --git a/src/lib-index/mail-index-sync.c b/src/lib-index/mail-index-sync.c index 75a4bac100..e6aa104b0a 100644 --- a/src/lib-index/mail-index-sync.c +++ b/src/lib-index/mail-index-sync.c @@ -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. */ diff --git a/src/lib-index/mail-index-transaction-export.c b/src/lib-index/mail-index-transaction-export.c index a125e2db79..b94fd3f12e 100644 --- a/src/lib-index/mail-index-transaction-export.c +++ b/src/lib-index/mail-index-transaction-export.c @@ -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); diff --git a/src/lib-index/mail-index-transaction-private.h b/src/lib-index/mail-index-transaction-private.h index 038627860f..eeb85515c4 100644 --- a/src/lib-index/mail-index-transaction-private.h +++ b/src/lib-index/mail-index-transaction-private.h @@ -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); diff --git a/src/lib-index/mail-index-transaction-update.c b/src/lib-index/mail-index-transaction-update.c index 0abede6273..277866c9a1 100644 --- a/src/lib-index/mail-index-transaction-update.c +++ b/src/lib-index/mail-index-transaction-update.c @@ -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) diff --git a/src/lib-index/mail-index-transaction.c b/src/lib-index/mail-index-transaction.c index 64506359b5..38f2d58383 100644 --- a/src/lib-index/mail-index-transaction.c +++ b/src/lib-index/mail-index-transaction.c @@ -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) diff --git a/src/lib-index/mail-index.c b/src/lib-index/mail-index.c index 2d91da02b5..97b6118c82 100644 --- a/src/lib-index/mail-index.c +++ b/src/lib-index/mail-index.c @@ -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) diff --git a/src/lib-index/mail-index.h b/src/lib-index/mail-index.h index 4e8a912826..f2c857cae3 100644 --- a/src/lib-index/mail-index.h +++ b/src/lib-index/mail-index.h @@ -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); diff --git a/src/lib-index/mail-transaction-log-file.c b/src/lib-index/mail-transaction-log-file.c index bfabc64d95..32db86889d 100644 --- a/src/lib-index/mail-transaction-log-file.c +++ b/src/lib-index/mail-transaction-log-file.c @@ -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); diff --git a/src/lib-index/mail-transaction-log-private.h b/src/lib-index/mail-transaction-log-private.h index 96eac19a5a..c92c2758ff 100644 --- a/src/lib-index/mail-transaction-log-private.h +++ b/src/lib-index/mail-transaction-log-private.h @@ -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]; diff --git a/src/lib-index/mail-transaction-log.h b/src/lib-index/mail-transaction-log.h index 2e4a315713..686b24cb53 100644 --- a/src/lib-index/mail-transaction-log.h +++ b/src/lib-index/mail-transaction-log.h @@ -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, -- 2.47.3