changeset 570:2626acd3c6f4 HEAD

And more locking/syncing fixes. Now it's finally beginning to look sane again.
author Timo Sirainen <tss@iki.fi>
date Mon, 04 Nov 2002 06:47:40 +0200
parents cafe57140f5c
children 944dbdc61f3d
files src/lib-index/mail-index-open.c src/lib-index/mail-index.c src/lib-index/mail-index.h src/lib-index/mbox/mbox-rewrite.c src/lib-index/mbox/mbox-sync-full.c src/lib-index/mbox/mbox-sync.c src/lib-storage/index/index-copy.c src/lib-storage/index/index-expunge.c src/lib-storage/index/index-fetch.c src/lib-storage/index/index-status.c src/lib-storage/index/index-storage.h src/lib-storage/index/index-sync.c src/lib-storage/index/index-update-flags.c src/lib-storage/index/maildir/maildir-copy.c
diffstat 14 files changed, 112 insertions(+), 89 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-index/mail-index-open.c	Sun Nov 03 12:11:47 2002 +0200
+++ b/src/lib-index/mail-index-open.c	Mon Nov 04 06:47:40 2002 +0200
@@ -214,9 +214,17 @@
 
 	/* sync ourself - before updating cache and compression which
 	   may happen because of this. */
-	if (!index->sync_and_lock(index, MAIL_LOCK_EXCLUSIVE, NULL))
+	if (!index->sync_and_lock(index, MAIL_LOCK_SHARED, NULL))
 		return FALSE;
 
+	/* we never want to keep shared lock if syncing happens to set it.
+	   either exclusive or nothing (NOTE: drop it directly, not through
+	   index->set_lock() so mbox lock won't be affected). */
+	if (index->lock_type == MAIL_LOCK_SHARED) {
+		if (!mail_index_set_lock(index, MAIL_LOCK_UNLOCK))
+			return FALSE;
+	}
+
 	if (!fast && (index->header->flags & MAIL_INDEX_FLAG_CACHE_FIELDS)) {
 		/* need to update cached fields */
 		if (!mail_index_update_cache(index))
--- a/src/lib-index/mail-index.c	Sun Nov 03 12:11:47 2002 +0200
+++ b/src/lib-index/mail-index.c	Mon Nov 04 06:47:40 2002 +0200
@@ -339,7 +339,7 @@
 	debug_mprotect(index->mmap_base, index->mmap_full_length, index);
 
 	if (!mail_index_mmap_update(index)) {
-		(void)mail_index_set_lock(index, MAIL_LOCK_UNLOCK);
+		(void)index->set_lock(index, MAIL_LOCK_UNLOCK);
 		return FALSE;
 	}
 
@@ -377,7 +377,7 @@
 
 		if (lock_type == MAIL_LOCK_SHARED) {
 			/* drop exclusive lock */
-			return mail_index_set_lock(index, lock_type);
+			return index->set_lock(index, lock_type);
 		}
 	}
 
@@ -387,7 +387,7 @@
 		   removed. */
 		index->header->flags |= MAIL_INDEX_FLAG_FSCK;
 		if (!mail_index_fmdatasync(index, sizeof(MailIndexHeader))) {
-			(void)mail_index_set_lock(index, MAIL_LOCK_UNLOCK);
+			(void)index->set_lock(index, MAIL_LOCK_UNLOCK);
 			return FALSE;
 		}
 	}
