dovecot-2.0: Added support for marking mailbox index deleted. Do...

dovecot at dovecot.org dovecot at dovecot.org
Sun Feb 7 03:25:36 EET 2010


details:   http://hg.dovecot.org/dovecot-2.0/rev/fc0ac73f0b36
changeset: 10655:fc0ac73f0b36
user:      Timo Sirainen <tss at iki.fi>
date:      Sun Feb 07 03:25:32 2010 +0200
description:
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.

diffstat:

20 files changed, 102 insertions(+), 3 deletions(-)
src/doveadm/doveadm-dump-log.c                 |    5 +++++
src/lib-index/mail-index-private.h             |    1 +
src/lib-index/mail-index-sync-update.c         |    6 ++++++
src/lib-index/mail-index-transaction-export.c  |    7 +++++++
src/lib-index/mail-index-transaction-private.h |    1 +
src/lib-index/mail-index-transaction-update.c  |    8 ++++++++
src/lib-index/mail-index-transaction.c         |    5 +++++
src/lib-index/mail-index.c                     |    5 +++++
src/lib-index/mail-index.h                     |    6 ++++++
src/lib-index/mail-transaction-log-file.c      |   14 ++++++++++++--
src/lib-index/mail-transaction-log-private.h   |    4 ++++
src/lib-index/mail-transaction-log.h           |    1 +
src/lib-storage/index/cydir/cydir-save.c       |    5 +++++
src/lib-storage/index/dbox-multi/mdbox-save.c  |    5 +++++
src/lib-storage/index/dbox-single/sdbox-save.c |    5 +++++
src/lib-storage/index/index-storage.c          |   10 +++++++++-
src/lib-storage/index/index-transaction.c      |    2 ++
src/lib-storage/index/maildir/maildir-copy.c   |    5 +++++
src/lib-storage/index/maildir/maildir-save.c   |    5 +++++
src/lib-storage/index/mbox/mbox-save.c         |    5 +++++

diffs (truncated from 346 to 300 lines):

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
@@ -108,6 +108,9 @@ static const char *log_record_type(unsig
 		break;
 	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);
@@ -411,6 +414,8 @@ static void log_record_print(const struc
 		}
 		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 @@ struct mail_index {
 	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 @@ int mail_index_sync_record(struct mail_i
 		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 @@ void mail_index_transaction_export(struc
 				  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 @@ struct mail_index_transaction {
 	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 @@ void mail_index_transaction_reset_v(stru
 	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 @@ void mail_index_reset(struct mail_index_
 	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 @@ int mail_index_transaction_commit_full(s
 		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 @@ void mail_index_mark_corrupted(struct ma
 	}
 }
 
+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 @@ void mail_index_update_highest_modseq(st
 /* 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 @@ mail_transaction_log_file_alloc(struct m
 	file->log = log;
 	file->filepath = i_strdup(path);
 	file->fd = -1;
+	file->index_deleted_offset = (uoff_t)-1;
 	return file;
 }
 
@@ -1101,14 +1102,19 @@ log_file_track_sync(struct mail_transact
 		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 @@ mail_transaction_log_file_sync(struct ma
 
 	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
@@ -64,6 +64,10 @@ struct mail_transaction_log_file {
 	/* don't give warnings about saved_tail_offset shrinking if
 	   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];
 
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 @@ enum mail_transaction_type {
 	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 @@ int cydir_save_begin(struct mail_save_co
 	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 @@ int mdbox_save_begin(struct mail_save_co
 	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 @@ int sdbox_save_begin(struct mail_save_co
 	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 @@ int index_storage_mailbox_open(struct ma
 	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 @@ bool index_storage_is_inconsistent(struc
 
 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 @@ int index_transaction_commit(struct mail
 	_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;


More information about the dovecot-cvs mailing list