[dovecot-cvs] dovecot/src/lib-storage/index index-messageset.c,1.19,1.20 index-messageset.h,1.7,1.8 index-search.c,1.80,1.81

cras at procontrol.fi cras at procontrol.fi
Sun Oct 26 21:41:12 EET 2003


Update of /home/cvs/dovecot/src/lib-storage/index
In directory danu:/tmp/cvs-serv5094/index

Modified Files:
	index-messageset.c index-messageset.h index-search.c 
Log Message:
Some optimizations to messageset handling in search.



Index: index-messageset.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/index-messageset.c,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -d -r1.19 -r1.20
--- index-messageset.c	24 Aug 2003 10:49:15 -0000	1.19
+++ index-messageset.c	26 Oct 2003 19:41:10 -0000	1.20
@@ -17,6 +17,7 @@
 	struct messageset_mail mail;
 	unsigned int messages_count;
 	unsigned int num1, num2;
+	unsigned int min_uid, max_uid;
 
 	const char *messageset, *p;
 	int uidset, skip_expunged;
@@ -44,6 +45,9 @@
 	ctx->uidset = uidset;
 	ctx->skip_expunged = skip_expunged;
 
+	ctx->min_uid = 1;
+	ctx->max_uid = (unsigned int)-1;
+
 	/* Reset index errors, we rely on it to check for failures */
 	index_reset_error(ctx->index);
 
@@ -67,6 +71,13 @@
 	return ctx;
 }
 
+void index_messageset_limit_range(struct messageset_context *ctx,
+				  unsigned int min_uid, unsigned int max_uid)
+{
+	ctx->min_uid = min_uid;
+	ctx->max_uid = max_uid;
+}
+
 int index_messageset_deinit(struct messageset_context *ctx)
 {
 	int ret = ctx->ret;
@@ -220,6 +231,14 @@
 			ctx->num2 = temp;
 		}
 	}
+	i_assert(ctx->num1 <= ctx->num2);
+
+	if (ctx->num1 < ctx->min_uid)
+		ctx->num1 = ctx->min_uid;
+	if (ctx->num2 > ctx->max_uid)
+		ctx->num2 = ctx->max_uid;
+	if (ctx->num1 > ctx->num2)
+		return 1;
 
 	/* get list of expunged messages in our range. */
 	ctx->expunges = mail_modifylog_uid_get_expunges(ctx->index->modifylog,
@@ -269,13 +288,24 @@
 	/* get the first non-expunged message. note that if all messages
 	   were expunged in the range, this points outside wanted range. */
 	ctx->mail.idx_seq = ctx->num1 - expunges_before;
+	ctx->mail.client_seq = ctx->num1;
 	ctx->mail.rec = ctx->index->lookup(ctx->index, ctx->mail.idx_seq);
+	while (ctx->mail.rec != NULL && ctx->mail.rec->uid < ctx->min_uid) {
+		ctx->mail.idx_seq++;
+		ctx->mail.client_seq++;
+		ctx->mail.rec = ctx->index->next(ctx->index, ctx->mail.rec);
+	}
+
+	if (ctx->mail.rec != NULL && ctx->mail.rec->uid > ctx->max_uid) {
+		ctx->mail.rec = NULL;
+		return 1;
+	}
+
 	if (ctx->mail.rec == NULL) {
 		return ctx->index->get_last_error(ctx->index) ==
 			MAIL_INDEX_ERROR_NONE ? 1 : -1;
 	}
 
-	ctx->mail.client_seq = ctx->num1;
 	return 0;
 }
 

Index: index-messageset.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/index-messageset.h,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- index-messageset.h	22 Jan 2003 19:23:28 -0000	1.7
+++ index-messageset.h	26 Oct 2003 19:41:10 -0000	1.8
@@ -19,6 +19,9 @@
 index_messageset_init_range(struct index_mailbox *ibox,
 			    unsigned int num1, unsigned int num2, int uidset);
 
+void index_messageset_limit_range(struct messageset_context *ctx,
+				  unsigned int min_uid, unsigned int max_uid);
+
 /* Returns 1 if all were found, 0 if some messages were expunged,
    -1 if internal error occured or -2 if messageset was invalid. */
 int index_messageset_deinit(struct messageset_context *ctx);

Index: index-search.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/index-search.c,v
retrieving revision 1.80
retrieving revision 1.81
diff -u -d -r1.80 -r1.81
--- index-search.c	21 Sep 2003 16:21:38 -0000	1.80
+++ index-search.c	26 Oct 2003 19:41:10 -0000	1.81
@@ -611,21 +611,32 @@
 	return TRUE;
 }
 
