changeset 5972:9fb9dc4d8df8 HEAD

Flush NFS caches when needed if MAIL_INDEX_OPEN_FLAG_NFS_FLUSH is enabled.
author Timo Sirainen <tss@iki.fi>
date Thu, 12 Jul 2007 23:55:08 +0300
parents 2bc25f61431f
children fe9da9c92cf4
files src/lib-index/mail-cache-compress.c src/lib-index/mail-cache-private.h src/lib-index/mail-cache-sync-update.c src/lib-index/mail-cache.c src/lib-index/mail-hash.c src/lib-index/mail-index-lock.c src/lib-index/mail-index-map.c src/lib-index/mail-index-private.h src/lib-index/mail-index-write.c src/lib-index/mail-index.c src/lib-index/mail-index.h src/lib-index/mail-transaction-log-file.c src/lib-index/mail-transaction-log.c src/lib-index/mailbox-list-index-sync.c src/lib-index/mailbox-list-index.c
diffstat 15 files changed, 179 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-index/mail-cache-compress.c	Thu Jul 12 23:54:34 2007 +0300
+++ b/src/lib-index/mail-cache-compress.c	Thu Jul 12 23:55:08 2007 +0300
@@ -257,6 +257,7 @@
 			return -1;
 		}
 
+		mail_cache_flush_read_cache(cache, FALSE);
 		ret = read_full(fd, &hdr, sizeof(hdr));
 		close_keep_errno(fd);
 
@@ -287,6 +288,9 @@
 	unsigned int i, count;
 	int fd, ret;
 
+	if (cache->fd != -1)
+		mail_cache_flush_read_cache(cache, TRUE);
+
 	/* get the latest info on fields */
 	if (mail_cache_header_fields_read(cache) < 0)
 		return -1;
--- a/src/lib-index/mail-cache-private.h	Thu Jul 12 23:54:34 2007 +0300
+++ b/src/lib-index/mail-cache-private.h	Thu Jul 12 23:55:08 2007 +0300
@@ -200,6 +200,7 @@
 /* Returns -1 if cache is / just got corrupted, 0 if ok. */
 int mail_cache_unlock(struct mail_cache *cache);
 
+void mail_cache_flush_read_cache(struct mail_cache *cache, bool just_locked);
 int mail_cache_write(struct mail_cache *cache, const void *data, size_t size,
 		     uoff_t offset);
 
--- a/src/lib-index/mail-cache-sync-update.c	Thu Jul 12 23:54:34 2007 +0300
+++ b/src/lib-index/mail-cache-sync-update.c	Thu Jul 12 23:55:08 2007 +0300
@@ -119,6 +119,7 @@
 		return 1;
 
 	if (cache->file_cache != NULL) {
+		mail_cache_flush_read_cache(cache, FALSE);
 		file_cache_invalidate(cache->file_cache, *new_cache_offset,
 				      (uoff_t)-1);
 	}
@@ -158,5 +159,6 @@
 
 void mail_cache_sync_lost_handler(struct mail_index *index)
 {
+	mail_cache_flush_read_cache(index->cache, FALSE);
 	file_cache_invalidate(index->cache->file_cache, 0, (uoff_t)-1);
 }
--- a/src/lib-index/mail-cache.c	Thu Jul 12 23:54:34 2007 +0300
+++ b/src/lib-index/mail-cache.c	Thu Jul 12 23:55:08 2007 +0300
@@ -77,6 +77,9 @@
 	if (cache->file_cache == NULL)
 		return;
 
+	nfs_flush_attr_cache_fd(cache->filepath, cache->fd);
+	nfs_flush_read_cache(cache->filepath, cache->fd, F_UNLCK, FALSE);
+
 	file_cache_set_fd(cache->file_cache, cache->fd);
 
 	if (fstat(cache->fd, &st) < 0)
@@ -397,19 +400,44 @@
 	i_free(cache);
 }
 