--- a/src/lib-index/mail-index.h	Sun Nov 03 12:11:47 2002 +0200
+++ b/src/lib-index/mail-index.h	Mon Nov 04 06:47:40 2002 +0200
@@ -200,11 +200,11 @@
 	int (*fsck)(MailIndex *index);
 
 	/* Synchronize the index with the mailbox. Index must not have shared
-	   lock when calling this function. The lock_type specifies what
-	   locking state the index will be left, also locking mailbox file
-	   if needed. If changes is non-NULL, it's set to TRUE if any changes
-	   were noticed. */
-	int (*sync_and_lock)(MailIndex *index, MailLockType lock_type,
+	   lock when calling this function. The data_lock_type specifies what
+	   lock should be set to data file (mbox file). This function may
+	   leave the index in ANY locking state. If changes is non-NULL, it's
+	   set to TRUE if any changes were noticed. */
+	int (*sync_and_lock)(MailIndex *index, MailLockType data_lock_type,
 			     int *changes);
 
 	/* Returns the index header (never fails). The index needs to be
--- a/src/lib-index/mbox/mbox-rewrite.c	Sun Nov 03 12:11:47 2002 +0200
+++ b/src/lib-index/mbox/mbox-rewrite.c	Mon Nov 04 06:47:40 2002 +0200
@@ -424,7 +424,9 @@
 	tmp_fd = -1; inbuf = NULL;
 	failed = TRUE; rewrite = FALSE;
 	do {
-		/* make sync() lock the file to prevent race conditions */
+		if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
+			break;
+
 		if (!index->sync_and_lock(index, MAIL_LOCK_EXCLUSIVE, NULL))
 			break;
 
@@ -479,6 +481,13 @@
 				break;
 			}
 
+			if (offset < inbuf->v_offset) {
+				index_set_corrupted(index,
+						    "Invalid message offset");
+				failed = TRUE;
+				break;
+			}
+
 			if (offset + hdr_size + body_size > inbuf->v_size) {
 				index_set_corrupted(index,
 						    "Invalid message size");
--- a/src/lib-index/mbox/mbox-sync-full.c	Sun Nov 03 12:11:47 2002 +0200
+++ b/src/lib-index/mbox/mbox-sync-full.c	Mon Nov 04 06:47:40 2002 +0200
@@ -266,11 +266,7 @@
 	IBuffer *inbuf;
 	int failed;
 
-	if (index->lock_type == MAIL_LOCK_SHARED)
-		(void)mail_index_set_lock(index, MAIL_LOCK_UNLOCK);
-
-	if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
-		return FALSE;
+	i_assert(index->lock_type == MAIL_LOCK_EXCLUSIVE);
 
 	inbuf = mbox_get_inbuf(index, 0, MAIL_LOCK_SHARED);
 	if (inbuf == NULL)
--- a/src/lib-index/mbox/mbox-sync.c	Sun Nov 03 12:11:47 2002 +0200
+++ b/src/lib-index/mbox/mbox-sync.c	Mon Nov 04 06:47:40 2002 +0200
@@ -41,7 +41,32 @@
 	return offset;
 }
 
-int mbox_index_sync(MailIndex *index, MailLockType lock_type, int *changes)
+static int mbox_lock_and_sync_full(MailIndex *index,
+				   MailLockType data_lock_type)
+{
+        MailLockType lock_type;
+
+	/* syncing needs exclusive index lock and shared
+	   mbox lock, but if we'd want exclusive mbox lock
+	   we need to set it here already */
+	if (index->lock_type == MAIL_LOCK_SHARED)
+		(void)mail_index_set_lock(index, MAIL_LOCK_UNLOCK);
+
+	if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
+		return FALSE;
+
+	if (index->mbox_lock_type == MAIL_LOCK_UNLOCK) {
+		lock_type = data_lock_type == MAIL_LOCK_EXCLUSIVE ?
+			MAIL_LOCK_EXCLUSIVE : MAIL_LOCK_SHARED;
+		if (!mbox_lock(index, lock_type))
+			return FALSE;
+	}
+
+	return mbox_sync_full(index);
+}
+
+int mbox_index_sync(MailIndex *index, MailLockType data_lock_type,
+		    int *changes)
 {
 	struct stat st;
 	time_t index_mtime;
@@ -74,55 +99,37 @@
                 mbox_file_close_fd(index);
 	}
 
