]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Locking fixes
authorTimo Sirainen <tss@iki.fi>
Sun, 16 May 2004 20:20:24 +0000 (23:20 +0300)
committerTimo Sirainen <tss@iki.fi>
Sun, 16 May 2004 20:20:24 +0000 (23:20 +0300)
--HG--
branch : HEAD

src/lib-index/mail-index-lock.c
src/lib-index/mail-index-view.c
src/lib-index/mail-index.c

index 6cf2d5019d9b3b5e309a0323700aadc3408c9371..eb7937a93df2b2c43f24c8ccc323e6253433823d 100644 (file)
@@ -149,7 +149,7 @@ static int mail_index_lock(struct mail_index *index, int lock_type,
                           unsigned int timeout_secs, int update_index,
                           unsigned int *lock_id_r)
 {
-       int ret;
+       int ret, ret2;
 
        i_assert(lock_type == F_RDLCK || lock_type == F_WRLCK);
 
@@ -166,8 +166,11 @@ static int mail_index_lock(struct mail_index *index, int lock_type,
        }
 
        if (update_index && index->excl_lock_count == 0) {
-               if (mail_index_has_changed(index) < 0)
+               if ((ret2 = mail_index_has_changed(index)) < 0)
                        return -1;
+               if (ret > 0 && ret2 == 0)
+                       return 1;
+               ret = 0;
        }
 
        if (ret > 0)
@@ -192,16 +195,36 @@ static int mail_index_lock(struct mail_index *index, int lock_type,
                return 1;
        }
 
-       ret = file_wait_lock_full(index->fd, lock_type, timeout_secs,
-                                 NULL, NULL);
-       if (ret <= 0) {
-               if (ret == 0 || errno == EDEADLK) {
-                       /* deadlock equals to timeout */
-                       return 0;
+       if (lock_type == F_RDLCK || !index->log_locked) {
+               ret = file_wait_lock_full(index->fd, lock_type, timeout_secs,
+                                         NULL, NULL);
+               if (ret < 0) {
+                       mail_index_set_syscall_error(index, "file_wait_lock()");
+                       return -1;
+               }
+       } else {
+               /* this is kind of kludgy. we wish to avoid deadlocks while
+                  trying to lock transaction log, but it can happen if our
+                  process is holding transaction log lock and waiting for
+                  index write lock, while the other process is holding index
+                  read lock and waiting for transaction log lock.
+
+                  we don't have a problem with grabbing read index lock
+                  because the only way for it to block is if it's
+                  write-locked, which isn't allowed unless transaction log
+                  is also locked.
+
+                  so, the workaround for this problem is that we simply try
+                  locking once. if it doesn't work, just rewrite the file.
+                  hopefully there won't be any other deadlocking issues. :) */
+               ret = file_try_lock(index->fd, lock_type);
+               if (ret < 0) {
+                       mail_index_set_syscall_error(index, "file_try_lock()");
+                       return -1;
                }
-               mail_index_set_syscall_error(index, "file_wait_lock()");
-               return -1;
        }
+       if (ret == 0)
+               return 0;
 
        if (index->lock_type == F_UNLCK)
                index->lock_id += 2;
@@ -291,7 +314,7 @@ static int mail_index_lock_exclusive_copy(struct mail_index *index)
 
        old_lock_type = index->lock_type;
        index->lock_type = F_WRLCK;
-        index->excl_lock_count++;
+       index->excl_lock_count++;
 
        if (mail_index_reopen(index, fd) < 0) {
                i_assert(index->excl_lock_count == 1);
@@ -422,5 +445,10 @@ void mail_index_unlock(struct mail_index *index, unsigned int lock_id)
 
 int mail_index_is_locked(struct mail_index *index, unsigned int lock_id)
 {
-       return (index->lock_id ^ lock_id) <= 1;
+       if ((index->lock_id ^ lock_id) <= 1) {
+               i_assert(index->lock_type != F_UNLCK);
+               return TRUE;
+       }
+
+       return FALSE;
 }
index 414239275493dba3dd577716d20d5663f3d95585..6b1a5ed410149f4be9d30c54871a8a1a5191378f 100644 (file)
@@ -50,11 +50,6 @@ int mail_index_view_lock_head(struct mail_index_view *view, int update_index)
 {
        unsigned int lock_id;
 
-       if (view->map != view->index->map) {
-               if (mail_index_view_map_protect(view) < 0)
-                       return -1;
-       }
-
        if (!mail_index_is_locked(view->index, view->lock_id)) {
                if (mail_index_lock_shared(view->index, update_index,
                                           &view->lock_id) < 0)
@@ -78,6 +73,15 @@ int mail_index_view_lock_head(struct mail_index_view *view, int update_index)
                view->lock_id = lock_id;
        }
 
+       i_assert(view->index->lock_type != F_UNLCK);
+
+       /* mail_index_lock_shared() may have reopened the file,
+          so do this after it. */
+       if (view->map != view->index->map) {
+               if (mail_index_view_map_protect(view) < 0)
+                       return -1;
+       }
+
        return 0;
 }
 
index ac4a8a4f42640ca5e3fcd5b14455627d2849d9ad..0ae31dcfa6081b351426d43dfcb26f8422541c56 100644 (file)
@@ -574,6 +574,7 @@ int mail_index_open(struct mail_index *index, enum mail_index_open_flags flags)
                index->shared_lock_count = 0;
                index->excl_lock_count = 0;
                index->lock_type = F_UNLCK;
+               index->lock_id = 2;
 
                index->nodiskspace = FALSE;
                index->index_lock_timeout = FALSE;