-static int mail_cache_lock_file(struct mail_cache *cache, int lock_type)
+void mail_cache_flush_read_cache(struct mail_cache *cache, bool just_locked)
 {
+	if (!cache->index->nfs_flush)
+		return;
+
+	/* Assume flock() is independent of fcntl() locks. This isn't true
+	   with Linux 2.6 NFS, but with it there's no point in using flock() */
+	if (cache->locked &&
+	    cache->index->lock_method == FILE_LOCK_METHOD_FCNTL) {
+		nfs_flush_read_cache(cache->filepath, cache->fd,
+				     F_WRLCK, just_locked);
+	} else {
+		nfs_flush_read_cache(cache->filepath, cache->fd,
+				     F_UNLCK, FALSE);
+	}
+}
+
+static int mail_cache_lock_file(struct mail_cache *cache)
+{
+	int ret;
+
 	if (cache->index->lock_method != FILE_LOCK_METHOD_DOTLOCK) {
 		i_assert(cache->file_lock == NULL);
-		return mail_index_lock_fd(cache->index, cache->filepath,
-					  cache->fd, lock_type,
-					  MAIL_INDEX_LOCK_SECS,
-					  &cache->file_lock);
+		ret = mail_index_lock_fd(cache->index, cache->filepath,
+					 cache->fd, F_WRLCK,
+					 MAIL_INDEX_LOCK_SECS,
+					 &cache->file_lock);
 	} else {
 		i_assert(cache->dotlock == NULL);
-		return file_dotlock_create(&cache->dotlock_settings,
-					   cache->filepath, 0, &cache->dotlock);
+		ret = file_dotlock_create(&cache->dotlock_settings,
+					  cache->filepath, 0, &cache->dotlock);
 	}
+
+	if (ret <= 0)
+		return ret;
+
+	mail_cache_flush_read_cache(cache, TRUE);
+	return 1;
 }
 
 static void mail_cache_unlock_file(struct mail_cache *cache)
@@ -454,7 +482,7 @@
 	}
 
 	for (i = 0; i < 3; i++) {
-		ret = mail_cache_lock_file(cache, F_WRLCK);
+		ret = mail_cache_lock_file(cache);
 		if (ret <= 0)
 			break;
 		cache->locked = TRUE;
@@ -538,6 +566,11 @@
 		mail_cache_update_need_compress(cache);
 	}
 
+	if (cache->index->nfs_flush) {
+		if (fdatasync(cache->fd) < 0)
+			mail_cache_set_syscall_error(cache, "fdatasync()");
+	}
+
 	mail_cache_unlock_file(cache);
 	return ret;
 }
--- a/src/lib-index/mail-hash.c	Thu Jul 12 23:54:34 2007 +0300
+++ b/src/lib-index/mail-hash.c	Thu Jul 12 23:55:08 2007 +0300
@@ -10,6 +10,7 @@
 #include "read-full.h"
 #include "write-full.h"
 #include "mmap-util.h"
+#include "nfs-workarounds.h"
 #include "mail-index-private.h"
 #include "mail-hash.h"
 
@@ -273,6 +274,9 @@
 		hash->mmap_size = size;
 	}
 
