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);
}
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)
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;
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);
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;
}
{
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)
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;
}