Mercurial > dovecot > original-hg > dovecot-1.2
view src/lib-index/mbox/mbox-lock.c @ 373:5d2298649157 HEAD
dotlock fixes: don't delete dotlock when we didn't create it (when removing
a shared lock). if mbox file hasn't been changed for 5 seconds, assume stale
lock file.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 06 Oct 2002 14:35:13 +0300 |
parents | 9b36fc3c1385 |
children | 83da62e0675a |
line wrap: on
line source
/* Copyright (C) 2002 Timo Sirainen */ #include "lib.h" #include "mbox-index.h" #include "mbox-lock.h" #include "mail-index-util.h" #include <time.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> #ifdef HAVE_FLOCK # include <sys/file.h> #endif /* 0.1 .. 0.2msec */ #define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000) /* assume stale dotlock if mbox file hasn't changed for 5 seconds */ #define MAX_UNCHANGED_LOCK_WAIT 5 /* abort trying to get lock after 30 seconds */ #define MAX_LOCK_WAIT 30 /* remove lock after 10 mins */ #define STALE_LOCK_TIMEOUT (60*10) #ifdef HAVE_FLOCK static int mbox_lock_flock(MailIndex *index, int lock_type) { if (lock_type == F_WRLCK) lock_type = LOCK_EX; else if (lock_type == F_RDLCK) lock_type = LOCK_SH; else lock_type = LOCK_UN; if (flock(index->mbox_fd, lock_type) < 0) return index_file_set_syscall_error(index, index->mbox_path, "flock()"); return TRUE; } #endif static int mbox_lock_fcntl(MailIndex *index, int lock_type) { struct flock fl; fl.l_type = lock_type; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; while (fcntl(index->mbox_fd, F_SETLKW, &fl) == -1) { if (errno != EINTR) { index_file_set_syscall_error(index, index->mbox_path, "fcntl()"); return FALSE; } } return TRUE; } static int mbox_lock_dotlock(MailIndex *index, const char *path, int set) { struct stat st; time_t now, max_wait_time, last_change, last_mtime; off_t last_size; int fd; path = t_strconcat(path, ".lock", NULL); if (!set) { if (unlink(path) == 0 || errno == ENOENT) return TRUE; return index_file_set_syscall_error(index, path, "unlink()"); } /* don't bother with the temp files as we'd just leave them lying around. besides, postfix also relies on O_EXCL working so we might as well. */ max_wait_time = time(NULL) + MAX_LOCK_WAIT; last_change = time(NULL); last_size = 0; last_mtime = 0; do { now = time(NULL); if (stat(path, &st) == 0) { /* lock exists, see if it's too old */ if (now > st.st_ctime + STALE_LOCK_TIMEOUT) { if (unlink(path) < 0 && errno != ENOENT) { index_file_set_syscall_error( index, path, "unlink()"); break; } continue; } /* see if there's been any changes in mbox */ if (stat(index->mbox_path, &st) < 0) { mbox_set_syscall_error(index, "stat()"); break; } if (last_size != st.st_size || last_mtime != st.st_mtime) { last_change = now; last_size = st.st_size; last_mtime = st.st_mtime; } if (now > last_change + MAX_UNCHANGED_LOCK_WAIT) { /* no changes for a while, assume stale lock */ if (unlink(path) < 0 && errno != ENOENT) { index_file_set_syscall_error( index, path, "unlink()"); break; } continue; } usleep(LOCK_RANDOM_USLEEP_TIME); continue; } fd = open(path, O_WRONLY | O_EXCL | O_CREAT, 0); if (fd != -1) { /* got it */ if (close(fd) < 0) { index_file_set_syscall_error(index, path, "close()"); } return TRUE; } if (errno != EEXIST) { index_file_set_syscall_error(index, path, "open()"); return FALSE; } } while (now < max_wait_time); index_set_error(index, "Timeout while waiting for release of mbox " "dotlock %s", path); return FALSE; } static int mbox_lock(MailIndex *index, int exclusive) { i_assert(index->mbox_fd != -1); if (++index->mbox_locks > 1) return TRUE; index->mbox_lock_type = exclusive ? F_WRLCK : F_RDLCK; if (!mbox_lock_fcntl(index, index->mbox_lock_type)) { (void)mbox_lock_dotlock(index, index->mbox_path, FALSE); return FALSE; } #ifdef HAVE_FLOCK if (!mbox_lock_flock(index, index->mbox_lock_type)) { (void)mbox_lock_dotlock(index, index->mbox_path, FALSE); return FALSE; } #endif if (exclusive) { if (!mbox_lock_dotlock(index, index->mbox_path, TRUE)) return FALSE; } return TRUE; } int mbox_lock_read(MailIndex *index) { return mbox_lock(index, FALSE); } int mbox_lock_write(MailIndex *index) { i_assert(index->mbox_locks == 0 || index->mbox_lock_type != F_RDLCK); return mbox_lock(index, TRUE); } int mbox_unlock(MailIndex *index) { int failed; i_assert(index->mbox_fd != -1); i_assert(index->mbox_locks > 0); if (--index->mbox_locks > 0) return TRUE; failed = FALSE; #ifdef HAVE_FLOCK if (!mbox_lock_flock(index, F_UNLCK)) failed = TRUE; #endif if (!mbox_lock_fcntl(index, F_UNLCK)) failed = TRUE; if (index->mbox_lock_type == F_WRLCK) { if (!mbox_lock_dotlock(index, index->mbox_path, FALSE)) failed = TRUE; } return !failed; }