[dovecot-cvs] dovecot/src/lib-storage/index/mbox mbox-lock.c, 1.8, 1.9 mbox-sync.c, 1.42, 1.43

cras at procontrol.fi cras at procontrol.fi
Sun Jun 20 14:17:55 EEST 2004


Update of /home/cvs/dovecot/src/lib-storage/index/mbox
In directory talvi:/tmp/cvs-serv10214/lib-storage/index/mbox

Modified Files:
	mbox-lock.c mbox-sync.c 
Log Message:
Allow dropping exclusive mbox locks to shared locks.



Index: mbox-lock.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/mbox/mbox-lock.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- mbox-lock.c	20 Jun 2004 10:37:45 -0000	1.8
+++ mbox-lock.c	20 Jun 2004 11:17:53 -0000	1.9
@@ -120,6 +120,7 @@
 static void mbox_init_lock_settings(void)
 {
 	const char *str;
+	int r, w;
 
 	str = getenv("MBOX_READ_LOCKS");
 	if (str == NULL) str = DEFAULT_READ_LOCK_METHODS;
@@ -129,6 +130,21 @@
 	if (str == NULL) str = DEFAULT_WRITE_LOCK_METHODS;
 	mbox_read_lock_methods(str, "MBOX_WRITE_LOCKS", write_locks);
 
+	/* check that read/write list orders match. write_locks must contain
+	   at least read_locks and possibly more. */
+	for (r = w = 0; write_locks[w] != (enum mbox_lock_type)-1; w++) {
+		if (read_locks[r] == (enum mbox_lock_type)-1)
+			break;
+		if (read_locks[r] == write_locks[w])
+			r++;
+	}
+	if (read_locks[r] != (enum mbox_lock_type)-1) {
+		i_fatal("mbox read/write lock list settings are invalid. "
+			"Lock ordering must be the same with both, "
+			"and write locks must contain all read locks "
+			"(and possibly more)");
+	}
+
 	str = getenv("MBOX_LOCK_TIMEOUT");
 	lock_timeout = str == NULL ? DEFAULT_LOCK_TIMEOUT : atoi(str);
 
@@ -213,6 +229,9 @@
 		return 1;
 	}
 
+	if (ibox->mbox_dotlock.ino != 0)
+		return 1;
+
         ctx->dotlock_last_stale = -1;
 
 	ret = file_lock_dotlock(ibox->path, NULL, FALSE, lock_timeout,
@@ -389,22 +408,11 @@
 	return ret;
 }
 
-int mbox_lock(struct index_mailbox *ibox, int lock_type,
-	      unsigned int *lock_id_r)
+static int mbox_update_locking(struct index_mailbox *ibox, int lock_type)
 {
 	struct mbox_lock_context ctx;
 	time_t max_wait_time;
-	int ret;
-
-	/* allow only unlock -> shared/exclusive or exclusive -> shared */
-	i_assert(lock_type == F_RDLCK || lock_type == F_WRLCK);
-	i_assert(lock_type == F_RDLCK || ibox->mbox_lock_type != F_RDLCK);
-
-	if (ibox->mbox_lock_type == lock_type) {
-		ibox->mbox_locks++;
-		*lock_id_r = ibox->mbox_lock_id;
-		return 1;
-	}
+	int ret, i, drop_locks;
 
         index_storage_lock_notify_reset(ibox);
 
@@ -416,10 +424,23 @@
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.ibox = ibox;
 
+	if (ibox->mbox_lock_type == F_WRLCK) {
+		/* dropping to shared lock. first drop those that we
+		   don't remove completely. */
+		for (i = 0; i < MBOX_LOCK_COUNT; i++)
+			ctx.lock_status[i] = 1;
+		for (i = 0; read_locks[i] != (enum mbox_lock_type)-1; i++)
+			ctx.lock_status[read_locks[i]] = 0;
+		drop_locks = TRUE;
+	} else {
+		drop_locks = FALSE;
+	}
+
 	ibox->mbox_lock_type = lock_type;
-	ret = mbox_lock_list(&ctx, ibox->mbox_lock_type, max_wait_time, 0);
+	ret = mbox_lock_list(&ctx, lock_type, max_wait_time, 0);
 	if (ret <= 0) {
-                (void)mbox_unlock_files(&ctx);
+		if (!drop_locks)
+			(void)mbox_unlock_files(&ctx);
 		if (ret == 0) {
 			mail_storage_set_error(ibox->box.storage,
 				"Timeout while waiting for lock");
@@ -427,8 +448,47 @@
 		return ret;
 	}
 
-	*lock_id_r = ++ibox->mbox_lock_id;
-	ibox->mbox_locks++;
+	if (drop_locks) {
+		/* dropping to shared lock: drop the locks that are only
+		   in write list */
+		memset(ctx.lock_status, 0, sizeof(ctx.lock_status));
+		for (i = 0; write_locks[i] != (enum mbox_lock_type)-1; i++)
+			ctx.lock_status[write_locks[i]] = 1;
+		for (i = 0; read_locks[i] != (enum mbox_lock_type)-1; i++)
+			ctx.lock_status[read_locks[i]] = 0;
+
+		ibox->mbox_lock_type = F_WRLCK;
+		(void)mbox_lock_list(&ctx, F_UNLCK, 0, 0);
+		ibox->mbox_lock_type = F_RDLCK;
+	}
+
+	return 1;
+}
+
+int mbox_lock(struct index_mailbox *ibox, int lock_type,
+	      unsigned int *lock_id_r)
+{
+	int ret;
+
+	/* allow only unlock -> shared/exclusive or exclusive -> shared */
+	i_assert(lock_type == F_RDLCK || lock_type == F_WRLCK);
+	i_assert(lock_type == F_RDLCK || ibox->mbox_lock_type != F_RDLCK);
+
+	if (ibox->mbox_lock_type == F_UNLCK) {
+		ret = mbox_update_locking(ibox, lock_type);
+		if (ret <= 0)
+			return ret;
+
+		ibox->mbox_lock_id += 2;
+	}
+
+	if (lock_type == F_RDLCK) {
+		ibox->mbox_shared_locks++;
+		*lock_id_r = ibox->mbox_lock_id;
+	} else {
+		ibox->mbox_excl_locks++;
+		*lock_id_r = ibox->mbox_lock_id + 1;
+	}
 	return 1;
 }
 
@@ -442,7 +502,7 @@
 	/* make sure we don't keep mmap() between locks */
 	mbox_file_close_stream(ctx->ibox);
 
-	ctx->ibox->mbox_lock_id++;
+	ctx->ibox->mbox_lock_id += 2;
 	ctx->ibox->mbox_lock_type = F_UNLCK;
 	return ret;
 }
