]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
mbox: Fixed assert-crash due to wrong transaction_count handling.
authorTimo Sirainen <tss@iki.fi>
Sun, 22 Sep 2013 03:30:47 +0000 (06:30 +0300)
committerTimo Sirainen <tss@iki.fi>
Sun, 22 Sep 2013 03:30:47 +0000 (06:30 +0300)
This happened only when messages had been expunged by another session just
before saving a new message.

src/lib-storage/index/mbox/mbox-storage.c
src/lib-storage/mail-storage.c

index 0d4195182f0043eeb7f7294187a7c33c102de49b..4b6fef54a9327ed0a540ef8aaeb92f6a618e7e3e 100644 (file)
@@ -737,7 +737,8 @@ mbox_transaction_unlock(struct mailbox *box, unsigned int lock_id1,
        if (lock_id2 != 0)
                mbox_unlock(mbox, lock_id2);
        if (mbox->mbox_global_lock_id == 0) {
-               i_assert(mbox->box.transaction_count > 0 ||
+               i_assert(mbox->box.transaction_count > 0);
+               i_assert(mbox->box.transaction_count > 1 ||
                         mbox->external_transactions > 0 ||
                         mbox->mbox_lock_type == F_UNLCK);
        } else {
index 415b00c6f3ab1ea45b05600248edc7ea0df89c50..4e753f45c33dead55419fbc69509e1230c61b5e3 100644 (file)
@@ -1836,15 +1836,15 @@ int mailbox_transaction_commit_get_changes(
        struct mail_transaction_commit_changes *changes_r)
 {
        struct mailbox_transaction_context *t = *_t;
+       struct mailbox *box = t->box;
        unsigned int save_count = t->save_count;
        int ret;
 
-       t->box->transaction_count--;
        changes_r->pool = NULL;
 
        *_t = NULL;
        T_BEGIN {
-               ret = t->box->v.transaction_commit(t, changes_r);
+               ret = box->v.transaction_commit(t, changes_r);
        } T_END;
        /* either all the saved messages get UIDs or none, because a) we
           failed, b) MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS not set,
@@ -1852,6 +1852,11 @@ int mailbox_transaction_commit_get_changes(
        i_assert(ret < 0 ||
                 seq_range_count(&changes_r->saved_uids) == save_count ||
                 array_count(&changes_r->saved_uids) == 0);
+       /* decrease the transaction count only after transaction_commit().
+          that way if it creates and destroys transactions internally, we
+          don't see transaction_count=0 until the parent transaction is fully
+          finished */
+       box->transaction_count--;
        if (ret < 0 && changes_r->pool != NULL)
                pool_unref(&changes_r->pool);
        return ret;
@@ -1860,11 +1865,11 @@ int mailbox_transaction_commit_get_changes(
 void mailbox_transaction_rollback(struct mailbox_transaction_context **_t)
 {
        struct mailbox_transaction_context *t = *_t;
-
-       t->box->transaction_count--;
+       struct mailbox *box = t->box;
 
        *_t = NULL;
-       t->box->v.transaction_rollback(t);
+       box->v.transaction_rollback(t);
+       box->transaction_count--;
 }
 
 unsigned int mailbox_transaction_get_count(const struct mailbox *box)