changeset 1974:d85f71ffeb8f HEAD

file_dotlock_open/delete/replace now has lock_suffix parameter. NULL defaults to ".lock". Fixed dotlocking transaction log.
author Timo Sirainen <tss@iki.fi>
date Tue, 04 May 2004 01:08:26 +0300
parents f6d2dba3b78b
children be0269b8e2d4
files src/lib-index/mail-transaction-log-private.h src/lib-index/mail-transaction-log.c src/lib-storage/index/maildir/maildir-uidlist.c src/lib-storage/subscription-file/subscription-file.c src/lib/file-dotlock.c src/lib/file-dotlock.h
diffstat 6 files changed, 83 insertions(+), 49 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-index/mail-transaction-log-private.h	Tue May 04 00:08:04 2004 +0300
+++ b/src/lib-index/mail-transaction-log-private.h	Tue May 04 01:08:26 2004 +0300
@@ -13,7 +13,6 @@
 	char *filepath;
 	int fd;
 	int lock_type;
-	struct dotlock dotlock;
 
 	ino_t st_ino;
 	dev_t st_dev;
@@ -30,6 +29,9 @@
 	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
--- a/src/lib-index/mail-transaction-log.c	Tue May 04 00:08:04 2004 +0300
+++ b/src/lib-index/mail-transaction-log.c	Tue May 04 01:08:26 2004 +0300
@@ -144,13 +144,16 @@
 	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 @@
 		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 @@
 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 @@
 		} 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 @@
 	}
 
 	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 */
--- a/src/lib-storage/index/maildir/maildir-uidlist.c	Tue May 04 00:08:04 2004 +0300
+++ b/src/lib-storage/index/maildir/maildir-uidlist.c	Tue May 04 01:08:26 2004 +0300
@@ -77,8 +77,8 @@
 	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 @@
 
 	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 @@
 		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);
--- a/src/lib-storage/subscription-file/subscription-file.c	Tue May 04 00:08:04 2004 +0300
+++ b/src/lib-storage/subscription-file/subscription-file.c	Tue May 04 01:08:26 2004 +0300
@@ -79,7 +79,8 @@
 		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 @@
 	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 @@
 	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;
--- a/src/lib/file-dotlock.c	Tue May 04 00:08:04 2004 +0300
+++ b/src/lib/file-dotlock.c	Tue May 04 01:08:26 2004 +0300
@@ -14,6 +14,8 @@
 #include <time.h>
 #include <sys/stat.h>
 
+#define DEFAULT_LOCK_SUFFIX ".lock"
+
 /* 0.1 .. 0.2msec */
 #define LOCK_RANDOM_USLEEP_TIME (100000 + (unsigned int)rand() % 100000)
 
@@ -244,13 +246,14 @@
 	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 @@
 
 	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 @@
 	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 @@
 	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 @@
 
 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 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 @@
 	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 @@
 	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 @@
 
 	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 @@
 	dotlock.ino = st.st_ino;
 	dotlock.mtime = st.st_mtime;
 
-	return dotlock_delete(path, &dotlock);
+	return dotlock_delete(path, lock_suffix, &dotlock);
 }
--- a/src/lib/file-dotlock.h	Tue May 04 00:08:04 2004 +0300
+++ b/src/lib/file-dotlock.h	Tue May 04 01:08:26 2004 +0300
@@ -40,7 +40,8 @@
 /* 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 @@
 		      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