dovecot-2.2: lib-storage: LAYOUT=index now first creates the bac...
dovecot at dovecot.org
dovecot at dovecot.org
Sat Oct 25 03:21:20 UTC 2014
details: http://hg.dovecot.org/dovecot-2.2/rev/004b9a36c92f
changeset: 18012:004b9a36c92f
user: Timo Sirainen <tss at iki.fi>
date: Sat Oct 25 06:19:41 2014 +0300
description:
lib-storage: LAYOUT=index now first creates the backend mailbox and only then adds it to list index.
This avoids any race conditions with mailbox creation and opening it.
diffstat:
src/lib-storage/list/mailbox-list-index-backend.c | 71 +++++++++++++++++-----
1 files changed, 55 insertions(+), 16 deletions(-)
diffs (131 lines):
diff -r 2b964521f5ab -r 004b9a36c92f src/lib-storage/list/mailbox-list-index-backend.c
--- a/src/lib-storage/list/mailbox-list-index-backend.c Sat Oct 25 06:18:45 2014 +0300
+++ b/src/lib-storage/list/mailbox-list-index-backend.c Sat Oct 25 06:19:41 2014 +0300
@@ -16,6 +16,9 @@
struct index_mailbox_list {
struct mailbox_list list;
const char *temp_prefix;
+
+ const char *create_mailbox_name;
+ guid_128_t create_mailbox_guid;
};
extern struct mailbox_list index_mailbox_list;
@@ -136,6 +139,13 @@
if (!mailbox_list_set_get_root_path(&_list->set, type, &root_dir))
return 0;
+ if (list->create_mailbox_name != NULL &&
+ strcmp(list->create_mailbox_name, name) == 0) {
+ *path_r = index_get_guid_path(_list, root_dir,
+ list->create_mailbox_guid);
+ return 1;
+ }
+
if (ilist->sync_ctx != NULL) {
/* we could get here during sync from
index_list_mailbox_create_selectable() */
@@ -338,19 +348,39 @@
new_update = *update;
if (guid_128_is_empty(new_update.mailbox_guid))
guid_128_generate(new_update.mailbox_guid);
- ret = index_list_mailbox_create_selectable(box, new_update.mailbox_guid);
- if (ret < 0) {
- mail_storage_copy_list_error(box->storage, box->list);
- return -1;
+
+ /* create the backend mailbox first before it exists in the
+ list. the mailbox creation wants to use get_path() though,
+ so use a bit kludgy create_mailbox_* variables during the
+ creation to return the path. we'll also support recursively
+ creating more mailboxes in here. */
+ const char *old_name;
+ guid_128_t old_guid;
+
+ old_name = list->create_mailbox_name;
+ guid_128_copy(old_guid, list->create_mailbox_guid);
+
+ list->create_mailbox_name = box->name;
+ guid_128_copy(list->create_mailbox_guid, new_update.mailbox_guid);
+
+ ret = ibox->module_ctx.super.create_box(box, &new_update, FALSE);
+
+ if (ret == 0) {
+ /* backend mailbox was successfully created. now add it
+ to the list. */
+ ret = index_list_mailbox_create_selectable(box, new_update.mailbox_guid);
+ if (ret < 0)
+ mail_storage_copy_list_error(box->storage, box->list);
+ if (ret <= 0) {
+ /* failed to add to list. rollback the backend
+ mailbox creation */
+ (void)mailbox_delete(box);
+ }
}
- if (ret > 0) {
- /* mailbox entry was created. create the mailbox
- itself now after the mailbox list index is already
- unlocked (to avoid deadlocks in case the create_box()
- goes back to updating mailbox list index). */
- if (ibox->module_ctx.super.create_box(box, update, FALSE) < 0)
- return -1;
- }
+ list->create_mailbox_name = old_name;
+ guid_128_copy(list->create_mailbox_guid, old_guid);
+ if (ret < 0)
+ return ret;
} else {
ret = 0;
}
@@ -460,13 +490,20 @@
}
static int
-index_list_delete_entry(struct mailbox_list *list, const char *name,
+index_list_delete_entry(struct index_mailbox_list *list, const char *name,
bool delete_selectable)
{
struct mailbox_list_index_sync_context *sync_ctx;
int ret;
- if (mailbox_list_index_sync_begin(list, &sync_ctx) < 0)
+ if (strcmp(name, list->create_mailbox_name) == 0) {
+ /* we're rollbacking a failed create. if the name exists in the
+ list, it was done by somebody else so we don't want to
+ remove it. */
+ return 0;
+ }
+
+ if (mailbox_list_index_sync_begin(&list->list, &sync_ctx) < 0)
return -1;
ret = mailbox_list_index_sync_delete(sync_ctx, name, delete_selectable);
if (mailbox_list_index_sync_end(&sync_ctx, TRUE) < 0)
@@ -477,6 +514,7 @@
static int
index_list_delete_mailbox(struct mailbox_list *_list, const char *name)
{
+ struct index_mailbox_list *list = (struct index_mailbox_list *)_list;
const char *path;
int ret;
@@ -498,7 +536,7 @@
if (ret == 0 || (_list->props & MAILBOX_LIST_PROP_AUTOCREATE_DIRS) != 0)
index_list_delete_finish(_list, name);
if (ret == 0) {
- if (index_list_delete_entry(_list, name, TRUE) < 0)
+ if (index_list_delete_entry(list, name, TRUE) < 0)
return -1;
}
return ret;
@@ -507,9 +545,10 @@
static int
index_list_delete_dir(struct mailbox_list *_list, const char *name)
{
+ struct index_mailbox_list *list = (struct index_mailbox_list *)_list;
int ret;
- if ((ret = index_list_delete_entry(_list, name, FALSE)) < 0)
+ if ((ret = index_list_delete_entry(list, name, FALSE)) < 0)
return -1;
if (ret == 0) {
mailbox_list_set_error(_list, MAIL_ERROR_EXISTS,
More information about the dovecot-cvs
mailing list