# HG changeset patch # User Timo Sirainen # Date 1265505932 -7200 # Node ID fc0ac73f0b36bd49b73da9e41134d2dc65c5b4d1 # Parent 302a4f807276af6a1414af935140e979506417be Added support for marking mailbox index deleted. Don't allow any changes after that. This is going to help with race conditions when deleting mailboxes. diff -r 302a4f807276 -r fc0ac73f0b36 src/doveadm/doveadm-dump-log.c --- a/src/doveadm/doveadm-dump-log.c Sun Feb 07 01:55:06 2010 +0200 +++ b/src/doveadm/doveadm-dump-log.c Sun Feb 07 03:25:32 2010 +0200 @@ -109,6 +109,9 @@ case MAIL_TRANSACTION_MODSEQ_UPDATE: name = "modseq-update"; break; + case MAIL_TRANSACTION_INDEX_DELETED: + name = "index-deleted"; + break; default: name = t_strdup_printf("unknown: %x", type); break; @@ -411,6 +414,8 @@ } break; } + case MAIL_TRANSACTION_INDEX_DELETED: + break; default: break; } diff -r 302a4f807276 -r fc0ac73f0b36 src/lib-index/mail-index-private.h --- a/src/lib-index/mail-index-private.h Sun Feb 07 01:55:06 2010 +0200 +++ b/src/lib-index/mail-index-private.h Sun Feb 07 03:25:32 2010 +0200 @@ -226,6 +226,7 @@ unsigned int index_lock_timeout:1; unsigned int opened:1; + unsigned int index_deleted:1; /* no changes allowed anymore */ unsigned int log_locked:1; unsigned int readonly:1; unsigned int mapping:1; diff -r 302a4f807276 -r fc0ac73f0b36 src/lib-index/mail-index-sync-update.c --- a/src/lib-index/mail-index-sync-update.c Sun Feb 07 01:55:06 2010 +0200 +++ b/src/lib-index/mail-index-sync-update.c Sun Feb 07 03:25:32 2010 +0200 @@ -814,6 +814,12 @@ ret = sync_modseq_update(ctx, rec, hdr->size); break; } + case MAIL_TRANSACTION_INDEX_DELETED: + if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) + break; + /* transaction log syncing should have already set this */ + i_assert(ctx->view->index->index_deleted); + break; default: mail_index_sync_set_corrupted(ctx, "Unknown transaction record type 0x%x", diff -r 302a4f807276 -r fc0ac73f0b36 src/lib-index/mail-index-transaction-export.c --- a/src/lib-index/mail-index-transaction-export.c Sun Feb 07 01:55:06 2010 +0200 +++ b/src/lib-index/mail-index-transaction-export.c Sun Feb 07 03:25:32 2010 +0200 @@ -455,6 +455,13 @@ MAIL_TRANSACTION_HEADER_UPDATE); } + if (t->index_deleted) { + static uint8_t null4[4] = { 0, 0, 0, 0 }; + mail_transaction_log_append_add(ctx.append_ctx, + MAIL_TRANSACTION_INDEX_DELETED, + &null4, 4); + } + /* Update the tail offsets only when committing the sync transaction. Other transactions may not know the latest tail offset and might end up shrinking it. (Alternatively the shrinking tail offsets could diff -r 302a4f807276 -r fc0ac73f0b36 src/lib-index/mail-index-transaction-private.h --- a/src/lib-index/mail-index-transaction-private.h Sun Feb 07 01:55:06 2010 +0200 +++ b/src/lib-index/mail-index-transaction-private.h Sun Feb 07 03:25:32 2010 +0200 @@ -85,6 +85,7 @@ unsigned int pre_hdr_changed:1; unsigned int post_hdr_changed:1; unsigned int reset:1; + unsigned int index_deleted: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. */ diff -r 302a4f807276 -r fc0ac73f0b36 src/lib-index/mail-index-transaction-update.c --- a/src/lib-index/mail-index-transaction-update.c Sun Feb 07 01:55:06 2010 +0200 +++ b/src/lib-index/mail-index-transaction-update.c Sun Feb 07 03:25:32 2010 +0200 @@ -97,6 +97,7 @@ t->pre_hdr_changed = FALSE; t->post_hdr_changed = FALSE; t->reset = FALSE; + t->index_deleted = FALSE; t->log_updates = FALSE; t->log_ext_updates = FALSE; } @@ -1169,6 +1170,13 @@ t->reset = TRUE; } +void mail_index_set_deleted(struct mail_index_transaction *t) +{ + i_assert((t->flags & MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL) != 0); + + t->index_deleted = TRUE; +} + void mail_index_transaction_set_max_modseq(struct mail_index_transaction *t, uint64_t max_modseq, ARRAY_TYPE(seq_range) *seqs) diff -r 302a4f807276 -r fc0ac73f0b36 src/lib-index/mail-index-transaction.c --- a/src/lib-index/mail-index-transaction.c Sun Feb 07 01:55:06 2010 +0200 +++ b/src/lib-index/mail-index-transaction.c Sun Feb 07 03:25:32 2010 +0200 @@ -213,6 +213,11 @@ mail_index_transaction_rollback(_t); return -1; } + if (t->view->index->index_deleted) { + /* no further changes allowed */ + mail_index_transaction_rollback(_t); + return -1; + } *_t = NULL; memset(result_r, 0, sizeof(*result_r)); diff -r 302a4f807276 -r fc0ac73f0b36 src/lib-index/mail-index.c --- a/src/lib-index/mail-index.c Sun Feb 07 01:55:06 2010 +0200 +++ b/src/lib-index/mail-index.c Sun Feb 07 03:25:32 2010 +0200 @@ -744,6 +744,11 @@ } } +bool mail_index_is_deleted(struct mail_index *index) +{ + return index->index_deleted; +} + void mail_index_fchown(struct mail_index *index, int fd, const char *path) { mode_t mode; diff -r 302a4f807276 -r fc0ac73f0b36 src/lib-index/mail-index.h --- a/src/lib-index/mail-index.h Sun Feb 07 01:55:06 2010 +0200 +++ b/src/lib-index/mail-index.h Sun Feb 07 03:25:32 2010 +0200 @@ -446,6 +446,12 @@ /* Reset the index before committing this transaction. This is usually done only when UIDVALIDITY changes. */ 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); +/* 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); /* Lookup a keyword, returns TRUE if found, FALSE if not. */ bool mail_index_keyword_lookup(struct mail_index *index, diff -r 302a4f807276 -r fc0ac73f0b36 src/lib-index/mail-transaction-log-file.c --- a/src/lib-index/mail-transaction-log-file.c Sun Feb 07 01:55:06 2010 +0200 +++ b/src/lib-index/mail-transaction-log-file.c Sun Feb 07 03:25:32 2010 +0200 @@ -72,6 +72,7 @@ file->log = log; file->filepath = i_strdup(path); file->fd = -1; + file->index_deleted_offset = (uoff_t)-1; return file; } @@ -1101,14 +1102,19 @@ return 0; /* external transactions: */ - if ((hdr->type & MAIL_TRANSACTION_TYPE_MASK) == - MAIL_TRANSACTION_HEADER_UPDATE) { + switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) { + case MAIL_TRANSACTION_HEADER_UPDATE: /* see if this updates mailbox_sync_offset */ ret = log_file_track_mailbox_sync_offset_hdr(file, data, trans_size - sizeof(*hdr)); if (ret != 0) return ret < 0 ? -1 : 0; + break; + case MAIL_TRANSACTION_INDEX_DELETED: + file->log->index->index_deleted = TRUE; + file->index_deleted_offset = file->sync_offset + trans_size; + break; } if (file->max_tail_offset == file->sync_offset) { @@ -1133,6 +1139,10 @@ 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 -r 302a4f807276 -r fc0ac73f0b36 src/lib-index/mail-transaction-log-private.h --- a/src/lib-index/mail-transaction-log-private.h Sun Feb 07 01:55:06 2010 +0200 +++ b/src/lib-index/mail-transaction-log-private.h Sun Feb 07 03:25:32 2010 +0200 @@ -65,6 +65,10 @@ 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; + struct modseq_cache modseq_cache[LOG_FILE_MODSEQ_CACHE_SIZE]; struct file_lock *file_lock; diff -r 302a4f807276 -r fc0ac73f0b36 src/lib-index/mail-transaction-log.h --- a/src/lib-index/mail-transaction-log.h Sun Feb 07 01:55:06 2010 +0200 +++ b/src/lib-index/mail-transaction-log.h Sun Feb 07 03:25:32 2010 +0200 @@ -42,6 +42,7 @@ MAIL_TRANSACTION_UID_UPDATE = 0x00004000, MAIL_TRANSACTION_MODSEQ_UPDATE = 0x00008000, MAIL_TRANSACTION_EXT_HDR_UPDATE32 = 0x00010000, + MAIL_TRANSACTION_INDEX_DELETED = 0x00020000, MAIL_TRANSACTION_TYPE_MASK = 0x000fffff, diff -r 302a4f807276 -r fc0ac73f0b36 src/lib-storage/index/cydir/cydir-save.c --- a/src/lib-storage/index/cydir/cydir-save.c Sun Feb 07 01:55:06 2010 +0200 +++ b/src/lib-storage/index/cydir/cydir-save.c Sun Feb 07 03:25:32 2010 +0200 @@ -85,6 +85,11 @@ enum mail_flags save_flags; struct istream *crlf_input; + if (mail_index_is_deleted(ctx->mbox->ibox.index)) { + mailbox_set_deleted(trans->box); + return -1; + } + T_BEGIN { const char *path; diff -r 302a4f807276 -r fc0ac73f0b36 src/lib-storage/index/dbox-multi/mdbox-save.c --- a/src/lib-storage/index/dbox-multi/mdbox-save.c Sun Feb 07 01:55:06 2010 +0200 +++ b/src/lib-storage/index/dbox-multi/mdbox-save.c Sun Feb 07 03:25:32 2010 +0200 @@ -97,6 +97,11 @@ struct dbox_save_mail *save_mail; uoff_t mail_size, append_offset; + if (mail_index_is_deleted(ctx->mbox->ibox.index)) { + mailbox_set_deleted(_ctx->transaction->box); + return -1; + } + /* get the size of the mail to be saved, if possible */ if (i_stream_get_size(input, TRUE, &mail_size) <= 0) { const struct stat *st; diff -r 302a4f807276 -r fc0ac73f0b36 src/lib-storage/index/dbox-single/sdbox-save.c --- a/src/lib-storage/index/dbox-single/sdbox-save.c Sun Feb 07 01:55:06 2010 +0200 +++ b/src/lib-storage/index/dbox-single/sdbox-save.c Sun Feb 07 03:25:32 2010 +0200 @@ -78,6 +78,11 @@ struct dbox_file *file; int ret; + if (mail_index_is_deleted(ctx->mbox->ibox.index)) { + mailbox_set_deleted(_ctx->transaction->box); + return -1; + } + file = sdbox_file_init(ctx->mbox, 0); ctx->append_ctx = dbox_file_append_init(file); ret = dbox_file_get_append_stream(ctx->append_ctx, diff -r 302a4f807276 -r fc0ac73f0b36 src/lib-storage/index/index-storage.c --- a/src/lib-storage/index/index-storage.c Sun Feb 07 01:55:06 2010 +0200 +++ b/src/lib-storage/index/index-storage.c Sun Feb 07 03:25:32 2010 +0200 @@ -441,6 +441,11 @@ index_thread_mailbox_opened(ibox); if (hook_mailbox_opened != NULL) hook_mailbox_opened(box); + + if (mail_index_is_deleted(ibox->index)) { + mailbox_set_deleted(box); + return -1; + } return 0; } @@ -649,7 +654,10 @@ void mail_storage_set_index_error(struct index_mailbox *ibox) { - mail_storage_set_internal_error(ibox->box.storage); + if (mail_index_is_deleted(ibox->index)) + mailbox_set_deleted(&ibox->box); + else + mail_storage_set_internal_error(ibox->box.storage); mail_index_reset_error(ibox->index); } diff -r 302a4f807276 -r fc0ac73f0b36 src/lib-storage/index/index-transaction.c --- a/src/lib-storage/index/index-transaction.c Sun Feb 07 01:55:06 2010 +0200 +++ b/src/lib-storage/index/index-transaction.c Sun Feb 07 03:25:32 2010 +0200 @@ -122,6 +122,8 @@ _t->changes = changes_r; ret = mail_index_transaction_commit_full(&itrans, &result); + if (ret < 0 && mail_index_is_deleted(ibox->index)) + mailbox_set_deleted(&ibox->box); changes_r->ignored_uid_changes = result.ignored_uid_changes; changes_r->ignored_modseq_changes = result.ignored_modseq_changes; diff -r 302a4f807276 -r fc0ac73f0b36 src/lib-storage/index/maildir/maildir-copy.c --- a/src/lib-storage/index/maildir/maildir-copy.c Sun Feb 07 01:55:06 2010 +0200 +++ b/src/lib-storage/index/maildir/maildir-copy.c Sun Feb 07 03:25:32 2010 +0200 @@ -170,6 +170,11 @@ return 0; } + if (mail_index_is_deleted(dest_mbox->ibox.index)) { + mailbox_set_deleted(&dest_mbox->ibox.box); + return -1; + } + memset(&do_ctx, 0, sizeof(do_ctx)); do_ctx.dest_path = str_new(default_pool, 512); diff -r 302a4f807276 -r fc0ac73f0b36 src/lib-storage/index/maildir/maildir-save.c --- a/src/lib-storage/index/maildir/maildir-save.c Sun Feb 07 01:55:06 2010 +0200 +++ b/src/lib-storage/index/maildir/maildir-save.c Sun Feb 07 03:25:32 2010 +0200 @@ -305,6 +305,11 @@ string_t *path; int fd; + if (mail_index_is_deleted(mbox->ibox.index)) { + mailbox_set_deleted(box); + return -1; + } + path = t_str_new(256); str_append(path, dir); str_append_c(path, '/'); diff -r 302a4f807276 -r fc0ac73f0b36 src/lib-storage/index/mbox/mbox-save.c --- a/src/lib-storage/index/mbox/mbox-save.c Sun Feb 07 01:55:06 2010 +0200 +++ b/src/lib-storage/index/mbox/mbox-save.c Sun Feb 07 03:25:32 2010 +0200 @@ -261,6 +261,11 @@ return -1; } + if (mail_index_is_deleted(mbox->ibox.index)) { + mailbox_set_deleted(&mbox->ibox.box); + return -1; + } + if ((_t->flags & MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS) != 0 || ctx->ctx.uid != 0) want_mail = TRUE;