@@ -452,11 +512,28 @@
 	struct mbox_lock_context ctx;
 	int i;
 
-	i_assert(ibox->mbox_locks > 0);
-	i_assert(ibox->mbox_lock_id == lock_id);
+	i_assert(ibox->mbox_lock_id == (lock_id & ~1));
 
-	if (--ibox->mbox_locks > 0)
-		return 0;
+	if (lock_id & 1) {
+		/* dropping exclusive lock */
+		i_assert(ibox->mbox_excl_locks > 0);
+		if (--ibox->mbox_excl_locks > 0)
+			return 0;
+		if (ibox->mbox_shared_locks > 0) {
+			/* drop to shared lock */
+			if (mbox_update_locking(ibox, F_RDLCK) < 0)
+				return -1;
+			return 0;
+		}
+	} else {
+		/* dropping shared lock */
+		i_assert(ibox->mbox_shared_locks > 0);
+		if (--ibox->mbox_shared_locks > 0)
+			return 0;
+		if (ibox->mbox_excl_locks > 0)
+			return 0;
+	}
+	/* all locks gone */
 
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.ibox = ibox;

Index: mbox-sync.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/mbox/mbox-sync.c,v
retrieving revision 1.42
retrieving revision 1.43
diff -u -d -r1.42 -r1.43
--- mbox-sync.c	20 Jun 2004 09:23:15 -0000	1.42
+++ mbox-sync.c	20 Jun 2004 11:17:53 -0000	1.43
@@ -1159,9 +1159,22 @@
 		}
 	}
 
-	if (sync_ctx.lock_id != 0 && (ret < 0 || !lock)) {
-		/* FIXME: drop to read locking and keep it MBOX_SYNC_SECS+1
-		   to make sure we notice changes made by others */
+	if (sync_ctx.lock_id != 0 && ibox->mbox_lock_type != F_RDLCK) {
+		/* drop to read lock */
+		unsigned int lock_id = 0;
+
+		if (mbox_lock(ibox, F_RDLCK, &lock_id) <= 0)
+			ret = -1;
+		else {
+			if (mbox_unlock(ibox, sync_ctx.lock_id) < 0)
+				ret = -1;
+			sync_ctx.lock_id = lock_id;
+		}
+	}
+
+	if (sync_ctx.lock_id != 0 && !lock) {
+		/* FIXME: keep the lock MBOX_SYNC_SECS+1 to make sure we
+		   notice changes made by others */
 		if (mbox_unlock(ibox, sync_ctx.lock_id) < 0)
 			ret = -1;
 	}



More information about the dovecot-cvs mailing list