-	if (lock_type == MAIL_LOCK_EXCLUSIVE) {
-		/* if we know that we want exclusive lock, we might get
-		   it immediately to save extra lock changes */
-		if (!index->set_lock(index, MAIL_LOCK_EXCLUSIVE))
-			return FALSE;
-	}
-
 	if (index_mtime != st.st_mtime || index->mbox_size != filesize) {
 		mbox_file_close_inbuf(index);
 
-		/* problem .. index->mbox_size points to data after the last
-		   message. that should be \n or end of file. modify filesize
-		   accordingly to allow the extra byte. Don't actually bother
-		   to open the file and verify it, it'd just slow things.. */
 		index->mbox_size = get_indexed_mbox_size(index);
-		if (filesize == index->mbox_size+1)
-			index->mbox_size = filesize;
-
 		if (index->file_sync_stamp == 0 &&
-		    index->mbox_size == filesize) {
+		    index->mbox_size == filesize+1) {
 			/* just opened the mailbox, and the file size is same
 			   as we expected. don't bother checking it any
-			   further. */
+			   further. the +1 comes from the extra \n at end. */
 		} else {
 			if (changes != NULL)
 				*changes = TRUE;
 
-			/* file has changed, scan through the whole mbox */
-			if (!mbox_sync_full(index)) {
-				(void)index->set_lock(index, MAIL_LOCK_UNLOCK);
+			if (!mbox_lock_and_sync_full(index, data_lock_type))
 				return FALSE;
-			}
-
-			if (lock_type == MAIL_LOCK_EXCLUSIVE &&
-			    index->mbox_lock_type == MAIL_LOCK_SHARED) {
-				/* mbox_sync_full() left it */
-				if (!mbox_unlock(index))
-					return FALSE;
-			}
 		}
 
 		index->file_sync_stamp = st.st_mtime;
 	}
 
-	if (!index->set_lock(index, lock_type))
-		return FALSE;
+	/* we need some index lock to be able to lock mbox */
+	if (index->lock_type == MAIL_LOCK_UNLOCK) {
+		if (!index->set_lock(index, MAIL_LOCK_SHARED))
+			return FALSE;
+	}
 
-	if (lock_type != MAIL_LOCK_UNLOCK) {
-		if (!mbox_lock(index, lock_type))
+	if (data_lock_type == MAIL_LOCK_UNLOCK) {
+		if (!mbox_unlock(index))
+			return FALSE;
+	} else {
+		if (!mbox_lock(index, data_lock_type))
 			return FALSE;
 	}
 
--- a/src/lib-storage/index/index-copy.c	Sun Nov 03 12:11:47 2002 +0200
+++ b/src/lib-storage/index/index-copy.c	Mon Nov 04 06:47:40 2002 +0200
@@ -53,8 +53,8 @@
 		strcmp(destbox->name, box->name) == 0 ?
 		MAIL_LOCK_EXCLUSIVE : MAIL_LOCK_SHARED;
 
-	if (!ibox->index->sync_and_lock(ibox->index, lock_type, NULL))
-		return mail_storage_set_index_error(ibox);
+	if (!index_storage_sync_and_lock(ibox, TRUE, lock_type))
+		return FALSE;
 
 	ctx.custom_flags =
 		mail_custom_flags_list_get(ibox->index->custom_flags);
--- a/src/lib-storage/index/index-expunge.c	Sun Nov 03 12:11:47 2002 +0200
+++ b/src/lib-storage/index/index-expunge.c	Mon Nov 04 06:47:40 2002 +0200
@@ -70,13 +70,17 @@
 		return FALSE;
 	}
 
+	if (!ibox->index->set_lock(ibox->index, MAIL_LOCK_EXCLUSIVE))
+		return mail_storage_set_index_error(ibox);
+
 	if (!index_storage_sync_and_lock(ibox, FALSE, MAIL_LOCK_EXCLUSIVE))
 		return FALSE;
 
