From d5960ce1c0adda5c9e259bc429123ebc29c60bae Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Tue, 4 May 2004 01:08:26 +0300 Subject: [PATCH] file_dotlock_open/delete/replace now has lock_suffix parameter. NULL defaults to ".lock". Fixed dotlocking transaction log. --HG-- branch : HEAD --- src/lib-index/mail-transaction-log-private.h | 4 +- src/lib-index/mail-transaction-log.c | 42 ++++++++----- .../index/maildir/maildir-uidlist.c | 8 +-- .../subscription-file/subscription-file.c | 9 +-- src/lib/file-dotlock.c | 61 ++++++++++++------- src/lib/file-dotlock.h | 8 ++- 6 files changed, 83 insertions(+), 49 deletions(-) diff --git a/src/lib-index/mail-transaction-log-private.h b/src/lib-index/mail-transaction-log-private.h index 256789e18d..d749300bee 100644 --- a/src/lib-index/mail-transaction-log-private.h +++ b/src/lib-index/mail-transaction-log-private.h @@ -13,7 +13,6 @@ struct mail_transaction_log_file { char *filepath; int fd; int lock_type; - struct dotlock dotlock; ino_t st_ino; dev_t st_dev; @@ -30,6 +29,9 @@ struct mail_transaction_log { struct mail_index *index; struct mail_transaction_log_view *views; struct mail_transaction_log_file *head, *tail; + + unsigned int dotlock_count; + struct dotlock dotlock; }; void diff --git a/src/lib-index/mail-transaction-log.c b/src/lib-index/mail-transaction-log.c index dbb7ab0beb..b6518ee32b 100644 --- a/src/lib-index/mail-transaction-log.c +++ b/src/lib-index/mail-transaction-log.c @@ -144,13 +144,16 @@ mail_transaction_log_file_dotlock(struct mail_transaction_log_file *file, int ret; if (lock_type == F_UNLCK) { - ret = file_unlock_dotlock(file->filepath, &file->dotlock); + file->lock_type = F_UNLCK; + if (--file->log->dotlock_count > 0) + return 0; + + ret = file_unlock_dotlock(file->filepath, &file->log->dotlock); if (ret < 0) { mail_index_file_set_syscall_error(file->log->index, file->filepath, "file_unlock_dotlock()"); return -1; } - file->lock_type = F_UNLCK; if (ret == 0) { mail_index_set_error(file->log->index, @@ -161,13 +164,18 @@ mail_transaction_log_file_dotlock(struct mail_transaction_log_file *file, return 0; } - ret = file_lock_dotlock(file->filepath, NULL, FALSE, - LOG_DOTLOCK_TIMEOUT, - LOG_DOTLOCK_STALE_TIMEOUT, - LOG_DOTLOCK_IMMEDIATE_STALE_TIMEOUT, - NULL, NULL, &file->dotlock); + if (file->log->dotlock_count > 0) + ret = 1; + else { + ret = file_lock_dotlock(file->filepath, NULL, FALSE, + LOG_DOTLOCK_TIMEOUT, + LOG_DOTLOCK_STALE_TIMEOUT, + LOG_DOTLOCK_IMMEDIATE_STALE_TIMEOUT, + NULL, NULL, &file->log->dotlock); + } if (ret > 0) { - file->lock_type = F_WRLCK; + file->log->dotlock_count++; + file->lock_type = F_WRLCK; return 0; } if (ret < 0) { @@ -311,12 +319,16 @@ static int mail_transaction_log_file_create(struct mail_transaction_log *log, const char *path, dev_t dev, ino_t ino) { +#define LOG_NEW_DOTLOCK_SUFFIX ".newlock" struct mail_index *index = log->index; struct mail_transaction_log_header hdr; struct stat st; int fd, fd2, ret; - fd = file_dotlock_open(path, NULL, LOG_DOTLOCK_TIMEOUT, + /* With dotlocking we might already have path.lock created, so this + filename has to be different. */ + fd = file_dotlock_open(path, NULL, LOG_NEW_DOTLOCK_SUFFIX, + LOG_DOTLOCK_TIMEOUT, LOG_DOTLOCK_STALE_TIMEOUT, LOG_DOTLOCK_IMMEDIATE_STALE_TIMEOUT, NULL, NULL); if (fd == -1) { @@ -334,7 +346,8 @@ mail_transaction_log_file_create(struct mail_transaction_log *log, } else if (st.st_dev == dev && st.st_ino == ino) { /* same file, still broken */ } else { - (void)file_dotlock_delete(path, fd2); + (void)file_dotlock_delete(path, LOG_NEW_DOTLOCK_SUFFIX, + fd2); return fd2; } @@ -364,19 +377,20 @@ mail_transaction_log_file_create(struct mail_transaction_log *log, } if (write_full(fd, &hdr, sizeof(hdr)) < 0) { - mail_index_file_set_syscall_error(index, path, "write_full()"); - (void)file_dotlock_delete(path, fd); + mail_index_file_set_syscall_error(index, path, + "write_full()"); + (void)file_dotlock_delete(path, LOG_NEW_DOTLOCK_SUFFIX, fd); return -1; } fd2 = dup(fd); if (fd2 < 0) { mail_index_file_set_syscall_error(index, path, "dup()"); - (void)file_dotlock_delete(path, fd); + (void)file_dotlock_delete(path, LOG_NEW_DOTLOCK_SUFFIX, fd); return -1; } - if (file_dotlock_replace(path, fd, FALSE) <= 0) + if (file_dotlock_replace(path, LOG_NEW_DOTLOCK_SUFFIX, fd, FALSE) <= 0) return -1; /* success */ diff --git a/src/lib-storage/index/maildir/maildir-uidlist.c b/src/lib-storage/index/maildir/maildir-uidlist.c index e15b1f6a54..0a58f2b520 100644 --- a/src/lib-storage/index/maildir/maildir-uidlist.c +++ b/src/lib-storage/index/maildir/maildir-uidlist.c @@ -77,8 +77,8 @@ int maildir_uidlist_try_lock(struct maildir_uidlist *uidlist) path = t_strconcat(uidlist->ibox->control_dir, "/" MAILDIR_UIDLIST_NAME, NULL); old_mask = umask(0777 & ~uidlist->ibox->mail_create_mode); - fd = file_dotlock_open(path, NULL, 0, 0, UIDLIST_LOCK_STALE_TIMEOUT, - NULL, NULL); + fd = file_dotlock_open(path, NULL, NULL, 0, 0, + UIDLIST_LOCK_STALE_TIMEOUT, NULL, NULL); umask(old_mask); if (fd == -1) { if (errno == EAGAIN) @@ -101,7 +101,7 @@ void maildir_uidlist_unlock(struct maildir_uidlist *uidlist) path = t_strconcat(uidlist->ibox->control_dir, "/" MAILDIR_UIDLIST_NAME, NULL); - (void)file_dotlock_delete(path, uidlist->lock_fd); + (void)file_dotlock_delete(path, NULL, uidlist->lock_fd); uidlist->lock_fd = -1; } @@ -482,7 +482,7 @@ static int maildir_uidlist_rewrite(struct maildir_uidlist *uidlist) db_path = t_strconcat(ibox->control_dir, "/" MAILDIR_UIDLIST_NAME, NULL); - if (file_dotlock_replace(db_path, uidlist->lock_fd, + if (file_dotlock_replace(db_path, NULL, uidlist->lock_fd, FALSE) <= 0) { mail_storage_set_critical(ibox->box.storage, "file_dotlock_replace(%s) failed: %m", db_path); diff --git a/src/lib-storage/subscription-file/subscription-file.c b/src/lib-storage/subscription-file/subscription-file.c index e819b3f8ad..44312e9bce 100644 --- a/src/lib-storage/subscription-file/subscription-file.c +++ b/src/lib-storage/subscription-file/subscription-file.c @@ -79,7 +79,8 @@ int subsfile_set_subscribed(struct mail_storage *storage, const char *path, name = "INBOX"; /* FIXME: set lock notification callback */ - fd_out = file_dotlock_open(path, NULL, SUBSCRIPTION_FILE_LOCK_TIMEOUT, + fd_out = file_dotlock_open(path, NULL, NULL, + SUBSCRIPTION_FILE_LOCK_TIMEOUT, SUBSCRIPTION_FILE_CHANGE_TIMEOUT, SUBSCRIPTION_FILE_IMMEDIATE_TIMEOUT, NULL, NULL); @@ -97,7 +98,7 @@ int subsfile_set_subscribed(struct mail_storage *storage, const char *path, fd_in = open(path, O_RDONLY); if (fd_in == -1 && errno != ENOENT) { subsfile_set_syscall_error(storage, "open()", path); - file_dotlock_delete(path, fd_out); + file_dotlock_delete(path, NULL, fd_out); return -1; } @@ -137,13 +138,13 @@ int subsfile_set_subscribed(struct mail_storage *storage, const char *path, o_stream_unref(output); if (failed || (set && found) || (!set && !found)) { - if (file_dotlock_delete(path, fd_out) < 0) { + if (file_dotlock_delete(path, NULL, fd_out) < 0) { subsfile_set_syscall_error(storage, "file_dotlock_delete()", path); failed = TRUE; } } else { - if (file_dotlock_replace(path, fd_out, TRUE) < 0) { + if (file_dotlock_replace(path, NULL, fd_out, TRUE) < 0) { subsfile_set_syscall_error(storage, "file_dotlock_replace()", path); failed = TRUE; diff --git a/src/lib/file-dotlock.c b/src/lib/file-dotlock.c index 75c3488bba..85cd177958 100644 --- a/src/lib/file-dotlock.c +++ b/src/lib/file-dotlock.c @@ -14,6 +14,8 @@ #include #include +#define DEFAULT_LOCK_SUFFIX ".lock" + /* 0.1 .. 0.2msec */ #define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000) @@ -244,13 +246,14 @@ static int try_create_lock(struct lock_info *lock_info, const char *temp_prefix) return 1; } -static int dotlock_create(const char *path, const char *temp_prefix, - int checkonly, int *fd, - unsigned int timeout, unsigned int stale_timeout, - unsigned int immediate_stale_timeout, - int (*callback)(unsigned int secs_left, int stale, - void *context), - void *context) +static int +dotlock_create(const char *path, const char *temp_prefix, + const char *lock_suffix, int checkonly, int *fd, + unsigned int timeout, unsigned int stale_timeout, + unsigned int immediate_stale_timeout, + int (*callback)(unsigned int secs_left, int stale, + void *context), + void *context) { const char *lock_path; struct lock_info lock_info; @@ -261,7 +264,7 @@ static int dotlock_create(const char *path, const char *temp_prefix, now = time(NULL); - lock_path = t_strconcat(path, ".lock", NULL); + lock_path = t_strconcat(path, lock_suffix, NULL); stale_notify_threshold = stale_timeout / 2; max_wait_time = now + timeout; @@ -342,11 +345,11 @@ int file_lock_dotlock(const char *path, const char *temp_prefix, int checkonly, struct stat st; int fd, ret; - lock_path = t_strconcat(path, ".lock", NULL); + lock_path = t_strconcat(path, DEFAULT_LOCK_SUFFIX, NULL); - ret = dotlock_create(path, temp_prefix, checkonly, &fd, - timeout, stale_timeout, immediate_stale_timeout, - callback, context); + ret = dotlock_create(path, temp_prefix, DEFAULT_LOCK_SUFFIX, + checkonly, &fd, timeout, stale_timeout, + immediate_stale_timeout, callback, context); if (ret <= 0 || checkonly) return ret; @@ -379,12 +382,13 @@ int file_lock_dotlock(const char *path, const char *temp_prefix, int checkonly, return 1; } -static int dotlock_delete(const char *path, const struct dotlock *dotlock) +static int dotlock_delete(const char *path, const char *lock_suffix, + const struct dotlock *dotlock) { const char *lock_path; struct stat st; - lock_path = t_strconcat(path, ".lock", NULL); + lock_path = t_strconcat(path, lock_suffix, NULL); if (lstat(lock_path, &st) < 0) { if (errno == ENOENT) { @@ -424,10 +428,11 @@ static int dotlock_delete(const char *path, const struct dotlock *dotlock) int file_unlock_dotlock(const char *path, const struct dotlock *dotlock) { - return dotlock_delete(path, dotlock); + return dotlock_delete(path, DEFAULT_LOCK_SUFFIX, dotlock); } -int file_dotlock_open(const char *path, const char *temp_prefix, +int file_dotlock_open(const char *path, + const char *temp_prefix, const char *lock_suffix, unsigned int timeout, unsigned int stale_timeout, unsigned int immediate_stale_timeout, int (*callback)(unsigned int secs_left, int stale, @@ -436,7 +441,10 @@ int file_dotlock_open(const char *path, const char *temp_prefix, { int ret, fd; - ret = dotlock_create(path, temp_prefix, FALSE, &fd, + if (lock_suffix == NULL) + lock_suffix = DEFAULT_LOCK_SUFFIX; + + ret = dotlock_create(path, temp_prefix, lock_suffix, FALSE, &fd, timeout, stale_timeout, immediate_stale_timeout, callback, context); if (ret <= 0) @@ -444,13 +452,17 @@ int file_dotlock_open(const char *path, const char *temp_prefix, return fd; } -int file_dotlock_replace(const char *path, int fd, int verify_owner) +int file_dotlock_replace(const char *path, const char *lock_suffix, + int fd, int verify_owner) { struct stat st, st2; const char *lock_path; int old_errno; - lock_path = t_strconcat(path, ".lock", NULL); + if (lock_suffix == NULL) + lock_suffix = DEFAULT_LOCK_SUFFIX; + + lock_path = t_strconcat(path, lock_suffix, NULL); if (verify_owner) { if (fstat(fd, &st) < 0) { old_errno = errno; @@ -487,16 +499,19 @@ int file_dotlock_replace(const char *path, int fd, int verify_owner) return 1; } -int file_dotlock_delete(const char *path, int fd) +int file_dotlock_delete(const char *path, const char *lock_suffix, int fd) { struct dotlock dotlock; struct stat st; int old_errno; + if (lock_suffix == NULL) + lock_suffix = DEFAULT_LOCK_SUFFIX; + if (fstat(fd, &st) < 0) { old_errno = errno; i_error("fstat(%s) failed: %m", - t_strconcat(path, ".lock", NULL)); + t_strconcat(path, lock_suffix, NULL)); (void)close(fd); errno = old_errno; return -1; @@ -504,7 +519,7 @@ int file_dotlock_delete(const char *path, int fd) if (close(fd) < 0) { i_error("close(%s) failed: %m", - t_strconcat(path, ".lock", NULL)); + t_strconcat(path, lock_suffix, NULL)); return -1; } @@ -512,5 +527,5 @@ int file_dotlock_delete(const char *path, int fd) dotlock.ino = st.st_ino; dotlock.mtime = st.st_mtime; - return dotlock_delete(path, &dotlock); + return dotlock_delete(path, lock_suffix, &dotlock); } diff --git a/src/lib/file-dotlock.h b/src/lib/file-dotlock.h index 7c13b3ee85..454efcefcb 100644 --- a/src/lib/file-dotlock.h +++ b/src/lib/file-dotlock.h @@ -40,7 +40,8 @@ int file_unlock_dotlock(const char *path, const struct dotlock *dotlock); /* Use dotlock as the new content for file. This provides read safety without locks, but not very good for large files. Returns fd for lock file. If locking timed out, returns -1 and errno = EAGAIN. */ -int file_dotlock_open(const char *path, const char *temp_prefix, +int file_dotlock_open(const char *path, + const char *temp_prefix, const char *lock_suffix, unsigned int timeout, unsigned int stale_timeout, unsigned int immediate_stale_timeout, int (*callback)(unsigned int secs_left, int stale, @@ -48,8 +49,9 @@ int file_dotlock_open(const char *path, const char *temp_prefix, void *context); /* Replaces path with path.lock file. Closes given fd. If verify_owner is TRUE, it checks that lock file hasn't been overwritten before renaming. */ -int file_dotlock_replace(const char *path, int fd, int verify_owner); +int file_dotlock_replace(const char *path, const char *lock_suffix, + int fd, int verify_owner); /* Like file_unlock_dotlock(). Closes given fd. */ -int file_dotlock_delete(const char *path, int fd); +int file_dotlock_delete(const char *path, const char *lock_suffix, int fd); #endif -- 2.47.3