mail-index-lock.c revision a10f2e84184b91c584671cbbdcfb9330a5b48a9e
40c5626383ebd5e8cf11a636f864023a2aafcd6bDaniel Couto Vale/* Copyright (C) 2003-2004 Timo Sirainen */
7bde6e1907fc17b0083a6bcfad10bb74be6e4bcdTim Reddehase Locking should never fail or timeout. Exclusive locks must be kept as short
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller time as possible. Shared locks can be long living, so if we can't get
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller exclusive lock directly within 2 seconds, we'll replace the index file with
76e062333eb08ffc0c22578cc86ffc970c321fecTim Reddehase a copy of it. That means the shared lock holders can keep using the old file
75c2a995e5c564f96cf5559145e59f89d6435ee1Tim Reddehase while we're modifying the new file.
75c2a995e5c564f96cf5559145e59f89d6435ee1Tim Reddehase lock_id is used to figure out if acquired lock is still valid. When index
435547b6b5df0f76cd04b09532341b07d0defeb1Tim Reddehase file is reopened, the lock_id can become invalid. It doesn't matter however,
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller as no-one's going to modify the old file anymore.
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller lock_id also tells if we're referring to shared or exclusive lock. This
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller allows us to drop back to shared locking once all exclusive locks are
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger dropped. Shared locks have even numbers, exclusive locks have odd numbers.
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger The number is increased by two every time the lock is dropped or index file
435547b6b5df0f76cd04b09532341b07d0defeb1Tim Reddehaseint mail_index_lock_fd(struct mail_index *index, const char *path, int fd,
40c5626383ebd5e8cf11a636f864023a2aafcd6bDaniel Couto Vale ret = fcntl(fd, timeout_secs ? F_SETLKW : F_SETLK, &fl);
71fdc30cc6e637d99cacb455537e7b8fbfe77395henning mueller /* locked by another process */
40c5626383ebd5e8cf11a636f864023a2aafcd6bDaniel Couto Vale /* most likely alarm hit, meaning we timeouted.
a837d007b255d7a6cca7994e1e555aba95ce41cchenning mueller even if not, we probably want to be killed
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger so stop blocking. */
75c2a995e5c564f96cf5559145e59f89d6435ee1Tim Reddehase mail_index_file_set_syscall_error(index, path, "fcntl()");
75c2a995e5c564f96cf5559145e59f89d6435ee1Tim Reddehase "(see lock_method setting in config file)");
75c2a995e5c564f96cf5559145e59f89d6435ee1Tim Reddehase int operation = timeout_secs != 0 ? 0 : LOCK_NB;
2977875e15fdb6d84be990579c61cda0b6cbb5d0Tim Reddehase /* a) locked by another process,
2977875e15fdb6d84be990579c61cda0b6cbb5d0Tim Reddehase b) timeouted */
609a4ff9a0e4cb89a9f529703c81554fe9c34ff6Tim Reddehase /* Give a bit more helpful error message since this
609a4ff9a0e4cb89a9f529703c81554fe9c34ff6Tim Reddehase is the default locking method and it doesn't work
3856b7bdf70cec553e0ca01ca823c7fc555a06f0Tim Reddehase "flock() failed with file %s: %m "
3856b7bdf70cec553e0ca01ca823c7fc555a06f0Tim Reddehase "(see lock_method setting in config file)",
609a4ff9a0e4cb89a9f529703c81554fe9c34ff6Tim Reddehase mail_index_file_set_syscall_error(index, path, "flock()");
a8ab4146c3238374bdd13a36b12d665cde57e078Tim Reddehase /* we shouldn't get here */
a8ab4146c3238374bdd13a36b12d665cde57e078Tim Reddehasestatic int mail_index_lock(struct mail_index *index, int lock_type,
a8ab4146c3238374bdd13a36b12d665cde57e078Tim Reddehase unsigned int *lock_id_r)
705933deb08bc4269e8c08d50143af3cb5c1c670henning mueller i_assert(lock_type == F_RDLCK || lock_type == F_WRLCK);
881c5d2df3b2375b1ed2093781643873e424fe2cTim Reddehase if (lock_type == F_RDLCK && index->lock_type != F_UNLCK) {
aa056a2e5efb6505701a4e4a31bf2f7e71ff1738henning mueller } else if (lock_type == F_WRLCK && index->lock_type == F_WRLCK) {
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger if (update_index && index->excl_lock_count == 0) {
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger if ((ret2 = mail_index_reopen_if_needed(index)) < 0)
6116d75120b5db0bcbc4a11abed8d0254ec85b8eTim Reddehase if (index->lock_method == MAIL_INDEX_LOCK_DOTLOCK) {
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger /* FIXME: exclusive locking will rewrite the index file every
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger time. shouldn't really be needed.. reading doesn't require
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger locks then, though */
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger if (update_index && index->lock_type == F_UNLCK) {
a274d776b3371051dcdd74b598182ce113ca5135Julian Kornberger if (mail_index_reopen_if_needed(index) < 0)
2e7a48951591a6eeda9a3ab4e14cd13012cb43eaJulian Kornberger if (lock_type == F_RDLCK || !index->log_locked) {
4952c0f2ffd64062becdc4efeb38446a904d7ec1Julian Kornberger ret = mail_index_lock_fd(index, index->filepath, index->fd,
6116d75120b5db0bcbc4a11abed8d0254ec85b8eTim Reddehase /* this is kind of kludgy. we wish to avoid deadlocks while
6116d75120b5db0bcbc4a11abed8d0254ec85b8eTim Reddehase trying to lock transaction log, but it can happen if our
6116d75120b5db0bcbc4a11abed8d0254ec85b8eTim Reddehase process is holding transaction log lock and waiting for
6116d75120b5db0bcbc4a11abed8d0254ec85b8eTim Reddehase index write lock, while the other process is holding index
6116d75120b5db0bcbc4a11abed8d0254ec85b8eTim Reddehase read lock and waiting for transaction log lock.
6116d75120b5db0bcbc4a11abed8d0254ec85b8eTim Reddehase we don't have a problem with grabbing read index lock
6116d75120b5db0bcbc4a11abed8d0254ec85b8eTim Reddehase because the only way for it to block is if it's
6116d75120b5db0bcbc4a11abed8d0254ec85b8eTim Reddehase write-locked, which isn't allowed unless transaction log
6116d75120b5db0bcbc4a11abed8d0254ec85b8eTim Reddehase is also locked.
6116d75120b5db0bcbc4a11abed8d0254ec85b8eTim Reddehase so, the workaround for this problem is that we simply try
6116d75120b5db0bcbc4a11abed8d0254ec85b8eTim Reddehase locking once. if it doesn't work, just rewrite the file.
58721b9d3a8cd6a624269ddf507f80af4417c9bdhenning mueller hopefully there won't be any other deadlocking issues. :) */
lock_type, 0);
if (ret <= 0)
return ret;
unsigned int *lock_id_r)
int ret;
if (ret > 0)
if (ret < 0)
unsigned int base_size;
const char *path;
if (ret == 0) {
return fd;
/* copy the index to index.tmp and use it */
unsigned int *lock_id_r)
int ret;
if (ret > 0)
if (ret < 0)
unsigned int base_size;
int fd;
F_RDLCK, 0);
return TRUE;
return FALSE;