Mercurial > dovecot > core-2.2
view src/lib-index/mail-lockdir.c @ 903:fd8888f6f037 HEAD
Naming style changes, finally got tired of most of the typedefs. Also the
previous enum -> macro change reverted so that we don't use the highest bit
anymore, that's incompatible with old indexes so they will be rebuilt.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sun, 05 Jan 2003 15:09:51 +0200 |
parents | 41dde6822eea |
children |
line wrap: on
line source
/* Copyright (C) 2002 Timo Sirainen */ #include "lib.h" #include "hostpid.h" #include "unlink-lockfiles.h" #include "mail-index.h" #include "mail-index-util.h" #include "mail-lockdir.h" #include <time.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/stat.h> #define DIRLOCK_FILE_PREFIX ".imap.dirlock" /* 0.1 .. 0.2msec */ #define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000) /* The dirlock should be used only while creating the index file. After the header is written, the file itself should be locked and dirlock dropped before index is built. So, this value shouldn't be very large, probably even a few seconds would more than enough but we'll use a safe 10 seconds by default. */ #define MAX_LOCK_WAIT_SECONDS 10 /* Non-local locks have a life time of 30 minutes, just to be sure that small clock differences won't break things. */ #define NFS_LOCK_TIMEOUT (60*30) static int mail_index_cleanup_dir_locks(const char *dir) { const char *hostprefix, *path; struct stat st; hostprefix = t_strconcat(DIRLOCK_FILE_PREFIX ".", my_hostname, ".", NULL); unlink_lockfiles(dir, hostprefix, DIRLOCK_FILE_PREFIX ".", time(NULL) - NFS_LOCK_TIMEOUT); /* if hard link count has dropped to 1, we've unlocked the file */ path = t_strconcat(dir, "/" DIRLOCK_FILE_PREFIX, NULL); if (stat(path, &st) == 0 && st.st_nlink == 1) { /* only itself, safe to delete */ (void)unlink(path); return TRUE; } return FALSE; } static int mail_index_unlock_dir(struct mail_index *index, const char *private_path, const char *lockpath) { struct stat st, lockst; if (stat(lockpath, &st) < 0) return index_file_set_syscall_error(index, lockpath, "stat()"); if (st.st_nlink > 1) { /* make sure we're really the one who's locked it */ if (stat(private_path, &lockst) < 0) { return index_file_set_syscall_error(index, private_path, "stat()"); } if (st.st_dev != lockst.st_dev || st.st_ino != lockst.st_ino) { index_set_error(index, "Unlocking file %s failed: " "we're not the lock owner " "(%lu,%lu vs %lu,%lu)", lockpath, (unsigned long) st.st_dev, (unsigned long) st.st_ino, (unsigned long) lockst.st_dev, (unsigned long) lockst.st_ino); return FALSE; } } /* first unlink the actual lock file */ if (unlink(lockpath) < 0) { index_file_set_syscall_error(index, lockpath, "unlink()"); return FALSE; } if (unlink(private_path) < 0) { /* non-fatal */ index_file_set_syscall_error(index, private_path, "unlink()"); } return TRUE; } int mail_index_lock_dir(struct mail_index *index, enum mail_lock_type lock_type) { struct stat st; const char *private_path, *lockpath; int fd, orig_errno, first; time_t max_wait_time; i_assert(lock_type == MAIL_LOCK_EXCLUSIVE || lock_type == MAIL_LOCK_UNLOCK); hostpid_init(); /* use .dirlock.host.pid as our lock indicator file and .dirlock as the real lock */ private_path = t_strconcat(index->dir, "/" DIRLOCK_FILE_PREFIX ".", my_hostname, ".", my_pid, NULL); lockpath = t_strconcat(index->dir, "/" DIRLOCK_FILE_PREFIX, NULL); if (lock_type == MAIL_LOCK_UNLOCK) return mail_index_unlock_dir(index, private_path, lockpath); (void)unlink(private_path); fd = open(private_path, O_RDWR | O_CREAT | O_EXCL, 0660); if (fd == -1) { if (errno == ENOSPC) index->nodiskspace = TRUE; index_file_set_syscall_error(index, private_path, "open()"); return FALSE; } /* try to link the file into lock file. */ first = TRUE; max_wait_time = time(NULL) + MAX_LOCK_WAIT_SECONDS; while (link(private_path, lockpath) < 0) { if (errno == ENOSPC) index->nodiskspace = TRUE; if (errno != EEXIST) { orig_errno = errno; /* NFS may die and link() fail even if it really was created */ if (stat(private_path, &st) == 0 && st.st_nlink == 2) break; errno = orig_errno; index_set_error(index, "link(%s, %s) lock failed: %m", private_path, lockpath); return FALSE; } if (first) { /* cleanup lock files once */ first = FALSE; if (mail_index_cleanup_dir_locks(index->dir)) continue; /* lock was deleted, try again */ } if (time(NULL) > max_wait_time) { index_set_error(index, "Timeout waiting for lock in directory %s", index->dir); return FALSE; } usleep(LOCK_RANDOM_USLEEP_TIME); } return TRUE; }