[dovecot-cvs] dovecot/src/imap imap-thread.c,1.29,1.30

tss at dovecot.org tss at dovecot.org
Sun Nov 26 15:20:14 UTC 2006


Update of /var/lib/cvs/dovecot/src/imap
In directory talvi:/tmp/cvs-serv13569/imap

Modified Files:
	imap-thread.c 
Log Message:
Resize the hash when needed. Also other fixes and cleanups.



Index: imap-thread.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/imap/imap-thread.c,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -d -r1.29 -r1.30
--- imap-thread.c	25 Nov 2006 22:17:40 -0000	1.29
+++ imap-thread.c	26 Nov 2006 15:20:12 -0000	1.30
@@ -202,6 +202,12 @@
 	pool_unref(ctx->msgid_pool);
 }
 
+static uint32_t crc32_str_nonzero(const char *str)
+{
+	uint32_t value = crc32_str(str);
+	return value == 0 ? 1 : value;
+}
+
 static int
 mail_thread_rec_idx(struct thread_context *ctx, uint32_t idx,
 		    const struct mail_thread_rec **rec_r)
@@ -217,7 +223,7 @@
 	return 0;
 }
 
-static unsigned int mail_thread_rec_hash(const void *key)
+static unsigned int mail_thread_hash_key(const void *key)
 {
 	const struct msgid_rec *key_rec = key;
 
@@ -241,7 +247,7 @@
 	msgids = mail_get_first_header(ctx->tmp_mail, HDR_IN_REPLY_TO);
 	msgid = msgids == NULL ? NULL : message_id_get_next(&msgids);
 	if (msgid != NULL) {
-		if (crc32_str(msgid) == msgid_crc32)
+		if (crc32_str_nonzero(msgid) == msgid_crc32)
 			found_msgid = msgid;
 	}
 
@@ -252,7 +258,7 @@
 	}
 
 	while ((msgid = message_id_get_next(&msgids)) != NULL) {
-		if (crc32_str(msgid) == msgid_crc32) {
+		if (crc32_str_nonzero(msgid) == msgid_crc32) {
 			if (found_msgid != NULL) {
 				/* hash collisions, we can't figure this out */
 				return -1;
@@ -284,6 +290,12 @@
 		/* each non-dummy child must have a valid In-Reply-To or
 		   References header pointing to the parent, otherwise it
 		   wouldn't be our child */
+		if (parent_rec->msgid_crc32 == 0) {
+			mail_hash_set_corrupted(ctx->msgid_hash,
+				"msgid_crc32=0 node has children");
+			return NULL;
+		}
+
 		if (mail_thread_find_child_msgid(ctx, child_rec->rec.uid,
 						 parent_rec->msgid_crc32,
 						 &msgid) == 0)
@@ -324,8 +336,8 @@
 	return *p;
 }
 
-static bool mail_thread_rec_msgid_cmp(const void *key, const void *data,
-				      void *context)
+static bool mail_thread_hash_cmp(const void *key, const void *data,
+				 void *context)
 {
 	struct imap_thread_mailbox *tbox = context;
 	struct thread_context *ctx = tbox->ctx;
@@ -350,6 +362,13 @@
 	return strcmp(msgid, key_rec->msgid) == 0;
 }
 
+static unsigned int mail_thread_hash_rec(const void *p)
+{
+	const struct mail_thread_rec *rec = p;
+
+	return rec->msgid_crc32;
+}
+
 static int
 imap_thread_context_init(struct imap_thread_mailbox *tbox,
 			 struct client *client, const char *charset,
@@ -364,6 +383,15 @@
 			       STATUS_MESSAGES | STATUS_UIDNEXT, &status) < 0)
 		return -1;
 
+	if (search_args->type != SEARCH_ALL ||
+	    search_args->next != NULL) {
+		/* each search condition requires their own separate thread
+		   index. for now we don't bother to support anything else than
+		   "search all" threading, since that's what pretty much all
+		   the clients do anyway. */
+		ctx->msgid_hash = NULL;
+	}
+
 	if (ctx->msgid_hash != NULL) {
 		if (mail_hash_lock(ctx->msgid_hash) <= 0)
 			ctx->msgid_hash = NULL;
@@ -380,36 +408,34 @@
 			ctx->msgid_hash = NULL;
 		} else {
 			/* rebuild */
-			if (mail_hash_reset(ctx->msgid_hash) < 0) {
-				mail_hash_unlock(ctx->msgid_hash);
+			if (mail_hash_reset(ctx->msgid_hash, 0) < 0)
 				ctx->msgid_hash = NULL;
-			}
 		}
-	} else if (search_args->next == NULL &&
-		   search_args->type == SEARCH_ALL) {
-		/* threading everything. this is the only case we're trying
-		   to optimize. */
-		if (hdr->last_uid != 0) {
-			/* messages already exist in the hash. add only the
-			   new messages in there. */
-			if (mailbox_get_uids(client->mailbox, 1, hdr->last_uid,
-					     &ctx->seqset.seq1,
-					     &ctx->seqset.seq2) < 0)
-				return -1;
+	} else if (hdr->last_uid != 0) {
+		/* non-empty hash. add only the new messages in there. */
+		if (mailbox_get_uids(client->mailbox, 1, hdr->last_uid,
+				     &ctx->seqset.seq1,
+				     &ctx->seqset.seq2) < 0) {
+			mail_hash_unlock(ctx->msgid_hash);
+			return -1;
+		}
 
-			if (ctx->seqset.seq2 != hdr->message_count) {
-				/* some messages have been expunged.
-				   have to rebuild. */
-				if (mail_hash_reset(ctx->msgid_hash) < 0) {
-					mail_hash_unlock(ctx->msgid_hash);
-					ctx->msgid_hash = NULL;
-				}
-			} else {
-				ctx->tmp_search_arg.type = SEARCH_SEQSET;
-				ctx->tmp_search_arg.value.seqset = &ctx->seqset;
-				ctx->tmp_search_arg.not = TRUE;
-				search_args = &ctx->tmp_search_arg;
-			}
+		if (ctx->seqset.seq2 != hdr->message_count) {
+			/* some messages have been expunged. have to rebuild. */
+			if (mail_hash_reset(ctx->msgid_hash, 0) < 0)
+				ctx->msgid_hash = NULL;
+		} else {
+			/* after all these checks, this is the only case we
+			   can actually optimize. */
+			ctx->tmp_search_arg.type = SEARCH_SEQSET;
+			ctx->tmp_search_arg.value.seqset = &ctx->seqset;
+			ctx->tmp_search_arg.not = TRUE;
+			search_args = &ctx->tmp_search_arg;
+
+			if (mail_hash_resize_if_needed(ctx->msgid_hash,
+						       status.messages -
+						       hdr->message_count) < 0)
+				ctx->msgid_hash = NULL;
 		}
 	}
 
@@ -422,9 +448,10 @@
 			mail_hash_open(ibox->index, ".thread",
 				       MAIL_HASH_OPEN_FLAG_CREATE |
 				       MAIL_HASH_OPEN_FLAG_IN_MEMORY,
-				       sizeof(struct mail_thread_rec),
-				       mail_thread_rec_hash,
-				       mail_thread_rec_msgid_cmp,
+				       sizeof(struct mail_thread_rec), 0,
+				       mail_thread_hash_key,
+				       mail_thread_hash_rec,
+				       mail_thread_hash_cmp,
 				       tbox);
 	}
 
@@ -436,6 +463,8 @@
 	ctx->box = client->mailbox;
 	ctx->output = client->output;
 
+	/* at this point the hash is either locked or we're using in-memory
+	   hash where it doesn't matter */
 	hdr = mail_hash_get_header(ctx->msgid_hash);
 	count = client->messages_count < hdr->record_count ? 0 :
 		client->messages_count - hdr->record_count;
@@ -571,7 +600,7 @@
 			mail_thread_rec_get_msgid(ctx, rec, idx);
 		if (key.msgid == NULL)
 			return -1;
-		key.msgid_crc32 = crc32_str(key.msgid);
+		key.msgid_crc32 = crc32_str_nonzero(key.msgid);
 
 		if (mail_hash_remove_idx(ctx->msgid_hash, idx, &key) < 0) {
 			ctx->failed = TRUE;
@@ -782,7 +811,7 @@
 
 	memset(&rec, 0, sizeof(rec));
 	rec.rec.uid = uid;
-	rec.msgid_crc32 = msgid == NULL ? 0 : crc32_str(msgid);
+	rec.msgid_crc32 = msgid == NULL ? 0 : crc32_str_nonzero(msgid);
 	rec.refcount = 1;
 	rec.sent_date = sent_date;
 
@@ -842,6 +871,7 @@
 		uint32_t orig_idx = idx;
 
 		orig_rec = *recp;
+		rec.msgid_crc32 = 0;
 		if (mail_hash_insert(ctx->msgid_hash, NULL, &rec, &idx) < 0) {
 			ctx->failed = TRUE;
 			return -1;
@@ -975,7 +1005,7 @@
 	int ret;
 
 	key.msgid = msgid;
-	key.msgid_crc32 = crc32_str(msgid);
+	key.msgid_crc32 = crc32_str_nonzero(msgid);
 
 	ret = mail_hash_lookup(ctx->msgid_hash, &key, &value, idx_r);
 	if (ret < 0 || ctx->failed) {
@@ -1816,7 +1846,7 @@
 	key_r->msgid = message_id_get_next(&message_id);
 	if (key_r->msgid == NULL)
 		return 0;
-	key_r->msgid_crc32 = crc32_str(key_r->msgid);
+	key_r->msgid_crc32 = crc32_str_nonzero(key_r->msgid);
 
 	if (mail_hash_lookup(ctx->msgid_hash, key_r, &value, idx_r) <= 0)
 		return -1;
@@ -1851,7 +1881,7 @@
 	references = t_strdup(references);
 	do {
 		key.msgid = msgid;
-		key.msgid_crc32 = crc32_str(msgid);
+		key.msgid_crc32 = crc32_str_nonzero(msgid);
 
 		ctx->cmp_match_count = 0;
 		ctx->cmp_last_idx = 0;
@@ -2005,9 +2035,11 @@
 	tbox->msgid_hash =
 		mail_hash_open(ibox->index, ".thread", create ?
 			       MAIL_HASH_OPEN_FLAG_CREATE : 0,
-			       sizeof(struct mail_thread_rec),
-			       mail_thread_rec_hash,
-			       mail_thread_rec_msgid_cmp, tbox);
+			       sizeof(struct mail_thread_rec), 0,
+			       mail_thread_hash_key,
+			       mail_thread_hash_rec,
+			       mail_thread_hash_cmp,
+			       tbox);
 	if (tbox->msgid_hash == NULL)
 		return;
 



More information about the dovecot-cvs mailing list