summaryrefslogtreecommitdiffstats
path: root/src/lib-index/mail-index-lock.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib-index/mail-index-lock.c')
-rw-r--r--src/lib-index/mail-index-lock.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/src/lib-index/mail-index-lock.c b/src/lib-index/mail-index-lock.c
new file mode 100644
index 0000000..cdf62e4
--- /dev/null
+++ b/src/lib-index/mail-index-lock.c
@@ -0,0 +1,63 @@
+/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
+
+/*
+ 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, we'll recreate the index. That means the shared
+ lock holders can keep using the old 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 us if we're referring to a shared or an 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 "nfs-workarounds.h"
+#include "mail-index-private.h"
+
+#define MAIL_INDEX_SHARED_LOCK_TIMEOUT 120
+
+int mail_index_lock_fd(struct mail_index *index, const char *path, int fd,
+ int lock_type, unsigned int timeout_secs,
+ struct file_lock **lock_r)
+{
+ const char *error;
+ int ret;
+
+ if (fd == -1) {
+ i_assert(MAIL_INDEX_IS_IN_MEMORY(index));
+ return 1;
+ }
+
+ struct file_lock_settings lock_set = {
+ .lock_method = index->set.lock_method,
+ };
+ ret = file_wait_lock(fd, path, lock_type, &lock_set, timeout_secs,
+ lock_r, &error);
+ if (ret < 0)
+ e_error(index->event, "%s", error);
+ return ret;
+}
+
+void mail_index_flush_read_cache(struct mail_index *index, const char *path,
+ int fd, bool locked)
+{
+ if ((index->flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) == 0)
+ return;
+
+ /* Assume flock() is emulated with fcntl(), because that's how most
+ OSes work nowadays. */
+ if (locked &&
+ (index->set.lock_method == FILE_LOCK_METHOD_FCNTL ||
+ index->set.lock_method == FILE_LOCK_METHOD_FLOCK)) {
+ nfs_flush_read_cache_locked(path, fd);
+ } else {
+ nfs_flush_read_cache_unlocked(path, fd);
+ }
+}