From: Timo Sirainen Date: Wed, 23 Jul 2003 02:55:12 +0000 (+0300) Subject: Explicit lock() method for mailbox. X-Git-Tag: 1.1.alpha1~4467 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4b9441132b03149cce54b8fbaabb6bbcc10b899e;p=thirdparty%2Fdovecot%2Fcore.git Explicit lock() method for mailbox. --HG-- branch : HEAD --- diff --git a/src/imap/cmd-copy.c b/src/imap/cmd-copy.c index 5f799031c4..c8bd18ba08 100644 --- a/src/imap/cmd-copy.c +++ b/src/imap/cmd-copy.c @@ -12,8 +12,7 @@ static int fetch_and_copy(struct mail_copy_context *copy_ctx, int failed = FALSE; fetch_ctx = box->fetch_init(box, MAIL_FETCH_STREAM_HEADER | - MAIL_FETCH_STREAM_BODY, FALSE, - messageset, uidset); + MAIL_FETCH_STREAM_BODY, messageset, uidset); if (fetch_ctx == NULL) return FALSE; @@ -56,10 +55,15 @@ int cmd_copy(struct client *client) return TRUE; } - /* FIXME: copying from mailbox to itself is kind of kludgy here. - currently it works simply because copy_init() will lock mbox - exclusively and fetching wont drop it. */ - copy_ctx = destbox->copy_init(destbox); + if (destbox == client->mailbox) { + /* copying inside same mailbox, make sure we get the + locking right */ + if (!destbox->lock(destbox, MAILBOX_LOCK_READ | + MAILBOX_LOCK_SAVE)) + failed = TRUE; + } + + copy_ctx = failed ? NULL : destbox->copy_init(destbox); if (copy_ctx == NULL) failed = TRUE; else { @@ -71,6 +75,8 @@ int cmd_copy(struct client *client) failed = TRUE; } + (void)destbox->lock(destbox, MAILBOX_LOCK_UNLOCK); + if (failed) client_send_storage_error(client); else if (!all_found) { @@ -79,7 +85,10 @@ int cmd_copy(struct client *client) client_send_tagline(client, "NO Some of the requested messages no longer exist."); } else { - client_sync_full_fast(client); + if (destbox == client->mailbox) + client_sync_full(client); + else + client_sync_full_fast(client); client_send_tagline(client, "OK Copy completed."); } diff --git a/src/imap/cmd-store.c b/src/imap/cmd-store.c index a7b4a41916..119d168c36 100644 --- a/src/imap/cmd-store.c +++ b/src/imap/cmd-store.c @@ -95,8 +95,11 @@ int cmd_store(struct client *client) /* and update the flags */ box = client->mailbox; - fetch_ctx = box->fetch_init(box, MAIL_FETCH_FLAGS, TRUE, - messageset, client->cmd_uid); + + failed = !box->lock(box, MAILBOX_LOCK_FLAGS | MAILBOX_LOCK_READ); + fetch_ctx = failed ? NULL : + box->fetch_init(box, MAIL_FETCH_FLAGS, + messageset, client->cmd_uid); if (fetch_ctx == NULL) failed = TRUE; else { @@ -119,6 +122,8 @@ int cmd_store(struct client *client) if (!box->fetch_deinit(fetch_ctx, &all_found)) failed = TRUE; + (void)box->lock(box, MAILBOX_LOCK_UNLOCK); + if (!failed) { if (client->cmd_uid) client_sync_full_fast(client); diff --git a/src/imap/imap-fetch.c b/src/imap/imap-fetch.c index 59dcfd0239..2b5dff5d7e 100644 --- a/src/imap/imap-fetch.c +++ b/src/imap/imap-fetch.c @@ -262,6 +262,7 @@ int imap_fetch(struct client *client, struct imap_fetch_body_data *bodies, const char *messageset, int uidset) { + struct mailbox *box = client->mailbox; struct imap_fetch_context ctx; struct mail *mail; int all_found; @@ -274,7 +275,7 @@ int imap_fetch(struct client *client, ctx.select_counter = client->select_counter; ctx.seen_flag.flags = MAIL_SEEN; - if (!client->mailbox->readonly) { + if (!box->readonly) { /* If we have any BODY[..] sections, \Seen flag is added for all messages */ struct imap_fetch_body_data *body; @@ -290,22 +291,29 @@ int imap_fetch(struct client *client, ctx.update_seen = TRUE; } - ctx.fetch_ctx = client->mailbox-> - fetch_init(client->mailbox, fetch_data, ctx.update_seen, - messageset, uidset); + if (ctx.update_seen) { + if (!box->lock(box, MAILBOX_LOCK_FLAGS | MAILBOX_LOCK_READ)) + return -1; + } + + ctx.fetch_ctx = box->fetch_init(box, fetch_data, messageset, uidset); if (ctx.fetch_ctx == NULL) - return -1; + ctx.failed = TRUE; + else { + ctx.str = str_new(default_pool, 8192); + while ((mail = box->fetch_next(ctx.fetch_ctx)) != NULL) { + if (!fetch_mail(&ctx, mail)) { + ctx.failed = TRUE; + break; + } + } + str_free(ctx.str); - ctx.str = str_new(default_pool, 8192); - while ((mail = client->mailbox->fetch_next(ctx.fetch_ctx)) != NULL) { - if (!fetch_mail(&ctx, mail)) { + if (!box->fetch_deinit(ctx.fetch_ctx, &all_found)) ctx.failed = TRUE; - break; - } } - str_free(ctx.str); - if (!client->mailbox->fetch_deinit(ctx.fetch_ctx, &all_found)) - return -1; + (void)box->lock(box, MAILBOX_LOCK_UNLOCK); + return ctx.failed ? -1 : all_found; } diff --git a/src/lib-storage/index/index-fetch.c b/src/lib-storage/index/index-fetch.c index dc8850a42d..34c71d169c 100644 --- a/src/lib-storage/index/index-fetch.c +++ b/src/lib-storage/index/index-fetch.c @@ -22,7 +22,7 @@ struct mail_fetch_context { struct mail_fetch_context * index_storage_fetch_init(struct mailbox *box, - enum mail_fetch_field wanted_fields, int update_flags, + enum mail_fetch_field wanted_fields, const char *messageset, int uidset) { struct index_mailbox *ibox = (struct index_mailbox *) box; @@ -32,12 +32,6 @@ index_storage_fetch_init(struct mailbox *box, ctx = i_new(struct mail_fetch_context, 1); ctx->old_lock = ibox->index->lock_type; - /* need exclusive lock to update the \Seen flags */ - if (update_flags && !box->readonly) { - if (!index_storage_lock(ibox, MAIL_LOCK_EXCLUSIVE)) - return NULL; - } - check_mail = (client_workarounds & WORKAROUND_OE6_FETCH_NO_NEWMAIL) == 0; if (!index_storage_sync_and_lock(ibox, check_mail, TRUE, diff --git a/src/lib-storage/index/index-storage.c b/src/lib-storage/index/index-storage.c index a3b0049763..efd4c00022 100644 --- a/src/lib-storage/index/index-storage.c +++ b/src/lib-storage/index/index-storage.c @@ -284,6 +284,14 @@ int index_storage_lock(struct index_mailbox *ibox, { int ret; + if (lock_type == MAIL_LOCK_UNLOCK) { + if (ibox->lock_type != MAILBOX_LOCK_UNLOCK) + return TRUE; + } else { + if (ibox->index->lock_type == MAIL_LOCK_EXCLUSIVE) + return TRUE; + } + /* we have to set/reset this every time, because the same index may be used by multiple IndexMailboxes. */ index_storage_init_lock_notify(ibox); diff --git a/src/lib-storage/index/index-storage.h b/src/lib-storage/index/index-storage.h index afd052e9a0..afb72670cd 100644 --- a/src/lib-storage/index/index-storage.h +++ b/src/lib-storage/index/index-storage.h @@ -21,6 +21,7 @@ struct index_mailbox { void (*mail_init)(struct index_mail *mail); struct mail_index *index; + enum mailbox_lock_type lock_type; struct timeout *autosync_to; struct index_autosync_file *autosync_files; @@ -91,7 +92,7 @@ int index_storage_sync(struct mailbox *box, enum mail_sync_flags flags); struct mail_fetch_context * index_storage_fetch_init(struct mailbox *box, - enum mail_fetch_field wanted_fields, int update_flags, + enum mail_fetch_field wanted_fields, const char *messageset, int uidset); int index_storage_fetch_deinit(struct mail_fetch_context *ctx, int *all_found); struct mail *index_storage_fetch_next(struct mail_fetch_context *ctx); diff --git a/src/lib-storage/index/maildir/maildir-storage.c b/src/lib-storage/index/maildir/maildir-storage.c index fbc5dc02ce..f075842935 100644 --- a/src/lib-storage/index/maildir/maildir-storage.c +++ b/src/lib-storage/index/maildir/maildir-storage.c @@ -705,6 +705,31 @@ static void maildir_storage_auto_sync(struct mailbox *box, } } +static int maildir_storage_lock(struct mailbox *box, + enum mailbox_lock_type lock_type) +{ + struct index_mailbox *ibox = (struct index_mailbox *) box; + + if (lock_type == MAIL_LOCK_UNLOCK) { + ibox->lock_type = MAIL_LOCK_UNLOCK; + if (!index_storage_lock(ibox, MAIL_LOCK_UNLOCK)) + return FALSE; + return TRUE; + } + + i_assert(ibox->lock_type == MAIL_LOCK_UNLOCK); + + if ((lock_type & (MAILBOX_LOCK_EXPUNGE | MAILBOX_LOCK_FLAGS)) != 0) { + if (!index_storage_lock(ibox, MAIL_LOCK_EXCLUSIVE)) + return FALSE; + } else if ((lock_type & MAILBOX_LOCK_READ) != 0) { + if (!index_storage_lock(ibox, MAIL_LOCK_SHARED)) + return FALSE; + } + + ibox->lock_type = lock_type; + return TRUE; +} struct mail_storage maildir_storage = { "maildir", /* name */ @@ -741,6 +766,7 @@ struct mailbox maildir_mailbox = { NULL, /* storage */ maildir_storage_close, + maildir_storage_lock, index_storage_get_status, index_storage_sync, maildir_storage_auto_sync, diff --git a/src/lib-storage/index/mbox/mbox-storage.c b/src/lib-storage/index/mbox/mbox-storage.c index 7525842edd..fca4f2e7e4 100644 --- a/src/lib-storage/index/mbox/mbox-storage.c +++ b/src/lib-storage/index/mbox/mbox-storage.c @@ -708,6 +708,39 @@ static void mbox_storage_auto_sync(struct mailbox *box, index_mailbox_check_add(ibox, ibox->index->mailbox_path); } +static int mbox_storage_lock(struct mailbox *box, + enum mailbox_lock_type lock_type) +{ + struct index_mailbox *ibox = (struct index_mailbox *) box; + + if (lock_type == MAIL_LOCK_UNLOCK) { + ibox->lock_type = MAIL_LOCK_UNLOCK; + if (!index_storage_lock(ibox, MAIL_LOCK_UNLOCK)) + return FALSE; + return TRUE; + } + + i_assert(ibox->lock_type == MAIL_LOCK_UNLOCK); + + if ((lock_type & (MAILBOX_LOCK_EXPUNGE | MAILBOX_LOCK_FLAGS)) != 0) { + if (!index_storage_lock(ibox, MAIL_LOCK_EXCLUSIVE)) + return FALSE; + } else if ((lock_type & MAILBOX_LOCK_READ) != 0) { + if (!index_storage_lock(ibox, MAIL_LOCK_SHARED)) + return FALSE; + } + + if ((lock_type & (MAILBOX_LOCK_EXPUNGE | MAILBOX_LOCK_SAVE)) != 0) { + /* FIXME: saving doesn't have to sync it, just lock it */ + if (!index_storage_sync_and_lock(ibox, FALSE, TRUE, + MAIL_LOCK_EXCLUSIVE)) + return FALSE; + } + + ibox->lock_type = lock_type; + return TRUE; +} + struct mail_storage mbox_storage = { "mbox", /* name */ @@ -743,6 +776,7 @@ struct mailbox mbox_mailbox = { NULL, /* storage */ mbox_storage_close, + mbox_storage_lock, index_storage_get_status, index_storage_sync, mbox_storage_auto_sync, diff --git a/src/lib-storage/mail-storage.h b/src/lib-storage/mail-storage.h index e120d5e43e..91e70b22f1 100644 --- a/src/lib-storage/mail-storage.h +++ b/src/lib-storage/mail-storage.h @@ -53,6 +53,14 @@ enum mailbox_sync_type { MAILBOX_SYNC_NO_EXPUNGES }; +enum mailbox_lock_type { + MAILBOX_LOCK_UNLOCK = 0x00, + MAILBOX_LOCK_READ = 0x01, + MAILBOX_LOCK_FLAGS = 0x02, + MAILBOX_LOCK_EXPUNGE = 0x04, + MAILBOX_LOCK_SAVE = 0x08 +}; + enum modify_type { MODIFY_ADD, MODIFY_REMOVE, @@ -225,6 +233,14 @@ struct mailbox { the mailbox was closed anyway. */ int (*close)(struct mailbox *box); + /* Explicitly lock the mailbox. If not used, all the methods below + use the minimum locking requirements. This allows you to for + example use the expunge() and update_flags() methods in + struct mail. The mailbox stays locked until you unlock it. + Note that if you call a method which wants more locks than you've + given here, the call will fail (to avoid deadlocks). */ + int (*lock)(struct mailbox *box, enum mailbox_lock_type lock_type); + /* Gets the mailbox status information. */ int (*get_status)(struct mailbox *box, enum mailbox_status_items items, struct mailbox_status *status); @@ -247,7 +263,6 @@ struct mailbox { struct mail_fetch_context * (*fetch_init)(struct mailbox *box, enum mail_fetch_field wanted_fields, - int update_flags, const char *messageset, int uidset); /* Deinitialize fetch request. all_found is set to TRUE if all of the fetched messages were found (ie. not just deleted). */ @@ -265,7 +280,7 @@ struct mailbox { enum mail_fetch_field wanted_fields); /* Modify sort_program to specify a sort program acceptable for - search_init(). If server supports no sorting, it's simply set to + search_init(). If mailbox supports no sorting, it's simply set to {MAIL_SORT_END}. */ int (*search_get_sorting)(struct mailbox *box, enum mail_sort_type *sort_program); @@ -376,7 +391,7 @@ struct mail { const struct mail_full_flags *flags, enum modify_type modify_type); - /* Copy this mail to another mailbox. */ + /* Copy this message to another mailbox. */ int (*copy)(struct mail *mail, struct mail_copy_context *ctx); };