]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Explicit lock() method for mailbox.
authorTimo Sirainen <tss@iki.fi>
Wed, 23 Jul 2003 02:55:12 +0000 (05:55 +0300)
committerTimo Sirainen <tss@iki.fi>
Wed, 23 Jul 2003 02:55:12 +0000 (05:55 +0300)
--HG--
branch : HEAD

src/imap/cmd-copy.c
src/imap/cmd-store.c
src/imap/imap-fetch.c
src/lib-storage/index/index-fetch.c
src/lib-storage/index/index-storage.c
src/lib-storage/index/index-storage.h
src/lib-storage/index/maildir/maildir-storage.c
src/lib-storage/index/mbox/mbox-storage.c
src/lib-storage/mail-storage.h

index 5f799031c4cd12e4c789b1ca69b597e5e0af79b1..c8bd18ba08dcdc6abddeaf51b473a7227d7e7ccc 100644 (file)
@@ -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.");
        }
 
index a7b4a4191646bbc1b9ab02ed016602120c8da0fe..119d168c36eeafe064b0e94d2508897b41b80e68 100644 (file)
@@ -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);
index 59dcfd02390f5540245c68c7811286157378f6d0..2b5dff5d7ea4f73e6cc9034fc1905aac0a9b6604 100644 (file)
@@ -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;
 }
index dc8850a42d2f3fb77ba52e8c2377cb8378998c73..34c71d169c71046ff0a1c63dc6a90d13fd073e00 100644 (file)
@@ -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,
index a3b0049763fe3715c860519e57f79edd3438b2e9..efd4c000221c500b41a6b52c84ae9932fce012ff 100644 (file)
@@ -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);
index afd052e9a0e71055eae323809e6ea10df6b5d48e..afb72670cd21a3cc1590542de144121de3afa812 100644 (file)
@@ -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);
index fbc5dc02ce0c0ff85a59c4f6603abf4a650ef65f..f075842935c34a1800d768b2883643e9f9e1be21 100644 (file)
@@ -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,
index 7525842edd4c3505a752110e2e0e289221118887..fca4f2e7e4f858d8f2dcb793cefa4e76b1f6c9d9 100644 (file)
@@ -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,
index e120d5e43e6c562d5d486fbb73615ba4bd54d1ea..91e70b22f16dda9fd0fd0c23dcc07627addc6e38 100644 (file)
@@ -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);
 };