changeset 5854:eca7e29dce0d HEAD

Rewrite index lock handling.
author Timo Sirainen <tss@iki.fi>
date Sun, 01 Jul 2007 22:05:09 +0300
parents d9f319a9d6e0
children fd6ff4d9cab1
files 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-sync-update.c src/lib-index/mail-index-sync.c src/lib-index/mail-index-transaction.c src/lib-index/mail-index-view-private.h src/lib-index/mail-index-view-sync.c src/lib-index/mail-index-view.c src/lib-index/mail-index-write.c src/lib-index/mail-index.c src/lib-index/mail-transaction-log-file.c
diffstat 12 files changed, 116 insertions(+), 140 deletions(-) [+]
line wrap: on
line diff
--- 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 @@
 
 	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 @@
 
 		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 @@
 		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 @@
 	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 @@
 		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 @@
 	}
 
 	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 @@
 
 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;
 	}
--- 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 @@
 }
 
 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 @@
 	}
 
 	/* 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 @@
 	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 @@
 		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 @@
 }
 
 int mail_index_map(struct mail_index *index,
-		   enum mail_index_sync_handler_type type,
-		   unsigned int *lock_id_r)
+		   enum mail_index_sync_handler_type type)
 {
-	unsigned int lock_id = 0;
 	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 @@
 		   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 @@
 			   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,6 +777,8 @@
 
 	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))
@@ -788,6 +787,19 @@
 	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,
 				const struct mail_index_map *src)
 {
@@ -882,7 +894,10 @@
 	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");
--- 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 @@
 
 	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 @@
 	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 @@
 /* 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 @@
    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,
--- 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 @@
 
 	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 @@
 
 	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);
--- a/src/lib-index/mail-index-sync.c	Sun Jul 01 18:39:51 2007 +0300
+++ b/src/lib-index/mail-index-sync.c	Sun Jul 01 22:05:09 2007 +0300
@@ -25,8 +25,6 @@
 
 	uint32_t append_uid_first, append_uid_last;
 
-	unsigned int lock_id;
-
 	unsigned int sync_appends:1;
 };
 
@@ -339,7 +337,6 @@
 	struct mail_index_view *sync_view;
 	uint32_t seq;
 	uoff_t offset;
-	unsigned int lock_id = 0;
 	int ret;
 
 	if (mail_transaction_log_sync_lock(index->log, &seq, &offset) < 0)
@@ -352,15 +349,15 @@
 	   We'll update the view to contain everything that exist in the
 	   transaction log except for expunges. They're synced in
 	   mail_index_sync_commit(). */
