dovecot: Rewrite index lock handling.

dovecot at dovecot.org dovecot at dovecot.org
Sun Jul 1 22:05:19 EEST 2007


details:   http://hg.dovecot.org/dovecot/rev/eca7e29dce0d
changeset: 5854:eca7e29dce0d
user:      Timo Sirainen <tss at iki.fi>
date:      Sun Jul 01 22:05:09 2007 +0300
description:
Rewrite index lock handling.

diffstat:

12 files changed, 120 insertions(+), 144 deletions(-)
src/lib-index/mail-index-lock.c           |   24 ++++---
src/lib-index/mail-index-map.c            |   49 ++++++++++-----
src/lib-index/mail-index-private.h        |   24 ++++---
src/lib-index/mail-index-sync-update.c    |    5 +
src/lib-index/mail-index-sync.c           |   24 ++-----
src/lib-index/mail-index-transaction.c    |    5 -
src/lib-index/mail-index-view-private.h   |    6 -
src/lib-index/mail-index-view-sync.c      |    2 
src/lib-index/mail-index-view.c           |   90 ++++++++---------------------
src/lib-index/mail-index-write.c          |    6 -
src/lib-index/mail-index.c                |   18 ++---
src/lib-index/mail-transaction-log-file.c |   11 +--

diffs (truncated from 778 to 300 lines):

