dovecot-2.2: lib-index, lib-storage: Fixed race conditions with ...
dovecot at dovecot.org
dovecot at dovecot.org
Thu Aug 28 17:15:19 UTC 2014
details: http://hg.dovecot.org/dovecot-2.2/rev/6980c53bf7d7
changeset: 17758:6980c53bf7d7
user: Timo Sirainen <tss at iki.fi>
date: Fri Aug 29 02:14:43 2014 +0900
description:
lib-index, lib-storage: Fixed race conditions with deleting mailbox.
Now only one process can successfully finish mailbox_mark_index_deleted().
diffstat:
src/lib-index/mail-index-sync.c | 31 +++++++++++++++++++------------
src/lib-index/mail-index.h | 6 +++++-
src/lib-index/mail-transaction-log-file.c | 1 +
src/lib-storage/index/index-sync.c | 7 +++++--
src/lib-storage/mail-storage-private.h | 2 ++
src/lib-storage/mail-storage.c | 5 ++++-
6 files changed, 36 insertions(+), 16 deletions(-)
diffs (141 lines):
diff -r 2324dea38a03 -r 6980c53bf7d7 src/lib-index/mail-index-sync.c
--- a/src/lib-index/mail-index-sync.c Fri Aug 29 00:41:07 2014 +0900
+++ b/src/lib-index/mail-index-sync.c Fri Aug 29 02:14:43 2014 +0900
@@ -360,13 +360,21 @@
}
}
- if (!mail_index_need_sync(index, flags,
- log_file_seq, log_file_offset)) {
+ if (!mail_index_need_sync(index, flags, log_file_seq, log_file_offset) &&
+ !index->index_deleted) {
if (locked)
mail_transaction_log_sync_unlock(index->log);
return 0;
}
+ if (!locked) {
+ /* it looks like we have something to sync. lock the file and
+ check again. */
+ flags &= ~MAIL_INDEX_SYNC_FLAG_REQUIRE_CHANGES;
+ return mail_index_sync_begin_init(index, flags, log_file_seq,
+ log_file_offset);
+ }
+
if (index->index_deleted &&
(flags & MAIL_INDEX_SYNC_FLAG_DELETING_INDEX) == 0) {
/* index is already deleted. we can't sync. */
@@ -375,14 +383,6 @@
return -1;
}
- if (!locked) {
- /* it looks like we have something to sync. lock the file and
- check again. */
- flags &= ~MAIL_INDEX_SYNC_FLAG_REQUIRE_CHANGES;
- return mail_index_sync_begin_init(index, flags, log_file_seq,
- log_file_offset);
- }
-
hdr = &index->map->hdr;
if (hdr->log_file_tail_offset > hdr->log_file_head_offset ||
hdr->log_file_seq > seq ||
@@ -482,7 +482,8 @@
ctx->ext_trans = mail_index_transaction_begin(ctx->view, trans_flags);
ctx->ext_trans->sync_transaction = TRUE;
ctx->ext_trans->commit_deleted_index =
- (flags & MAIL_INDEX_SYNC_FLAG_DELETING_INDEX) != 0;
+ (flags & (MAIL_INDEX_SYNC_FLAG_DELETING_INDEX |
+ MAIL_INDEX_SYNC_FLAG_TRY_DELETING_INDEX)) != 0;
*ctx_r = ctx;
*view_r = ctx->view;
@@ -789,10 +790,16 @@
index_undeleted = ctx->ext_trans->index_undeleted;
delete_index = index->index_delete_requested && !index_undeleted &&
- (ctx->flags & MAIL_INDEX_SYNC_FLAG_DELETING_INDEX) != 0;
+ (ctx->flags & (MAIL_INDEX_SYNC_FLAG_DELETING_INDEX |
+ MAIL_INDEX_SYNC_FLAG_TRY_DELETING_INDEX)) != 0;
if (delete_index) {
/* finish this sync by marking the index deleted */
mail_index_set_deleted(ctx->ext_trans);
+ } else if (index->index_deleted && !index_undeleted &&
+ (ctx->flags & MAIL_INDEX_SYNC_FLAG_TRY_DELETING_INDEX) == 0) {
+ /* another process just marked the index deleted.
+ finish the sync, but return error. */
+ ret = -1;
}
mail_index_sync_update_mailbox_offset(ctx);
diff -r 2324dea38a03 -r 6980c53bf7d7 src/lib-index/mail-index.h
--- a/src/lib-index/mail-index.h Fri Aug 29 00:41:07 2014 +0900
+++ b/src/lib-index/mail-index.h Fri Aug 29 02:14:43 2014 +0900
@@ -159,7 +159,11 @@
MAIL_INDEX_SYNC_FLAG_FSYNC = 0x10,
/* If we see "delete index" request transaction, finish it.
This flag also allows committing more changes to a deleted index. */
- MAIL_INDEX_SYNC_FLAG_DELETING_INDEX = 0x20
+ MAIL_INDEX_SYNC_FLAG_DELETING_INDEX = 0x20,
+ /* Same as MAIL_INDEX_SYNC_FLAG_DELETING_INDEX, but finish index
+ deletion only once and fail the rest (= avoid race conditions when
+ multiple processes try to mark the index deleted) */
+ MAIL_INDEX_SYNC_FLAG_TRY_DELETING_INDEX = 0x40
};
enum mail_index_view_sync_flags {
diff -r 2324dea38a03 -r 6980c53bf7d7 src/lib-index/mail-transaction-log-file.c
--- a/src/lib-index/mail-transaction-log-file.c Fri Aug 29 00:41:07 2014 +0900
+++ b/src/lib-index/mail-transaction-log-file.c Fri Aug 29 02:14:43 2014 +0900
@@ -1284,6 +1284,7 @@
if (file->sync_offset < file->index_undeleted_offset)
break;
file->log->index->index_deleted = TRUE;
+ file->log->index->index_delete_requested = FALSE;
file->index_deleted_offset = file->sync_offset + trans_size;
break;
case MAIL_TRANSACTION_INDEX_UNDELETED:
diff -r 2324dea38a03 -r 6980c53bf7d7 src/lib-storage/index/index-sync.c
--- a/src/lib-storage/index/index-sync.c Fri Aug 29 00:41:07 2014 +0900
+++ b/src/lib-storage/index/index-sync.c Fri Aug 29 02:14:43 2014 +0900
@@ -17,8 +17,11 @@
if ((box->flags & MAILBOX_FLAG_DROP_RECENT) != 0)
sync_flags |= MAIL_INDEX_SYNC_FLAG_DROP_RECENT;
- if (box->deleting)
- sync_flags |= MAIL_INDEX_SYNC_FLAG_DELETING_INDEX;
+ if (box->deleting) {
+ sync_flags |= box->delete_sync_check ?
+ MAIL_INDEX_SYNC_FLAG_TRY_DELETING_INDEX :
+ MAIL_INDEX_SYNC_FLAG_DELETING_INDEX;
+ }
return sync_flags;
}
diff -r 2324dea38a03 -r 6980c53bf7d7 src/lib-storage/mail-storage-private.h
--- a/src/lib-storage/mail-storage-private.h Fri Aug 29 00:41:07 2014 +0900
+++ b/src/lib-storage/mail-storage-private.h Fri Aug 29 02:14:43 2014 +0900
@@ -332,6 +332,8 @@
unsigned int creating:1;
/* Mailbox is being deleted */
unsigned int deleting:1;
+ /* Don't use MAIL_INDEX_SYNC_FLAG_DELETING_INDEX for sync flag */
+ unsigned int delete_sync_check:1;
/* Delete mailbox only if it's empty */
unsigned int deleting_must_be_empty:1;
/* The backend wants to skip checking if there are 0 messages before
diff -r 2324dea38a03 -r 6980c53bf7d7 src/lib-storage/mail-storage.c
--- a/src/lib-storage/mail-storage.c Fri Aug 29 00:41:07 2014 +0900
+++ b/src/lib-storage/mail-storage.c Fri Aug 29 02:14:43 2014 +0900
@@ -1319,7 +1319,10 @@
/* sync the mailbox. this finishes the index deletion and it can
succeed only for a single session. we do it here, so the rest of
the deletion code doesn't have to worry about race conditions. */
- if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0)
+ box->delete_sync_check = TRUE;
+ ret = mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ);
+ box->delete_sync_check = FALSE;
+ if (ret < 0)
return -1;
box->marked_deleted = del;
More information about the dovecot-cvs
mailing list