+	if (hash->index->nfs_flush)
+		nfs_flush_read_cache(hash->filepath, hash->fd, F_UNLCK, FALSE);
+
 	ret = pread_full(hash->fd, hash->mmap_base, size, 0);
 	if (ret < 0) {
 		mail_hash_set_syscall_error(hash, "pread_full()");
@@ -357,6 +361,9 @@
 	struct stat st;
 	size_t size;
 
+	if (hash->index->nfs_flush)
+		nfs_flush_attr_cache_fd(hash->filepath, hash->fd);
+
 	if (fstat(hash->fd, &st) < 0) {
 		mail_hash_set_syscall_error(hash, "fstat()");
 		return -1;
@@ -644,7 +651,10 @@
 	if (hash->fd == -1)
 		return mail_hash_reopen(hash);
 
-	if (stat(hash->filepath, &st) < 0) {
+	if (hash->index->nfs_flush)
+		nfs_flush_attr_cache(hash->filepath);
+
+	if (nfs_safe_stat(hash->filepath, &st) < 0) {
 		if (errno == ENOENT)
 			return mail_hash_reopen(hash);
 
--- a/src/lib-index/mail-index-lock.c	Thu Jul 12 23:54:34 2007 +0300
+++ b/src/lib-index/mail-index-lock.c	Thu Jul 12 23:55:08 2007 +0300
@@ -18,6 +18,7 @@
 */
 
 #include "lib.h"
+#include "nfs-workarounds.h"
 #include "mail-index-private.h"
 
 int mail_index_lock_fd(struct mail_index *index, const char *path, int fd,
@@ -117,13 +118,31 @@
 	return 1;
 }
 
+static void mail_index_flush_read_cache(struct mail_index *index)
+{
+	if (!index->nfs_flush)
+		return;
+
+	/* Assume flock() is independent of fcntl() locks. This isn't true
+	   with Linux 2.6 NFS, but with it there's no point in using flock() */
+	if (index->lock_method == FILE_LOCK_METHOD_FCNTL) {
+		nfs_flush_read_cache(index->filepath, index->fd,
+				     index->lock_type, TRUE);
+	} else {
+		nfs_flush_read_cache(index->filepath, index->fd,
+				     F_UNLCK, FALSE);
+	}
+}
+
 int mail_index_lock_shared(struct mail_index *index, unsigned int *lock_id_r)
 {
 	int ret;
 
 	ret = mail_index_lock(index, F_RDLCK, MAIL_INDEX_LOCK_SECS, lock_id_r);
-	if (ret > 0)
+	if (ret > 0) {
+		mail_index_flush_read_cache(index);
 		return 0;
+	}
 	if (ret < 0)
 		return -1;
 
@@ -137,7 +156,11 @@
 int mail_index_try_lock_exclusive(struct mail_index *index,
 				  unsigned int *lock_id_r)
 {
-	return mail_index_lock(index, F_WRLCK, 0, lock_id_r);
+	int ret;
+
+	if ((ret = mail_index_lock(index, F_WRLCK, 0, lock_id_r)) > 0)
+		mail_index_flush_read_cache(index);
+	return ret;
 }
 
 void mail_index_unlock(struct mail_index *index, unsigned int *_lock_id)
--- a/src/lib-index/mail-index-map.c	Thu Jul 12 23:54:34 2007 +0300
+++ b/src/lib-index/mail-index-map.c	Thu Jul 12 23:55:08 2007 +0300
@@ -678,6 +678,9 @@
 	if (mail_index_lock_shared(index, &lock_id) < 0)
 		return -1;
 
+	if (index->nfs_flush)
+		nfs_flush_attr_cache_fd(index->filepath, index->fd);
+
 	if (fstat(index->fd, &st) == 0)
 		file_size = st.st_size;
 	else {
--- a/src/lib-index/mail-index-private.h	Thu Jul 12 23:54:34 2007 +0300
+++ b/src/lib-index/mail-index-private.h	Thu Jul 12 23:55:08 2007 +0300
@@ -200,6 +200,7 @@
 	unsigned int mmap_disable:1;
 	unsigned int fsync_disable:1;
 	unsigned int use_excl_dotlocks:1;
+	unsigned int nfs_flush:1;
 	unsigned int readonly:1;
 	unsigned int fsck:1;
 	unsigned int mapping:1;
--- a/src/lib-index/mail-index-write.c	Thu Jul 12 23:54:34 2007 +0300
+++ b/src/lib-index/mail-index-write.c	Thu Jul 12 23:55:08 2007 +0300
@@ -138,6 +138,7 @@
 	const struct mail_index_header *hdr = &map->hdr;
 	struct stat st;
 	unsigned int lock_id;
+	int ret;
 
 	if (!mail_index_map_has_changed(map))
 		return;
@@ -192,14 +193,23 @@
 			}
 		}
 	} else {
-		if (mail_index_write_map_over(index) < 0) {
+		ret = mail_index_write_map_over(index);
+		if (ret < 0)
 			mail_index_set_syscall_error(index, "pwrite_full()");
+		else if (index->nfs_flush) {
+			ret = fdatasync(index->fd);
+			if (ret < 0) {
+				mail_index_set_syscall_error(index,
+							     "fdatasync()");
+			}
+		}
+		mail_index_unlock(index, &lock_id);
+
+		if (ret < 0) {
 			/* hopefully didn't break badly */
-			mail_index_unlock(index, &lock_id);
 			mail_index_move_to_memory(index);
 			return;
 		}
-		mail_index_unlock(index, &lock_id);
 	}
 
 	index->last_read_log_file_seq = hdr->log_file_seq;
--- a/src/lib-index/mail-index.c	Thu Jul 12 23:54:34 2007 +0300
+++ b/src/lib-index/mail-index.c	Thu Jul 12 23:55:08 2007 +0300
@@ -475,8 +475,21 @@
 			(flags & MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL) != 0;
 		index->fsync_disable =
 			(flags & MAIL_INDEX_OPEN_FLAG_FSYNC_DISABLE) != 0;
+		index->nfs_flush =
+			(flags & MAIL_INDEX_OPEN_FLAG_NFS_FLUSH) != 0;
 		index->lock_method = lock_method;
 
+		if (index->nfs_flush && index->fsync_disable) {
+			i_warning("nfs_flush_cache=yes requires "
+				  "fsync_disable=no, changing it");
+			index->fsync_disable = FALSE;
+		}
+		if (index->nfs_flush && !index->mmap_disable) {
+			i_warning("nfs_flush_cache=yes requires "
+				  "mmap_disable=yes, changing it");
+			index->mmap_disable = TRUE;
+		}
+
 		i_assert(!index->opened);
 		if (!mail_index_open_files(index, flags)) {
 			/* doesn't exist and create flag not used */
@@ -560,6 +573,9 @@
 		/* deleted/recreated, reopen */
 		return mail_index_try_open_only(index);
 	}
+
+	if (index->nfs_flush)
+		nfs_flush_attr_cache(index->filepath);
 	if (nfs_safe_stat(index->filepath, &st2) < 0) {
 		if (errno == ENOENT)
 			return 0;
--- a/src/lib-index/mail-index.h	Thu Jul 12 23:54:34 2007 +0300
+++ b/src/lib-index/mail-index.h	Thu Jul 12 23:55:08 2007 +0300
@@ -19,7 +19,9 @@
 	/* Rely on O_EXCL when creating dotlocks */
 	MAIL_INDEX_OPEN_FLAG_DOTLOCK_USE_EXCL	= 0x10,
 	/* Don't fsync() or fdatasync() */
-	MAIL_INDEX_OPEN_FLAG_FSYNC_DISABLE	= 0x20
+	MAIL_INDEX_OPEN_FLAG_FSYNC_DISABLE	= 0x20,
+	/* Flush NFS attr/data/write cache when necessary */
+	MAIL_INDEX_OPEN_FLAG_NFS_FLUSH		= 0x40,
 };
 
 enum mail_index_header_compat_flags {
--- a/src/lib-index/mail-transaction-log-file.c	Thu Jul 12 23:54:34 2007 +0300
+++ b/src/lib-index/mail-transaction-log-file.c	Thu Jul 12 23:55:08 2007 +0300
@@ -434,6 +434,9 @@
 	int fd, ret;
 	bool rename_existing;
 
+	if (index->nfs_flush)
+		nfs_flush_attr_cache(file->filepath);
+
 	/* log creation is locked now - see if someone already created it.
 	   note that if we're rotating, we need to keep the log locked until
 	   the file has been rewritten. and because fcntl() locks are stupid,
@@ -498,6 +501,16 @@
 		return -1;
 	}
 
+	if (index->nfs_flush) {
+		/* the header isn't important, so don't bother calling
+		   fdatasync() unless NFS is used */
+		if (fdatasync(new_fd) < 0) {
+			mail_index_file_set_syscall_error(index, file->filepath,
+							  "fdatasync()");
+			return -1;
+		}
+	}
+
 	file->fd = new_fd;
 	ret = mail_transaction_log_file_stat(file, FALSE);
 
@@ -782,7 +795,12 @@
 			}
 			return -1;
 		}
-		// FIXME: here we probably want to flush NFS data cache
+
+		if (file->log->index->nfs_flush) {
+			/* The size field will be updated soon */
+			nfs_flush_read_cache(file->filepath, file->fd,
+					     F_UNLCK, FALSE);
+		}
 	}
 
 	if (file->next != NULL &&
@@ -845,6 +863,11 @@
 
 	i_assert(file->mmap_base == NULL);
 
+	if (file->log->index->nfs_flush) {
+		/* Make sure we know the latest file size */
+		nfs_flush_attr_cache_fd(file->filepath, file->fd);
+	}
+
 	if (file->buffer != NULL && file->buffer_offset > start_offset) {
 		/* we have to insert missing data to beginning of buffer */
 		ret = mail_transaction_log_file_insert_read(file, start_offset);
--- a/src/lib-index/mail-transaction-log.c	Thu Jul 12 23:54:34 2007 +0300
+++ b/src/lib-index/mail-transaction-log.c	Thu Jul 12 23:55:08 2007 +0300
@@ -269,6 +269,8 @@
 
 	path = t_strconcat(log->index->filepath,
 			   MAIL_TRANSACTION_LOG_SUFFIX, NULL);
+	if (log->index->nfs_flush)
+		nfs_flush_attr_cache(path);
 	if (nfs_safe_stat(path, &st) < 0) {
 		if (errno != ENOENT) {
 			mail_index_file_set_syscall_error(log->index, path,
--- a/src/lib-index/mailbox-list-index-sync.c	Thu Jul 12 23:54:34 2007 +0300
+++ b/src/lib-index/mailbox-list-index-sync.c	Thu Jul 12 23:55:08 2007 +0300
@@ -336,6 +336,11 @@
 				  0) < 0)
 		return -1;
 
+	if (ctx->index->mail_index->nfs_flush) {
+		nfs_flush_read_cache(ctx->index->filepath, ctx->index->fd,
+				     F_UNLCK, FALSE);
+	}
+
 	/* we should have only external transactions in here, for which we
 	   don't need to do anything but write them to the index */
 	while (mail_index_sync_next(ctx->mail_sync_ctx, &sync_rec) > 0)
@@ -825,6 +830,18 @@
 			o_stream_send(ctx->output, &ctx->hdr, sizeof(ctx->hdr));
 		}
 
+		if (o_stream_flush(ctx->output) < 0) {
+			mailbox_list_index_set_syscall_error(ctx->index,
+							"o_stream_flush()");
+			ret = -1;
+		}
+		if (ret == 0 && ctx->index->mail_index->nfs_flush &&
+		    fdatasync(ctx->index->fd) < 0) {
+			mailbox_list_index_set_syscall_error(ctx->index,
+							     "fdatasync()");
+			ret = -1;
+		}
+
 		o_stream_destroy(&ctx->output);
 		buffer_free(ctx->output_buf);
 	}
--- a/src/lib-index/mailbox-list-index.c	Thu Jul 12 23:54:34 2007 +0300
+++ b/src/lib-index/mailbox-list-index.c	Thu Jul 12 23:55:08 2007 +0300
@@ -9,6 +9,7 @@
 #include "file-dotlock.h"
 #include "mmap-util.h"
 #include "write-full.h"
+#include "nfs-workarounds.h"
 #include "mail-index-private.h"
 #include "mailbox-list-index-private.h"
 
@@ -61,6 +62,11 @@
 
 static void mailbox_list_index_unmap(struct mailbox_list_index *index)
 {
+	if (index->mail_index->nfs_flush && index->fd != -1) {
+		nfs_flush_read_cache(index->filepath, index->fd,
+				     F_UNLCK, FALSE);
+	}
+
 	if (index->file_cache != NULL)
 		file_cache_invalidate(index->file_cache, 0, (uoff_t)-1);
 
@@ -224,7 +230,10 @@
 	if (index->fd == -1)
 		return 1;
 
-	if (stat(index->filepath, &st1) < 0) {
+	if (index->mail_index->nfs_flush)
+		nfs_flush_attr_cache(index->filepath);
+
+	if (nfs_safe_stat(index->filepath, &st1) < 0) {
 		if (errno == ENOENT)
 			return 1;
 
@@ -272,6 +281,12 @@
 		return -1;
 	}
 
+	if (index->mail_index->nfs_flush && fdatasync(fd) < 0) {
+		mailbox_list_index_set_syscall_error(index, "fdatasync()");
+		(void)file_dotlock_delete(&dotlock);
+		return -1;
+	}
+
 	if (file_dotlock_replace(&dotlock,
 				 DOTLOCK_REPLACE_FLAG_DONT_CLOSE_FD) < 0) {
 		mailbox_list_index_set_syscall_error(index,