mail-index-lock.c revision 0d5101a9e42a98724b4ca2860c16f1ada7dff17e
/* Copyright (C) 2003-2004 Timo Sirainen */
/*
Locking should never fail or timeout. Exclusive locks must be kept as short
time as possible. Shared locks can be long living, so if we can't get
exclusive lock directly within 2 seconds, we'll replace the index file with
a copy of it. That means the shared lock holders can keep using the old file
while we're modifying the new file.
lock_id is used to figure out if acquired lock is still valid. When index
file is reopened, the lock_id can become invalid. It doesn't matter however,
as no-one's going to modify the old file anymore.
lock_id also tells if we're referring to shared or exclusive lock. This
allows us to drop back to shared locking once all exclusive locks are
dropped. Shared locks have even numbers, exclusive locks have odd numbers.
The number is increased by two every time the lock is dropped or index file
is reopened.
*/
#include "lib.h"
#include "mmap-util.h"
#include "file-lock.h"
#include "write-full.h"
#include "mail-index-private.h"
#include <stdio.h>
{
int prot;
if (!MAIL_INDEX_MAP_IS_IN_MEMORY(map)) {
return -1;
}
}
return 0;
}
{
return 0;
}
unsigned int timeout_secs, int update_index,
unsigned int *lock_id_r)
{
ret = 1;
index->excl_lock_count++;
ret = 1;
} else {
ret = 0;
}
return -1;
return 1;
ret = 0;
}
if (ret > 0)
return 1;
if (index->fcntl_locks_disable) {
/* FIXME: exclusive locking will rewrite the index file every
time. shouldn't really be needed.. reading doesn't require
locks then, though */
return 0;
if (mail_index_refresh(index) < 0)
return -1;
}
return -1;
return 1;
}
if (ret < 0) {
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. :) */
if (ret < 0) {
return -1;
}
}
if (ret == 0)
return 0;
} else {
index->excl_lock_count++;
}
return -1;
return 1;
}
unsigned int *lock_id_r)
{
int ret;
if (ret > 0)
return 0;
if (ret < 0)
return -1;
"shared fcntl() lock for index file %s",
return -1;
}
{
const char *path;
if (fd == -1)
return -1;
return -1;
}
index->record_size) < 0) {
fd = -1;
} else {
}
return fd;
}
{
int fd, old_lock_type;
index->excl_lock_count++;
return 0;
}
/* copy the index to index.tmp and use it */
if (fd == -1)
return -1;
index->excl_lock_count++;
"unlink()");
}
index->excl_lock_count = 0;
return -1;
}
return 0;
}
unsigned int *lock_id_r)
{
int ret;
/* exclusive transaction log lock protects exclusive locking
for the main index file */
/* if header size is smaller than what we have, we'll have to recreate
the index to grow it. so don't even try regular locking. */
/* wait two seconds for exclusive lock */
if (ret > 0)
return 0;
if (ret < 0)
return -1;
}
if (mail_index_lock_exclusive_copy(index) < 0)
return -1;
return 0;
}
{
/* leave ourself shared locked. */
"file_try_lock()");
return -1;
}
}
"fsync()");
return -1;
}
return -1;
}
return 0;
}
{
/* new mapping replaces the old */
}
if (mail_index_copy(index) < 0)
}
if (mail_index_copy_lock_finish(index) < 0)
}
}
{
if ((lock_id & 1) == 0) {
/* shared lock */
/* unlocking some older generation of the index file.
we've already closed the file so just ignore this. */
return;
}
} else {
/* exclusive lock */
if (--index->excl_lock_count == 0)
}
if (!index->fcntl_locks_disable) {
"file_wait_lock()");
}
}
}
}
{
return TRUE;
}
return FALSE;
}