-	/* modifylog must be marked synced before expunging anything new */
-	failed = !index_storage_sync_modifylog(ibox, TRUE);
-
-	if (!failed)
+	/* modifylog must be marked synced before expunging
+	   anything new */
+	if (!index_storage_sync_modifylog(ibox, TRUE))
+		failed = TRUE;
+	else
 		failed = !ibox->expunge_locked(ibox, notify);
 
 	if (!ibox->index->set_lock(ibox->index, MAIL_LOCK_UNLOCK))
--- a/src/lib-storage/index/index-fetch.c	Sun Nov 03 12:11:47 2002 +0200
+++ b/src/lib-storage/index/index-fetch.c	Mon Nov 04 06:47:40 2002 +0200
@@ -362,21 +362,21 @@
 	}
 
 	/* need exclusive lock to update the \Seen flags */
-	if (!index_storage_sync_and_lock(ibox, TRUE, ctx.update_seen ?
-					 MAIL_LOCK_EXCLUSIVE :
-					 MAIL_LOCK_SHARED))
+	if (ctx.update_seen) {
+		if (!ibox->index->set_lock(ibox->index, MAIL_LOCK_EXCLUSIVE))
+			return mail_storage_set_index_error(ibox);
+	}
+
+	if (!index_storage_sync_and_lock(ibox, TRUE, MAIL_LOCK_SHARED))
 		return FALSE;
 
-	if (ctx.update_seen) {
+	if (ctx.update_seen &&
+	    ibox->index->header->messages_count ==
+	    ibox->index->header->seen_messages_count) {
 		/* if all messages are already seen, there's no point in
 		   keeping exclusive lock */
-		if (ibox->index->header->messages_count ==
-		    ibox->index->header->seen_messages_count) {
-			ctx.update_seen = FALSE;
-
-			(void)ibox->index->set_lock(ibox->index,
-						    MAIL_LOCK_SHARED);
-		}
+		ctx.update_seen = FALSE;
+		(void)ibox->index->set_lock(ibox->index, MAIL_LOCK_SHARED);
 	}
 
 	ctx.box = box;
--- a/src/lib-storage/index/index-status.c	Sun Nov 03 12:11:47 2002 +0200
+++ b/src/lib-storage/index/index-status.c	Mon Nov 04 06:47:40 2002 +0200
@@ -75,7 +75,7 @@
 
 	/* if we're doing STATUS for selected mailbox, we have to sync it
 	   first or STATUS reply may give different data */
-	if (!index_storage_sync_and_lock(ibox, TRUE, MAIL_LOCK_SHARED))
+	if (!index_storage_sync_and_lock(ibox, TRUE, MAIL_LOCK_UNLOCK))
 		return FALSE;
 
 	if (!index_storage_sync_modifylog(ibox, FALSE)) {
--- a/src/lib-storage/index/index-storage.h	Sun Nov 03 12:11:47 2002 +0200
+++ b/src/lib-storage/index/index-storage.h	Mon Nov 04 06:47:40 2002 +0200
@@ -38,7 +38,7 @@
 int index_storage_close(Mailbox *box);
 
 int index_storage_sync_and_lock(IndexMailbox *ibox, int sync_size,
-				MailLockType lock_type);
+				MailLockType data_lock_type);
 int index_storage_sync_modifylog(IndexMailbox *ibox, int hide_deleted);
 
 int index_mailbox_fix_custom_flags(IndexMailbox *ibox, MailFlags *flags,
--- a/src/lib-storage/index/index-sync.c	Sun Nov 03 12:11:47 2002 +0200
+++ b/src/lib-storage/index/index-sync.c	Mon Nov 04 06:47:40 2002 +0200
@@ -28,19 +28,14 @@
 }
 
 int index_storage_sync_and_lock(IndexMailbox *ibox, int sync_size,
-				MailLockType lock_type)
+				MailLockType data_lock_type)
 {
 	MailIndex *index = ibox->index;
-	int unlock, changes;
+	int changes, set_shared_lock;
 
-	if (lock_type != MAIL_LOCK_UNLOCK)
-		unlock = FALSE;
-	else {
-		unlock = TRUE;
-		lock_type = MAIL_LOCK_SHARED;
-	}
+        set_shared_lock = ibox->index->lock_type != MAIL_LOCK_EXCLUSIVE;
 
-	if (index->sync_and_lock(index, lock_type, &changes)) {
+	if (index->sync_and_lock(index, data_lock_type, &changes)) {
 		/* reset every time it has worked */
 		ibox->sent_diskspace_warning = FALSE;
 	} else {
@@ -60,12 +55,18 @@
 		index_reset_error(index);
 	}
 
+	if (set_shared_lock) {
+		/* just make sure we are locked, and that we drop our
+		   exclusive lock if it wasn't wanted originally */
+		if (!ibox->index->set_lock(ibox->index, MAIL_LOCK_SHARED)) {
+			(void)index->set_lock(index, MAIL_LOCK_UNLOCK);
+			return FALSE;
+		}
+	}
+
 	/* notify about changes in mailbox size. */
-	if (!changes) {
-		if (unlock)
-			(void)index->set_lock(index, MAIL_LOCK_UNLOCK);
+	if (!changes)
 		return TRUE; /* no changes - must be no new mail either */
-	}
 
 	if (sync_size)
 		index_storage_sync_size(ibox);
@@ -78,9 +79,6 @@
 			MAIL_CUSTOM_FLAGS_COUNT, ibox->sync_context);
 	}
 