diff -r d9f319a9d6e0 -r eca7e29dce0d src/lib-index/mail-index-lock.c
--- a/src/lib-index/mail-index-lock.c	Sun Jul 01 18:39:51 2007 +0300
+++ b/src/lib-index/mail-index-lock.c	Sun Jul 01 22:05:09 2007 +0300
@@ -42,11 +42,11 @@ static int mail_index_lock(struct mail_i
 
 	if (lock_type == F_RDLCK && index->lock_type != F_UNLCK) {
 		index->shared_lock_count++;
-		*lock_id_r = index->lock_id;
+		*lock_id_r = index->lock_id_counter;
 		ret = 1;
 	} else if (lock_type == F_WRLCK && index->lock_type == F_WRLCK) {
 		index->excl_lock_count++;
-		*lock_id_r = index->lock_id + 1;
+		*lock_id_r = index->lock_id_counter + 1;
 		ret = 1;
 	} else {
 		ret = 0;
@@ -67,7 +67,7 @@ static int mail_index_lock(struct mail_i
 
 		index->shared_lock_count++;
 		index->lock_type = F_RDLCK;
-		*lock_id_r = index->lock_id;
+		*lock_id_r = index->lock_id_counter;
 		return 1;
 	}
 
@@ -103,15 +103,15 @@ static int mail_index_lock(struct mail_i
 		return ret;
 
 	if (index->lock_type == F_UNLCK)
-		index->lock_id += 2;
+		index->lock_id_counter += 2;
 	index->lock_type = lock_type;
 
 	if (lock_type == F_RDLCK) {
 		index->shared_lock_count++;
-		*lock_id_r = index->lock_id;
+		*lock_id_r = index->lock_id_counter;
 	} else {
 		index->excl_lock_count++;
-		*lock_id_r = index->lock_id + 1;
+		*lock_id_r = index->lock_id_counter + 1;
 	}
 
 	return 1;
@@ -140,8 +140,12 @@ int mail_index_try_lock_exclusive(struct
 	return mail_index_lock(index, F_WRLCK, 0, lock_id_r);
 }
 
-void mail_index_unlock(struct mail_index *index, unsigned int lock_id)
+void mail_index_unlock(struct mail_index *index, unsigned int *_lock_id)
 {
+	unsigned int lock_id = *_lock_id;
+
+	*_lock_id = 0;
+
 	if ((lock_id & 1) == 0) {
 		/* shared lock */
 		if (!mail_index_is_locked(index, lock_id)) {
@@ -154,7 +158,7 @@ void mail_index_unlock(struct mail_index
 		index->shared_lock_count--;
 	} else {
 		/* exclusive lock */
-		i_assert(lock_id == index->lock_id + 1);
+		i_assert(lock_id == index->lock_id_counter + 1);
 		i_assert(index->excl_lock_count > 0);
 		i_assert(index->lock_type == F_WRLCK);
 		if (--index->excl_lock_count == 0 &&
@@ -166,7 +170,7 @@ void mail_index_unlock(struct mail_index
 	}
 
 	if (index->shared_lock_count == 0 && index->excl_lock_count == 0) {
-		index->lock_id += 2;
+		index->lock_id_counter += 2;
 		index->lock_type = F_UNLCK;
 		if (index->lock_method != FILE_LOCK_METHOD_DOTLOCK) {
 			if (!MAIL_INDEX_IS_IN_MEMORY(index))
@@ -178,7 +182,7 @@ void mail_index_unlock(struct mail_index
 
 bool mail_index_is_locked(struct mail_index *index, unsigned int lock_id)
 {
-	if ((index->lock_id ^ lock_id) <= 1 && lock_id != 0) {
+	if ((index->lock_id_counter ^ lock_id) <= 1 && lock_id != 0) {
 		i_assert(index->lock_type != F_UNLCK);
 		return TRUE;
 	}
diff -r d9f319a9d6e0 -r eca7e29dce0d src/lib-index/mail-index-map.c
--- a/src/lib-index/mail-index-map.c	Sun Jul 01 18:39:51 2007 +0300
+++ b/src/lib-index/mail-index-map.c	Sun Jul 01 22:05:09 2007 +0300
@@ -653,11 +653,11 @@ struct mail_index_map *mail_index_map_al
 }
 
 static int mail_index_map_latest_file(struct mail_index *index,
-				      struct mail_index_map **map,
-				      unsigned int *lock_id_r)
+				      struct mail_index_map **map)
 {
 	struct mail_index_map *new_map;
 	struct stat st;
+	unsigned int lock_id;
 	uoff_t file_size;
 	bool use_mmap;
 	int ret;
@@ -673,7 +673,7 @@ static int mail_index_map_latest_file(st
 	}
 
 	/* the index file is still open, lock it */
-	if (mail_index_lock_shared(index, lock_id_r) < 0)
+	if (mail_index_lock_shared(index, &lock_id) < 0)
 		return -1;
 
 	if (fstat(index->fd, &st) == 0)
@@ -681,6 +681,7 @@ static int mail_index_map_latest_file(st
 	else {
 		if (errno != ESTALE) {
 			mail_index_set_syscall_error(index, "fstat()");
+			mail_index_unlock(index, &lock_id);
 			return -1;
 		}
 		file_size = (uoff_t)-1;
@@ -692,8 +693,13 @@ static int mail_index_map_latest_file(st
 		file_size > MAIL_INDEX_MMAP_MIN_SIZE;
 
 	new_map = mail_index_map_alloc(index);
-	ret = use_mmap ? mail_index_mmap(new_map, file_size) :
-		mail_index_read_map(new_map, file_size);
+	if (use_mmap) {
+		new_map->lock_id = lock_id;
+		ret = mail_index_mmap(new_map, file_size);
+	} else {
+		ret = mail_index_read_map(new_map, file_size);
+		mail_index_unlock(index, &lock_id);
+	}
 	if (ret > 0) {
 		/* make sure the header is ok before using this mapping */
 		ret = mail_index_check_header(new_map);
@@ -720,16 +726,13 @@ static int mail_index_map_latest_file(st
 }
 
 int mail_index_map(struct mail_index *index,
-		   enum mail_index_sync_handler_type type,
-		   unsigned int *lock_id_r)
-{
-	unsigned int lock_id = 0;
+		   enum mail_index_sync_handler_type type)
+{
 	int ret;
 
 	i_assert(index->lock_type != F_WRLCK);
 	i_assert(!index->mapping);
 
-	*lock_id_r = 0;
 	index->mapping = TRUE;
 
 	if (index->map == NULL)
@@ -749,7 +752,7 @@ int mail_index_map(struct mail_index *in
 		   any reason, we'll fallback to updating the existing mapping
 		   from transaction logs (which we'll also do even if the
 		   reopening succeeds) */
-		(void)mail_index_map_latest_file(index, &index->map, &lock_id);
+		(void)mail_index_map_latest_file(index, &index->map);
 
 		/* if we're creating the index file, we don't have any
 		   logs yet */
@@ -758,12 +761,6 @@ int mail_index_map(struct mail_index *in
 			   transaction log */
 			ret = mail_index_sync_map(&index->map, type, TRUE);
 		}
-
-		/* we need the lock only if we didn't move the map to memory */
-		if (!MAIL_INDEX_MAP_IS_IN_MEMORY(index->map))
-			*lock_id_r = lock_id;
-		else
-			mail_index_unlock(index, lock_id);
 	}
 
 	index->mapping = FALSE;
@@ -780,12 +777,27 @@ void mail_index_unmap(struct mail_index_
 
 	i_assert(map->refcount == 0);
 	mail_index_map_clear(map);
+	mail_index_map_unlock(map);
+
 	if (map->extension_pool != NULL)
 		pool_unref(map->extension_pool);
 	if (array_is_created(&map->keyword_idx_map))
 		array_free(&map->keyword_idx_map);
 	buffer_free(map->hdr_copy_buf);
 	i_free(map);
+}
+
+int mail_index_map_lock(struct mail_index_map *map)
+{
+	if (map->lock_id != 0 || MAIL_INDEX_MAP_IS_IN_MEMORY(map))
+		return 0;
+
+	return mail_index_lock_shared(map->index, &map->lock_id);
+}
+
+void mail_index_map_unlock(struct mail_index_map *map)
+{
+	mail_index_unlock(map->index, &map->lock_id);
 }
 
 static void mail_index_map_copy(struct mail_index_map *dest,
@@ -882,7 +894,10 @@ void mail_index_map_move_to_memory(struc
 	if (map->mmap_base == NULL)
 		return;
 
+	i_assert(map->lock_id != 0);
+
 	mail_index_map_copy(map, map);
+	mail_index_map_unlock(map);
 
 	if (munmap(map->mmap_base, map->mmap_size) < 0)
 		i_error("munmap(index map) failed: %m");
diff -r d9f319a9d6e0 -r eca7e29dce0d src/lib-index/mail-index-private.h
--- a/src/lib-index/mail-index-private.h	Sun Jul 01 18:39:51 2007 +0300
+++ b/src/lib-index/mail-index-private.h	Sun Jul 01 22:05:09 2007 +0300
@@ -117,6 +117,7 @@ struct mail_index_map {
 
 	void *mmap_base;
 	size_t mmap_size, mmap_used_size;
+	unsigned int lock_id;
 
 	buffer_t *buffer;
 	buffer_t *hdr_copy_buf;
@@ -175,7 +176,7 @@ struct mail_index {
 	uoff_t fsck_log_head_file_offset;
 
 	int lock_type, shared_lock_count, excl_lock_count;
-	unsigned int lock_id;
+	unsigned int lock_id_counter;
 	enum file_lock_method lock_method;
 
 	struct file_lock *file_lock;
@@ -235,7 +236,7 @@ int mail_index_lock_shared(struct mail_i
 /* Returns 1 = ok, 0 = already locked, -1 = error. */
 int mail_index_try_lock_exclusive(struct mail_index *index,
 				  unsigned int *lock_id_r);
-void mail_index_unlock(struct mail_index *index, unsigned int lock_id);
+void mail_index_unlock(struct mail_index *index, unsigned int *lock_id);
 /* Returns TRUE if given lock_id is valid. */
 bool mail_index_is_locked(struct mail_index *index, unsigned int lock_id);
 
@@ -249,22 +250,23 @@ struct mail_index_map *mail_index_map_al
    file and/or it may read the latest changes from transaction log. The log is
    read up to EOF, but non-synced expunges are skipped.
 
-   If mapping required reading the index file, it's shared locked and lock_id
-   is returned. Otherwise returned lock_id is 0.
+   If we mmap()ed the index file, the map is returned locked.
 
    Returns 1 = ok, 0 = corrupted, -1 = error. If non-fatal problems were found,
    1 is returned but index->fsck=TRUE is set. */
 int mail_index_map(struct mail_index *index,
-		   enum mail_index_sync_handler_type type,
-		   unsigned int *lock_id_r);
-/* Return the latest index file's header. This should be used only when you
-   don't want to see later changes from transaction log.
-   Returns 1 = ok, 0 = corrupted, -1 = error. */
-int mail_index_get_last_written_header(struct mail_index *index,
-				       struct mail_index_header *hdr_r);
+		   enum mail_index_sync_handler_type type);
 /* Unreference given mapping and unmap it if it's dropped to zero. */
 void mail_index_unmap(struct mail_index_map **map);
+
+/* Lock the map if the data is mmaped and map is unlocked. */
+int mail_index_map_lock(struct mail_index_map *map);
+/* Unlock the map if it's locked. */
+void mail_index_map_unlock(struct mail_index_map *map);
+
+/* Clone a map. The returned map is always in memory. */
 struct mail_index_map *mail_index_map_clone(const struct mail_index_map *map);
+/* Move a mmaped map to memory. */
 void mail_index_map_move_to_memory(struct mail_index_map *map);
 
 uint32_t mail_index_map_lookup_ext(struct mail_index_map *map,
diff -r d9f319a9d6e0 -r eca7e29dce0d src/lib-index/mail-index-sync-update.c
--- a/src/lib-index/mail-index-sync-update.c	Sun Jul 01 18:39:51 2007 +0300
+++ b/src/lib-index/mail-index-sync-update.c	Sun Jul 01 22:05:09 2007 +0300
@@ -706,6 +706,9 @@ int mail_index_sync_map(struct mail_inde
 
 	i_assert(index->map == map || type == MAIL_INDEX_SYNC_HANDLER_VIEW);
 
+	if (mail_index_map_lock(map) < 0)
+		return -1;
+
 	if (!force) {
 		/* see if we'd prefer to reopen the index file instead of
 		   syncing the current map from the transaction log */
@@ -734,7 +737,7 @@ int mail_index_sync_map(struct mail_inde
 
 	start_offset = type == MAIL_INDEX_SYNC_HANDLER_FILE ?
 		map->hdr.log_file_tail_offset : map->hdr.log_file_head_offset;
-	view = mail_index_view_open_with_map(map);
+	view = mail_index_view_open_with_map(index, map);
 	ret = mail_transaction_log_view_set(view->log_view,
 					    map->hdr.log_file_seq, start_offset,
 					    (uint32_t)-1, (uoff_t)-1, &reset);


More information about the dovecot-cvs mailing list