-static int search_get_sequid(struct index_mailbox *ibox,
-			     const struct mail_search_arg *args,
-			     unsigned int *first_seq, unsigned int *last_seq,
-			     unsigned int *first_uid, unsigned int *last_uid)
+struct search_msgset_context {
+	struct index_mailbox *ibox;
+
+	unsigned int first_seq, last_seq;
+	unsigned int first_uid, last_uid;
+
+	struct mail_search_arg *msgset_arg;
+	unsigned int msgset_arg_count;
+};
+
+static int search_parse_msgset_args(struct search_msgset_context *ctx,
+				    struct mail_search_arg *args)
 {
+	struct index_mailbox *ibox = ctx->ibox;
+
 	for (; args != NULL; args = args->next) {
 		/* FIXME: we don't check if OR condition can limit the range.
 		   It's a bit tricky and unlikely to affect performance much. */
 		if (args->type == SEARCH_SUB) {
-			if (!search_get_sequid(ibox, args->value.subargs,
-					       first_seq, last_seq,
-					       first_uid, last_uid))
+			if (!search_parse_msgset_args(ctx, args->value.subargs))
 				return FALSE;
 		} else if (args->type == SEARCH_SET) {
-			if (!seq_update(args->value.str, first_seq, last_seq,
+			ctx->msgset_arg = args;
+			ctx->msgset_arg_count++;
+			if (!seq_update(args->value.str,
+					&ctx->first_seq, &ctx->last_seq,
 					ibox->synced_messages_count)) {
 				mail_storage_set_syntax_error(ibox->box.storage,
 					"Invalid messageset: %s",
@@ -633,7 +644,10 @@
 				return FALSE;
 			}
 		} else if (args->type == SEARCH_UID) {
-			if (!seq_update(args->value.str, first_uid, last_uid,
+			ctx->msgset_arg = args;
+			ctx->msgset_arg_count++;
+			if (!seq_update(args->value.str,
+					&ctx->first_uid, &ctx->last_uid,
 					ibox->index->header->next_uid-1)) {
 				mail_storage_set_syntax_error(ibox->box.storage,
 					"Invalid messageset: %s",
@@ -642,8 +656,9 @@
 			}
 		} else if (args->type == SEARCH_ALL) {
 			/* go through everything */
-			*first_seq = 1;
-			*last_seq = ibox->synced_messages_count;
+			ctx->first_seq = 1;
+			ctx->last_seq = ibox->synced_messages_count;
+			ctx->msgset_arg_count++;
 			return TRUE;
 		}
 	}
@@ -652,7 +667,7 @@
 }
 
 static int search_limit_by_flags(struct index_mailbox *ibox,
-				 const struct mail_search_arg *args,
+				 struct mail_search_arg *args,
 				 unsigned int *first_uid,
 				 unsigned int *last_uid)
 {
@@ -666,15 +681,19 @@
 			if (!args->not && hdr->seen_messages_count == 0)
 				return FALSE;
 
-			/* UNSEEN with all seen? */
-			if (args->not &&
-			    hdr->seen_messages_count == hdr->messages_count)
-				return FALSE;
+			if (hdr->seen_messages_count == hdr->messages_count) {
+				/* UNSEEN with all seen? */
+				if (args->not)
+					return FALSE;
 
-			/* UNSEEN with lowwater limiting */
-			uid = hdr->first_unseen_uid_lowwater;
-			if (args->not && *first_uid < uid)
-				*first_uid = uid;
+				/* SEEN with all seen */
+				args->match_always = TRUE;
+			} else {
+				/* UNSEEN with lowwater limiting */
+				uid = hdr->first_unseen_uid_lowwater;
+				if (args->not && *first_uid < uid)
+					*first_uid = uid;
+			}
 		}
 
 		if (args->type == SEARCH_DELETED) {
@@ -682,15 +701,20 @@
 			if (!args->not && hdr->deleted_messages_count == 0)
 				return FALSE;
 
-			/* UNDELETED with all deleted? */
-			if (args->not &&
-			    hdr->deleted_messages_count == hdr->messages_count)
-				return FALSE;
+			if (hdr->deleted_messages_count ==
+			    hdr->messages_count) {
+				/* UNDELETED with all deleted? */
+				if (args->not)
+					return FALSE;
 
-			/* DELETED with lowwater limiting */
-			uid = hdr->first_deleted_uid_lowwater;
-			if (!args->not && *first_uid < uid)
-				*first_uid = uid;
+				/* DELETED with all deleted */
+				args->match_always = TRUE;
+			} else {
+				/* DELETED with lowwater limiting */
+				uid = hdr->first_deleted_uid_lowwater;
+				if (!args->not && *first_uid < uid)
+					*first_uid = uid;
+			}
 		}
 
 		if (args->type == SEARCH_RECENT) {
@@ -728,53 +752,67 @@
 	return TRUE;
 }
 
-static int search_get_uid_range(struct index_mailbox *ibox,
-				const struct mail_search_arg *args,
-				unsigned int *first_uid, unsigned int *last_uid)
+static int search_get_msgset(struct index_mailbox *ibox,
+			     struct mail_search_arg *args,
+			     struct messageset_context **msgset_r)
 {
-	unsigned int first_seq, last_seq, uid;
+        struct search_msgset_context ctx;
+	unsigned int uid;
 
-	*first_uid = *last_uid = 0;
-	first_seq = last_seq = 0;
+	memset(&ctx, 0, sizeof(ctx));
+	ctx.ibox = ibox;
 
-	if (!search_get_sequid(ibox, args, &first_seq, &last_seq,
-			       first_uid, last_uid))
+	if (!search_parse_msgset_args(&ctx, args))
 		return -1;
 
 	/* seq_update() should make sure that these can't happen */
-	i_assert(first_seq <= last_seq);
-	i_assert(*first_uid <= *last_uid);
+	i_assert(ctx.first_seq <= ctx.last_seq);
+	i_assert(ctx.first_uid <= ctx.last_uid);
 
-	if (first_seq > 1) {
-		if (!client_seq_to_uid(ibox, first_seq, &uid))
+	if (ctx.first_seq > 1) {
+		if (!client_seq_to_uid(ibox, ctx.first_seq, &uid))
 			return -1;
 		if (uid == 0)
 			return 0;
 
-		if (*first_uid == 0 || uid < *first_uid)
-			*first_uid = uid;
+		if (ctx.first_uid == 0 || uid < ctx.first_uid)
+			ctx.first_uid = uid;
 	}
 
-	if (last_seq > 1 && last_seq != ibox->synced_messages_count) {
-		if (!client_seq_to_uid(ibox, last_seq, &uid))
+	if (ctx.last_seq > 1 && ctx.last_seq != ibox->synced_messages_count) {
+		if (!client_seq_to_uid(ibox, ctx.last_seq, &uid))
 			return -1;
 		if (uid == 0)
 			return 0;
 
-		if (*last_uid == 0 || uid > *last_uid)
-			*last_uid = uid;
+		if (ctx.last_uid == 0 || uid > ctx.last_uid)
+			ctx.last_uid = uid;
 	}
 
-	if (*first_uid == 0)
-		*first_uid = 1;
-	if (*last_uid == 0 || last_seq == ibox->synced_messages_count)
-		*last_uid = ibox->index->header->next_uid-1;
+	if (ctx.first_uid == 0)
+		ctx.first_uid = 1;
+	if (ctx.last_uid == 0 || ctx.last_seq == ibox->synced_messages_count)
+		ctx.last_uid = ibox->index->header->next_uid-1;
 
 	/* UNSEEN and DELETED in root search level may limit the range */
-	if (!search_limit_by_flags(ibox, args, first_uid, last_uid))
+	if (!search_limit_by_flags(ibox, args, &ctx.first_uid, &ctx.last_uid))
 		return 0;
 
-	i_assert(*first_uid <= *last_uid);
+	i_assert(ctx.first_uid <= ctx.last_uid);
+
+	if (ctx.msgset_arg != NULL && ctx.msgset_arg_count == 1) {
+		/* one messageset argument, we can use it */
+		*msgset_r = index_messageset_init(ibox,
+				ctx.msgset_arg->value.str,
+				ctx.msgset_arg->type == SEARCH_UID, TRUE);
+		/* we might be able to limit it some more */
+		index_messageset_limit_range(*msgset_r,
+					     ctx.first_uid, ctx.last_uid);
+		ctx.msgset_arg->match_always = TRUE;
+	} else {
+		*msgset_r = index_messageset_init_range(ibox, ctx.first_uid,
+							ctx.last_uid, TRUE);
+	}
 	return 1;
 }
 
@@ -795,7 +833,6 @@
 {
 	struct index_mailbox *ibox = (struct index_mailbox *) box;
 	struct mail_search_context *ctx;
-	unsigned int first_uid, last_uid;
 
 	if (sort_program != NULL && *sort_program != MAIL_SORT_END) {
 		i_error("BUG: index_storage_search_init(): "
@@ -817,8 +854,10 @@
 	if (ibox->synced_messages_count == 0)
 		return ctx;
 
+	mail_search_args_reset(ctx->args, TRUE);
+
 	/* see if we can limit the records we look at */
-	switch (search_get_uid_range(ibox, args, &first_uid, &last_uid)) {
+	switch (search_get_msgset(ibox, args, &ctx->msgset_ctx)) {
 	case -1:
 		/* error */
 		ctx->failed = TRUE;
@@ -828,8 +867,6 @@
 		return ctx;
 	}
 
-	ctx->msgset_ctx =
-		index_messageset_init_range(ibox, first_uid, last_uid, TRUE);
 	return ctx;
 }
 
@@ -870,7 +907,7 @@
 	int ret;
 
 	/* check the index matches first */
-	mail_search_args_reset(ctx->args);
+	mail_search_args_reset(ctx->args, FALSE);
 	ret = mail_search_args_foreach(ctx->args, search_index_arg, ctx);
 	if (ret >= 0)
 		return ret > 0;



More information about the dovecot-cvs mailing list