-	if ((ret = mail_index_map(index, MAIL_INDEX_SYNC_HANDLER_HEAD,
-				  &lock_id)) <= 0) {
+	if ((ret = mail_index_map(index, MAIL_INDEX_SYNC_HANDLER_HEAD)) <= 0) {
 		if (ret == 0 || mail_index_fsck(index) <= 0) {
+			mail_index_map_unlock(index->map);
 			mail_transaction_log_sync_unlock(index->log);
 			return -1;
 		}
 		/* let's try again */
-		if (mail_index_map(index, MAIL_INDEX_SYNC_HANDLER_HEAD,
-				   &lock_id) <= 0) {
+		if (mail_index_map(index, MAIL_INDEX_SYNC_HANDLER_HEAD) <= 0) {
+			mail_index_map_unlock(index->map);
 			mail_transaction_log_sync_unlock(index->log);
 			return -1;
 		}
@@ -369,7 +366,7 @@
 
 	if (!mail_index_need_sync(index, hdr, flags,
 				  log_file_seq, log_file_offset)) {
-		mail_index_unlock(index, lock_id);
+		mail_index_map_unlock(index->map);
 		mail_transaction_log_sync_unlock(index->log);
 		return 0;
 	}
@@ -382,7 +379,7 @@
 			"broken sync positions in index file %s",
 			index->filepath);
 		if (mail_index_fsck(index) <= 0) {
-			mail_index_unlock(index, lock_id);
+			mail_index_map_unlock(index->map);
 			mail_transaction_log_sync_unlock(index->log);
 			return -1;
 		}
@@ -390,7 +387,6 @@
 
 	ctx = i_new(struct mail_index_sync_ctx, 1);
 	ctx->index = index;
-	ctx->lock_id = lock_id;
 	ctx->last_tail_seq = hdr->log_file_seq;
 	ctx->last_tail_offset = hdr->log_file_tail_offset;
 
@@ -408,7 +404,7 @@
 		   to skip over it. fix the problem with fsck and try again. */
 		mail_index_sync_rollback(&ctx);
 		if (mail_index_fsck(index) <= 0) {
-			mail_index_unlock(index, lock_id);
+			mail_index_map_unlock(index->map);
 			mail_transaction_log_sync_unlock(index->log);
 			return -1;
 		}
@@ -578,7 +574,7 @@
 
 	*_ctx = NULL;
 
-	mail_index_unlock(ctx->index, ctx->lock_id);
+	mail_index_map_unlock(ctx->index->map);
 	mail_transaction_log_sync_unlock(ctx->index->log);
 
 	mail_index_view_close(&ctx->view);
@@ -609,7 +605,6 @@
 {
         struct mail_index_sync_ctx *ctx = *_ctx;
 	struct mail_index *index = ctx->index;
-	unsigned int lock_id;
 	uint32_t seq, diff;
 	uoff_t offset;
 	bool want_rotate;
@@ -631,8 +626,7 @@
 	/* refresh the mapping with newly committed external transactions
 	   and the synced expunges. sync using file handler here so that the
 	   expunge handlers get called. */
-	if (mail_index_map(ctx->index, MAIL_INDEX_SYNC_HANDLER_FILE,
-			   &lock_id) <= 0)
+	if (mail_index_map(ctx->index, MAIL_INDEX_SYNC_HANDLER_FILE) <= 0)
 		ret = -1;
 
 	/* FIXME: create a better rule? */
--- a/src/lib-index/mail-index-transaction.c	Sun Jul 01 18:39:51 2007 +0300
+++ b/src/lib-index/mail-index-transaction.c	Sun Jul 01 22:05:09 2007 +0300
@@ -218,6 +218,8 @@
 				rec = MAIL_INDEX_MAP_IDX(view->map, *seq - 1);
 			}
 
+			/* we're using only rec->uid, no need to bother locking
+			   the index. */
 			if (rec->uid == 0) {
 				/* FIXME: replace with simple assert once we
 				   figure out why this happens.. */
@@ -258,9 +260,6 @@
 	ARRAY_TYPE(seq_array) *updates;
 	unsigned int i, count;
 
-	if (mail_index_view_lock(t->view) < 0)
-		return -1;
-
 	if (array_is_created(&t->ext_rec_updates)) {
 		updates = array_get_modifiable(&t->ext_rec_updates, &count);
 		for (i = 0; i < count; i++) {
--- a/src/lib-index/mail-index-view-private.h	Sun Jul 01 18:39:51 2007 +0300
+++ b/src/lib-index/mail-index-view-private.h	Sun Jul 01 22:05:09 2007 +0300
@@ -65,7 +65,6 @@
 	ARRAY_DEFINE(module_contexts, union mail_index_view_module_context *);
 
 	int transactions;
-	unsigned int lock_id;
 
 	unsigned int inconsistent:1;
 	/* this view was created by mail_index_sync_begin() */
@@ -75,12 +74,11 @@
 };
 
 struct mail_index_view *
-mail_index_view_open_with_map(struct mail_index_map *map);
+mail_index_view_open_with_map(struct mail_index *index,
+			      struct mail_index_map *map);
 void mail_index_view_clone(struct mail_index_view *dest,
 			   const struct mail_index_view *src);
 void mail_index_view_ref(struct mail_index_view *view);
-int mail_index_view_lock(struct mail_index_view *view);
-int mail_index_view_lock_head(struct mail_index_view *view);
 void mail_index_view_unref_maps(struct mail_index_view *view);
 void mail_index_view_add_hidden_transaction(struct mail_index_view *view,
 					    uint32_t log_file_seq,
--- a/src/lib-index/mail-index-view-sync.c	Sun Jul 01 18:39:51 2007 +0300
+++ b/src/lib-index/mail-index-view-sync.c	Sun Jul 01 22:05:09 2007 +0300
@@ -227,7 +227,7 @@
 	i_assert(!view->syncing);
 	i_assert(view->transactions == 0);
 
-	if (mail_index_view_lock_head(view) < 0)
+	if (mail_index_map_lock(view->index->map) < 0)
 		return -1;
 
 	sync_expunges = (flags & MAIL_INDEX_VIEW_SYNC_FLAG_NOEXPUNGES) == 0;
--- a/src/lib-index/mail-index-view.c	Sun Jul 01 18:39:51 2007 +0300
+++ b/src/lib-index/mail-index-view.c	Sun Jul 01 22:05:09 2007 +0300
@@ -42,7 +42,9 @@
 {
 	i_assert(view->refcount == 0);
 
-	mail_index_view_unlock(view);
+	/* we're not unlocking the view, because views could be temporarily
+	   created and closed and the current map should stay locked
+	   (especially syncing) */
 	mail_transaction_log_view_close(&view->log_view);
 
 	if (array_is_created(&view->syncs_hidden))
@@ -69,51 +71,14 @@
 }
 #endif
 
-int mail_index_view_lock_head(struct mail_index_view *view)
-{
-#ifdef DEBUG
-	mail_index_view_check_nextuid(view);
-#endif
-	if (mail_index_view_is_inconsistent(view))
-		return -1;
-	if (MAIL_INDEX_MAP_IS_IN_MEMORY(view->index->map))
-		return 0;
-
-	if (!mail_index_is_locked(view->index, view->lock_id)) {
-		if (mail_index_lock_shared(view->index, &view->lock_id) < 0) {
-			view->inconsistent = TRUE;
-			return -1;
-		}
-	}
-	return 0;
-}
-
-int mail_index_view_lock(struct mail_index_view *view)
-{
-	if (view->map != view->index->map) {
-		/* not head mapping, no need to lock */
-		if (mail_index_view_is_inconsistent(view))
-			return -1;
-
-#ifdef DEBUG
-		mail_index_view_check_nextuid(view);
-#endif
-		return 0;
-	}
-
-	return mail_index_view_lock_head(view);
-}
-
 void mail_index_view_unlock(struct mail_index_view *view)
 {
 #ifdef DEBUG
 	mail_index_view_check_nextuid(view);
 #endif
 
-	if (view->lock_id != 0 && view->transactions == 0) {
-		mail_index_unlock(view->index, view->lock_id);
-		view->lock_id = 0;
-	}
+	mail_index_map_unlock(view->map);
+	mail_index_map_unlock(view->index->map);
 }
 
 bool mail_index_view_is_inconsistent(struct mail_index_view *view)
@@ -199,7 +164,7 @@
 
 	i_assert(seq > 0 && seq <= mail_index_view_get_messages_count(view));
 
-	if (mail_index_view_lock(view) < 0)
+	if (mail_index_map_lock(view->map) < 0)
 		return -1;
 
 	/* look up the record */
@@ -218,7 +183,7 @@
 	}
 
 	/* look up the record from head mapping. it may contain some changes. */
-	if (mail_index_view_lock_head(view) < 0)
+	if (mail_index_map_lock(view->index->map) < 0)
 		return -1;
 
 	/* start looking up from the same sequence as in the old view.
@@ -265,9 +230,8 @@
 {
 	i_assert(seq > 0 && seq <= mail_index_view_get_messages_count(view));
 
-	if (mail_index_view_lock(view) < 0)
-		return -1;
-
+	/* UID lookups don't require the view to be locked. only expunges
+	   change them, and expunges will recreate the file */
 	*uid_r = MAIL_INDEX_MAP_IDX(view->map, seq-1)->uid;
 	return 0;
 }
@@ -326,9 +290,7 @@
 	i_assert(first_uid > 0);
 	i_assert(first_uid <= last_uid);
 
-	if (mail_index_view_lock(view) < 0)
-		return -1;
-
+	/* no locking needed for UIDs, see _view_lookup_uid() */
 	if (view->hdr.messages_count == 0) {
 		*first_seq_r = *last_seq_r = 0;
 		return 0;
@@ -375,9 +337,6 @@
 
 	*seq_r = 0;
 
-	if (mail_index_view_lock(view) < 0)
-		return -1;
-
 	if ((flags_mask & MAIL_RECENT) != 0 && (flags & MAIL_RECENT) != 0)
 		LOW_UPDATE(view->map->hdr.first_recent_uid_lowwater);
 	if ((flags_mask & MAIL_SEEN) != 0 && (flags & MAIL_SEEN) == 0)
@@ -398,6 +357,10 @@
 
 	i_assert(view->hdr.messages_count <= view->map->records_count);
 
+	/* we can delay locking until we're looking at the flags */
+	if (mail_index_map_lock(view->map) < 0)
+		return -1;
+
 	for (; seq <= view->hdr.messages_count; seq++) {
 		rec = MAIL_INDEX_MAP_IDX(view->map, seq-1);
 		if ((rec->flags & flags_mask) == (uint8_t)flags) {
@@ -440,15 +403,14 @@
 	const struct mail_index_ext *ext;
 	uint32_t idx;
 
-	/* if we have a mapping, the view where it's from is already locked */
 	if (map == NULL) {
 		/* no mapping given, use head mapping */
-		if (mail_index_view_lock_head(view) < 0)
-			return -1;
-
 		map = view->index->map;
 	}
 
+	if (mail_index_map_lock(map) < 0)
+		return -1;
+
 	if (!mail_index_map_get_ext_idx(map, ext_id, &idx)) {
 		/* extension doesn't exist in this index file */
 		*data_r = NULL;
@@ -472,7 +434,6 @@
 
 	i_assert(view->transactions == 0);
 
-	mail_index_view_unlock(view);
 	view->v.close(view);
 }
 
@@ -670,17 +631,18 @@
 };
 
 struct mail_index_view *
-mail_index_view_open_with_map(struct mail_index_map *map)
+mail_index_view_open_with_map(struct mail_index *index,
+			      struct mail_index_map *map)
 {
 	struct mail_index_view *view;
 
 	view = i_new(struct mail_index_view, 1);
 	view->refcount = 1;
 	view->v = view_vfuncs;
-	view->index = map->index;
-	view->log_view = mail_transaction_log_view_open(map->index->log);
+	view->index = index;
+	view->log_view = mail_transaction_log_view_open(index->log);
 
-	view->indexid = map->index->indexid;
+	view->indexid = index->indexid;
 	view->map = map;
 	view->map->refcount++;
 
@@ -698,7 +660,7 @@
 
 struct mail_index_view *mail_index_view_open(struct mail_index *index)
 {
-	return mail_index_view_open_with_map(index->map);
+	return mail_index_view_open_with_map(index, index->map);
 }
 
 const struct mail_index_ext *
--- a/src/lib-index/mail-index-write.c	Sun Jul 01 18:39:51 2007 +0300
+++ b/src/lib-index/mail-index-write.c	Sun Jul 01 22:05:09 2007 +0300
@@ -180,7 +180,7 @@
 		} else if (mail_index_has_last_changed(index)) {
 			/* changed, we can't trust updating it anymore */
 			map->write_atomic = TRUE;
-			mail_index_unlock(index, lock_id);
+			mail_index_unlock(index, &lock_id);
 		}
 	}
 
@@ -195,11 +195,11 @@
 		if (mail_index_write_map_over(index) < 0) {
 			mail_index_set_syscall_error(index, "pwrite_full()");
 			/* hopefully didn't break badly */
-			mail_index_unlock(index, lock_id);
+			mail_index_unlock(index, &lock_id);
 			mail_index_move_to_memory(index);
 			return;
 		}
-		mail_index_unlock(index, lock_id);
+		mail_index_unlock(index, &lock_id);
 	}
 
 	index->last_read_log_file_seq = hdr->log_file_seq;
--- a/src/lib-index/mail-index.c	Sun Jul 01 18:39:51 2007 +0300
+++ b/src/lib-index/mail-index.c	Sun Jul 01 22:05:09 2007 +0300
@@ -351,7 +351,6 @@
 static int
 mail_index_try_open(struct mail_index *index)
 {
-	unsigned int lock_id;
 	int ret;
 
         i_assert(index->fd == -1);
@@ -359,9 +358,9 @@
 	if (MAIL_INDEX_IS_IN_MEMORY(index))
 		return 0;
 
-	ret = mail_index_map(index, MAIL_INDEX_SYNC_HANDLER_HEAD, &lock_id);
-	mail_index_unlock(index, lock_id);
-
+	i_assert(index->map == NULL || index->map->lock_id == 0);
+	ret = mail_index_map(index, MAIL_INDEX_SYNC_HANDLER_HEAD);
+	mail_index_map_unlock(index->map);
 	if (ret == 0) {
 		/* it's corrupted - recreate it */
 		if (index->fd != -1) {
@@ -465,7 +464,7 @@
 		index->shared_lock_count = 0;
 		index->excl_lock_count = 0;
 		index->lock_type = F_UNLCK;
-		index->lock_id = 2;
+		index->lock_id_counter = 2;
 
 		index->readonly = FALSE;
 		index->nodiskspace = FALSE;
@@ -524,7 +523,7 @@
 
 	if (index->lock_type == F_RDLCK)
 		index->lock_type = F_UNLCK;
-	index->lock_id += 2;
+	index->lock_id_counter += 2;
 	index->shared_lock_count = 0;
 }
 
@@ -583,7 +582,7 @@
 
 int mail_index_refresh(struct mail_index *index)
 {
-	unsigned int lock_id;
+	bool locked = index->map->lock_id != 0;
 	int ret;
 
 	if (MAIL_INDEX_IS_IN_MEMORY(index))
@@ -595,8 +594,9 @@
 		return 0;
 	}
 
-	ret = mail_index_map(index, MAIL_INDEX_SYNC_HANDLER_HEAD, &lock_id);
-	mail_index_unlock(index, lock_id);
+	ret = mail_index_map(index, MAIL_INDEX_SYNC_HANDLER_HEAD);
+	if (!locked)
+		mail_index_map_unlock(index->map);
 	return ret <= 0 ? -1 : 0;
 }
 
--- a/src/lib-index/mail-transaction-log-file.c	Sun Jul 01 18:39:51 2007 +0300
+++ b/src/lib-index/mail-transaction-log-file.c	Sun Jul 01 22:05:09 2007 +0300
@@ -141,7 +141,7 @@
 			      struct mail_transaction_log_header *hdr)
 {
 	struct mail_index *index = log->index;
-	unsigned int lock_id = 0;
+	bool locked = index->map->lock_id != 0;
 
 	memset(hdr, 0, sizeof(*hdr));
 	hdr->major_version = MAIL_TRANSACTION_LOG_MAJOR_VERSION;
@@ -153,9 +153,11 @@
 	if (index->fd != -1) {
 		/* not creating index - make sure we have latest header */
 		if (!index->mapping) {
-			if (mail_index_map(index, MAIL_INDEX_SYNC_HANDLER_HEAD,
-					   &lock_id) <= 0)
+			if (mail_index_map(index,
+					   MAIL_INDEX_SYNC_HANDLER_HEAD) <= 0)
 				return -1;
+			if (!locked)
+				mail_index_map_unlock(index->map);
 		} else {
 			/* if we got here from mapping, the .log file is
 			   corrupted. use whatever values we got from index
@@ -170,9 +172,6 @@
 		hdr->file_seq = 1;
 	}
 
-	if (index->fd != -1)
-		mail_index_unlock(index, lock_id);
-
 	if (log->head != NULL && hdr->file_seq <= log->head->hdr.file_seq) {
 		/* make sure the sequence grows */
 		hdr->file_seq = log->head->hdr.file_seq+1;