-	if (unlock)
-		(void)index->set_lock(index, MAIL_LOCK_UNLOCK);
-
 	return TRUE;
 }
 
@@ -208,7 +206,7 @@
 	IndexMailbox *ibox = (IndexMailbox *) box;
 	int failed;
 
-	if (!index_storage_sync_and_lock(ibox, FALSE, MAIL_LOCK_SHARED))
+	if (!index_storage_sync_and_lock(ibox, FALSE, MAIL_LOCK_UNLOCK))
 		return FALSE;
 
 	if (!sync_expunges) {
@@ -218,9 +216,7 @@
 		failed = !index_storage_sync_modifylog(ibox, FALSE);
 	}
 
-	/* check size only if we're locked (== at least something changed) */
-	if (ibox->index->lock_type != MAIL_LOCK_UNLOCK)
-		index_storage_sync_size(ibox);
+	index_storage_sync_size(ibox);
 
 	if (!ibox->index->set_lock(ibox->index, MAIL_LOCK_UNLOCK))
 		return mail_storage_set_index_error(ibox);
--- a/src/lib-storage/index/index-update-flags.c	Sun Nov 03 12:11:47 2002 +0200
+++ b/src/lib-storage/index/index-update-flags.c	Mon Nov 04 06:47:40 2002 +0200
@@ -75,7 +75,10 @@
 	if (!index_mailbox_fix_custom_flags(ibox, &flags, custom_flags))
 		return FALSE;
 
-	if (!index_storage_sync_and_lock(ibox, TRUE, MAIL_LOCK_EXCLUSIVE))
+	if (!ibox->index->set_lock(ibox->index, MAIL_LOCK_EXCLUSIVE))
+		return mail_storage_set_index_error(ibox);
+
+	if (!index_storage_sync_and_lock(ibox, TRUE, MAIL_LOCK_UNLOCK))
 		return FALSE;
 
 	ctx.ibox = ibox;
--- a/src/lib-storage/index/maildir/maildir-copy.c	Sun Nov 03 12:11:47 2002 +0200
+++ b/src/lib-storage/index/maildir/maildir-copy.c	Mon Nov 04 06:47:40 2002 +0200
@@ -58,8 +58,8 @@
 	CopyHardContext ctx;
 	int ret;
 
-	if (!src->index->sync_and_lock(src->index, MAIL_LOCK_SHARED, NULL))
-		return mail_storage_set_index_error(src);
+	if (!index_storage_sync_and_lock(src, TRUE, MAIL_LOCK_SHARED))
+		return -1;
 
 	ctx.storage = src->box.storage;
 	ctx.dest = dest;