[dovecot-cvs] dovecot/src/lib-index mail-index-private.h, 1.54, 1.55 mail-index-sync-keywords.c, 1.4, 1.5 mail-index-sync-private.h, 1.25, 1.26 mail-index-sync.c, 1.54, 1.55 mail-index-transaction-private.h, 1.23, 1.24 mail-index-transaction.c, 1.57, 1.58 mail-index-view.c, 1.33, 1.34 mail-index.c, 1.196, 1.197 mail-index.h, 1.145, 1.146 mail-transaction-log-append.c, 1.7, 1.8

cras at dovecot.org cras at dovecot.org
Sun Apr 3 00:09:08 EEST 2005


Update of /var/lib/cvs/dovecot/src/lib-index
In directory talvi:/tmp/cvs-serv14722/lib-index

Modified Files:
	mail-index-private.h mail-index-sync-keywords.c 
	mail-index-sync-private.h mail-index-sync.c 
	mail-index-transaction-private.h mail-index-transaction.c 
	mail-index-view.c mail-index.c mail-index.h 
	mail-transaction-log-append.c 
Log Message:
Keywords are now stored in X-Keywords headers in mbox. Did several related
API changes to get better performance.



Index: mail-index-private.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-index-private.h,v
retrieving revision 1.54
retrieving revision 1.55
diff -u -d -r1.54 -r1.55
--- mail-index-private.h	29 Mar 2005 12:18:49 -0000	1.54
+++ mail-index-private.h	2 Apr 2005 21:09:03 -0000	1.55
@@ -62,14 +62,6 @@
 	/* unsigned char name[] */
 };
 
-struct mail_keywords {
-	struct mail_index *index;
-	unsigned int count;
-
-        /* variable sized list of keyword indexes */
-	uint32_t idx[1];
-};
-
 struct mail_index_keyword_header {
 	uint32_t keywords_count;
 	/* struct mail_index_keyword_header_rec[] */
@@ -99,9 +91,7 @@
 	buffer_t *buffer;
 	buffer_t *hdr_copy_buf;
 
-	pool_t keywords_pool;
-	const char *const *keywords;
-	unsigned int keywords_count;
+	array_t ARRAY_DEFINE(keyword_idx_map, unsigned int); /* file -> index */
 
 	unsigned int write_to_disk:1;
 };
@@ -142,8 +132,8 @@
 	uoff_t sync_log_file_offset;
 
 	pool_t keywords_pool;
-	array_t ARRAY_DEFINE(keywords_arr, const char *);
-	const char *const *keywords;
+	array_t ARRAY_DEFINE(keywords, const char *);
+	struct hash_table *keywords_hash; /* name -> idx */
 
 	uint32_t keywords_ext_id;
 	unsigned int last_grow_count;

Index: mail-index-sync-keywords.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-index-sync-keywords.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- mail-index-sync-keywords.c	12 Mar 2005 18:16:29 -0000	1.4
+++ mail-index-sync-keywords.c	2 Apr 2005 21:09:03 -0000	1.5
@@ -11,18 +11,24 @@
 	       const char *keyword_name, unsigned int *idx_r)
 {
 	struct mail_index_map *map = ctx->view->map;
-	unsigned int i;
+	const unsigned int *idx_map;
+	unsigned int i, count, keyword_idx;
 
 	if (!ctx->keywords_read) {
 		if (mail_index_map_read_keywords(ctx->view->index, map) < 0)
 			return -1;
 		ctx->keywords_read = TRUE;
 	}
-
-	for (i = 0; i < map->keywords_count; i++) {
-		if (strcmp(map->keywords[i], keyword_name) == 0) {
-			*idx_r = i;
-			return 1;
+	if (mail_index_keyword_lookup(ctx->view->index, keyword_name,
+				      FALSE, &keyword_idx) &&
+	    array_is_created(&map->keyword_idx_map)) {
+		/* FIXME: slow. maybe create index -> file mapping as well */
+		idx_map = array_get(&map->keyword_idx_map, &count);
+		for (i = 0; i < count; i++) {
+			if (idx_map[i] == keyword_idx) {
+				*idx_r = i;
+				return 1;
+			}
 		}
 	}
 

Index: mail-index-sync-private.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-index-sync-private.h,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -d -r1.25 -r1.26
--- mail-index-sync-private.h	2 Apr 2005 19:31:27 -0000	1.25
+++ mail-index-sync-private.h	2 Apr 2005 21:09:03 -0000	1.26
@@ -26,7 +26,8 @@
 struct mail_index_sync_list {
 	const array_t *ARRAY_DEFINE_PTR(array, struct uid_range);
 	unsigned int idx;
-	unsigned int keyword_num;
+	unsigned int keyword_idx:31;
+	unsigned int keyword_remove:1;
 };
 
 struct mail_index_expunge_handler {

Index: mail-index-sync.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-index-sync.c,v
retrieving revision 1.54
retrieving revision 1.55
diff -u -d -r1.54 -r1.55
--- mail-index-sync.c	29 Mar 2005 12:18:49 -0000	1.54
+++ mail-index-sync.c	2 Apr 2005 21:09:03 -0000	1.55
@@ -185,7 +185,8 @@
 mail_index_sync_read_and_sort(struct mail_index_sync_ctx *ctx,
 			      int *seen_external_r)
 {
-        struct mail_index_sync_list *synclist;
+	struct mail_index_sync_list *synclist;
+        const struct mail_index_transaction_keyword_update *keyword_updates;
 	unsigned int i, keyword_count;
 	int ret;
 
@@ -236,10 +237,20 @@
 		synclist->array = &ctx->trans->keyword_resets;
 	}
 
+	keyword_updates = keyword_count == 0 ? NULL :
+		array_get(&ctx->trans->keyword_updates, NULL);
 	for (i = 0; i < keyword_count; i++) {
-		synclist = array_modifyable_append(&ctx->sync_list);
-		synclist->array = array_idx(&ctx->trans->keyword_updates, i);
-		synclist->keyword_num = i;
+		if (array_is_created(&keyword_updates[i].add_seq)) {
+			synclist = array_modifyable_append(&ctx->sync_list);
+			synclist->array = &keyword_updates[i].add_seq;
+			synclist->keyword_idx = i;
+		}
+		if (array_is_created(&keyword_updates[i].remove_seq)) {
+			synclist = array_modifyable_append(&ctx->sync_list);
+			synclist->array = &keyword_updates[i].remove_seq;
+			synclist->keyword_idx = i;
+			synclist->keyword_remove = TRUE;
+		}
 	}
 
 	return ret;
@@ -430,16 +441,17 @@
 	rec->remove_flags = update->remove_flags;
 }
 
-static void mail_index_sync_get_keyword_update(struct mail_index_sync_rec *rec,
-					       const struct uid_range *range,
-					       unsigned int num)
+static void
+mail_index_sync_get_keyword_update(struct mail_index_sync_rec *rec,
+				   const struct uid_range *range,
+				   struct mail_index_sync_list *sync_list)
 {
-	rec->type = num % 2 == 0 ?
+	rec->type = !sync_list->keyword_remove ?
 		MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD :
 		MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE;
 	rec->uid1 = range->uid1;
 	rec->uid2 = range->uid2;
-	rec->keyword_idx = num / 2;
+	rec->keyword_idx = sync_list->keyword_idx;
 }
 
 static void mail_index_sync_get_keyword_reset(struct mail_index_sync_rec *rec,
@@ -530,7 +542,7 @@
 		mail_index_sync_get_keyword_reset(sync_rec, uid_range);
 	} else {
 		mail_index_sync_get_keyword_update(sync_rec, uid_range,
-						   sync_list[i].keyword_num);
+						   &sync_list[i]);
 	}
 	sync_list[i].idx++;
 
@@ -624,12 +636,6 @@
 	mail_index_sync_end(ctx);
 }
 
-const char *const *const *
-mail_index_sync_get_keywords(struct mail_index_sync_ctx *ctx)
-{
-	return &ctx->index->keywords;
-}
-
 void mail_index_sync_flags_apply(const struct mail_index_sync_rec *sync_rec,
 				 uint8_t *flags)
 {
@@ -637,3 +643,41 @@
 
 	*flags = (*flags & ~sync_rec->remove_flags) | sync_rec->add_flags;
 }
+
+int mail_index_sync_keywords_apply(const struct mail_index_sync_rec *sync_rec,
+				   array_t *keywords)
+{
+	ARRAY_SET_TYPE(keywords, unsigned int);
+	const unsigned int *keyword_indexes;
+	unsigned int idx = sync_rec->keyword_idx;
+	unsigned int i, count;
+
+	keyword_indexes = array_get(keywords, &count);
+	switch (sync_rec->type) {
+	case MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD:
+		for (i = 0; i < count; i++) {
+			if (keyword_indexes[i] == idx)
+				return FALSE;
+		}
+
+		array_append(keywords, &idx, 1);
+		return TRUE;
+	case MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE:
+		for (i = 0; i < count; i++) {
+			if (keyword_indexes[i] == idx) {
+				array_delete(keywords, i, 1);
+				return TRUE;
+			}
+		}
+		return FALSE;
+	case MAIL_INDEX_SYNC_TYPE_KEYWORD_RESET:
+		if (array_count(keywords) == 0)
+			return FALSE;
+
+		array_clear(keywords);
+		return TRUE;
+	default:
+		i_unreached();
+		return FALSE;
+	}
+}

Index: mail-index-transaction-private.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-index-transaction-private.h,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -d -r1.23 -r1.24
--- mail-index-transaction-private.h	12 Mar 2005 18:16:29 -0000	1.23
+++ mail-index-transaction-private.h	2 Apr 2005 21:09:03 -0000	1.24
@@ -3,6 +3,11 @@
 
 #include "mail-transaction-log.h"
 
+struct mail_index_transaction_keyword_update {
+	array_t ARRAY_DEFINE(add_seq, uint32_t);
+	array_t ARRAY_DEFINE(remove_seq, uint32_t);
+};
+
 struct mail_index_transaction {
 	int refcount;
 	struct mail_index_view *view;
@@ -21,7 +26,8 @@
 	array_t ARRAY_DEFINE(ext_resizes, struct mail_transaction_ext_intro);
 	array_t ARRAY_DEFINE(ext_resets, uint32_t);
 
-	array_t ARRAY_DEFINE(keyword_updates, array_t);
+	array_t ARRAY_DEFINE(keyword_updates,
+			     struct mail_index_transaction_keyword_update);
 	array_t ARRAY_DEFINE(keyword_resets, struct seq_range);
 
         struct mail_cache_transaction_ctx *cache_trans_ctx;

Index: mail-index-transaction.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-index-transaction.c,v
retrieving revision 1.57
retrieving revision 1.58
diff -u -d -r1.57 -r1.58
--- mail-index-transaction.c	27 Mar 2005 12:22:21 -0000	1.57
+++ mail-index-transaction.c	2 Apr 2005 21:09:03 -0000	1.58
@@ -56,11 +56,15 @@
 	}
 
 	if (array_is_created(&t->keyword_updates)) {
-		recs = array_get_modifyable(&t->keyword_updates, &count);
+		struct mail_index_transaction_keyword_update *u;
+
+		u = array_get_modifyable(&t->keyword_updates, &count);
 
 		for (i = 0; i < count; i++) {
-			if (array_is_created(&recs[i]))
-				array_free(&recs[i]);
+			if (array_is_created(&u[i].add_seq))
+				array_free(&u[i].add_seq);
+			if (array_is_created(&u[i].remove_seq))
+				array_free(&u[i].remove_seq);
 		}
 		array_free(&t->keyword_updates);
 	}
@@ -830,11 +834,9 @@
 mail_index_keywords_create(struct mail_index_transaction *t,
 			   const char *const keywords[])
 {
-	/* @UNSAFE */
 	struct mail_index *index = t->view->index;
 	struct mail_keywords *k;
-	const char **missing_keywords, *keyword;
-	unsigned int count, i, j, k_pos = 0, missing_count = 0;
+	unsigned int i, count;
 
 	if (keywords == NULL) {
 		k = i_new(struct mail_keywords, 1);
@@ -843,48 +845,39 @@
 	}
 	count = strarray_length(keywords);
 
+	/* @UNSAFE */
 	k = i_malloc(sizeof(struct mail_keywords) +
 		     (sizeof(k->idx) * (count-1)));
-	k->index = t->view->index;
+	k->index = index;
 	k->count = count;
 
-	t_push();
-	missing_keywords = t_new(const char *, count + 1);
-
 	/* look up the keywords from index. they're never removed from there
 	   so we can permanently store indexes to them. */
 	for (i = 0; i < count; i++) {
-		for (j = 0; index->keywords[j] != NULL; j++) {
-			if (strcasecmp(keywords[i], index->keywords[j]) == 0)
-				break;
-		}
-
-		if (index->keywords[j] != NULL)
-			k->idx[k_pos++] = j;
-		else
-			missing_keywords[missing_count++] = keywords[i];
+		(void)mail_index_keyword_lookup(index, keywords[i],
+						TRUE, &k->idx[i]);
 	}
+	return k;
+}
 
-	if (missing_count > 0) {
-		/* add missing keywords. first drop the trailing NULL. */
-		array_delete(&index->keywords_arr,
-			     array_count(&index->keywords_arr) - 1, 1);
-
-		j = array_count(&index->keywords_arr);
-		for (; *missing_keywords != NULL; missing_keywords++, j++) {
-			keyword = p_strdup(index->keywords_pool,
-					   *missing_keywords);
-			array_append(&index->keywords_arr, &keyword, 1);
+struct mail_keywords *
+mail_index_keywords_create_from_indexes(struct mail_index_transaction *t,
+					const array_t *keyword_indexes)
+{
+	ARRAY_SET_TYPE(keyword_indexes, unsigned int);
+	struct mail_keywords *k;
+	unsigned int count;
 
-			k->idx[k_pos++] = j;
-		}
+	count = array_count(keyword_indexes);
 
-		(void)array_modifyable_append(&index->keywords_arr);
-		index->keywords = array_idx(&index->keywords_arr, 0);
-	}
-	i_assert(k_pos == count);
+	/* @UNSAFE */
+	k = i_malloc(sizeof(struct mail_keywords) +
+		     (sizeof(k->idx) * (count-1)));
+	k->index = t->view->index;
+	k->count = count;
 
-	t_pop();
+	memcpy(k->idx, array_get(keyword_indexes, NULL),
+	       count * sizeof(k->idx[0]));
 	return k;
 }
 
@@ -897,8 +890,8 @@
 				enum modify_type modify_type,
 				struct mail_keywords *keywords)
 {
-	array_t *arr;
-	unsigned int i, idx;
+	struct mail_index_transaction_keyword_update *u;
+	unsigned int i;
 
 	i_assert(seq > 0 &&
 		 (seq <= mail_index_view_get_messages_count(t->view) ||
@@ -906,48 +899,40 @@
 	i_assert(keywords->count > 0 || modify_type == MODIFY_REPLACE);
 	i_assert(keywords->index == t->view->index);
 
-	/* keyword_updates is an array of
-	   { buffer_t *add_seq; buffer_t *remove_seq; }
-	   which is why there's the multiplication by 2.
-
-	   If t->keyword_resets is set for the sequence, there's no need to
-	   update remove_seq as it will remove all keywords. */
-
 	if (!array_is_created(&t->keyword_updates)) {
 		uint32_t max_idx = keywords->idx[keywords->count-1];
 
 		ARRAY_CREATE(&t->keyword_updates, default_pool,
-			     array_t, max_idx * 2);
+			     struct mail_index_transaction_keyword_update,
+			     max_idx);
 	}
 
 	switch (modify_type) {
 	case MODIFY_ADD:
 		for (i = 0; i < keywords->count; i++) {
-			idx = keywords->idx[i] * 2;
-			arr = array_modifyable_idx(&t->keyword_updates, idx);
-			mail_index_seq_range_array_add(arr, 16, seq);
-
-			arr = array_modifyable_idx(&t->keyword_updates, idx+1);
-			mail_index_seq_range_array_remove(arr, seq);
+			u = array_modifyable_idx(&t->keyword_updates,
+						 keywords->idx[i]);
+			mail_index_seq_range_array_add(&u->add_seq, 16, seq);
+			mail_index_seq_range_array_remove(&u->remove_seq, seq);
 		}
 		break;
 	case MODIFY_REMOVE:
 		for (i = 0; i < keywords->count; i++) {
-			idx = keywords->idx[i] * 2;
-			arr = array_modifyable_idx(&t->keyword_updates, idx);
-			mail_index_seq_range_array_remove(arr, seq);
-
-			arr = array_modifyable_idx(&t->keyword_updates, idx+1);
-			mail_index_seq_range_array_add(arr, 16, seq);
+			u = array_modifyable_idx(&t->keyword_updates,
+						 keywords->idx[i]);
+			mail_index_seq_range_array_remove(&u->add_seq, seq);
+			mail_index_seq_range_array_add(&u->remove_seq, 16, seq);
 		}
 		break;
 	case MODIFY_REPLACE:
 		for (i = 0; i < keywords->count; i++) {
-			idx = keywords->idx[i] * 2;
-			arr = array_modifyable_idx(&t->keyword_updates, idx);
-			mail_index_seq_range_array_add(arr, 16, seq);
+			u = array_modifyable_idx(&t->keyword_updates,
+						 keywords->idx[i]);
+			mail_index_seq_range_array_add(&u->add_seq, 16, seq);
 		}
 
+		/* If t->keyword_resets is set for a sequence, there's no
+		   need to update remove_seq as it will remove all keywords. */
 		mail_index_seq_range_array_add(&t->keyword_resets, 16, seq);
 		break;
 	}

Index: mail-index-view.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-index-view.c,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -d -r1.33 -r1.34
--- mail-index-view.c	12 Mar 2005 18:16:29 -0000	1.33
+++ mail-index-view.c	2 Apr 2005 21:09:03 -0000	1.34
@@ -458,58 +458,71 @@
 }
 
 int mail_index_lookup_keywords(struct mail_index_view *view, uint32_t seq,
-			       buffer_t *buf, const char *const **keywords_r)
+			       array_t *keyword_idx)
 {
+	ARRAY_SET_TYPE(keyword_idx, unsigned int);
 	struct mail_index_map *map;
 	const struct mail_index_ext *ext;
 	const void *data;
-	unsigned int i, j;
+	const unsigned int *keyword_idx_map;
+	unsigned int i, j, keyword_count, index_idx;
 	uint32_t ext_id, idx;
 	int ret;
 
-	*keywords_r = NULL;
-	buffer_set_used_size(buf, 0);
+	array_clear(keyword_idx);
 
 	ext_id = view->index->keywords_ext_id;
 	ret = mail_index_lookup_ext_full(view, seq, ext_id, &map, &data);
 	if (ret < 0)
 		return -1;
 
-	if (!mail_index_map_get_ext_idx(map, ext_id, &idx)) {
-		buffer_append_zero(buf, sizeof(const char *));
-		*keywords_r = buf->data;
+	if (!mail_index_map_get_ext_idx(map, ext_id, &idx))
 		return ret;
-	}
 
 	ext = array_idx(&map->extensions, idx);
+	if (!array_is_created(&map->keyword_idx_map)) {
+		keyword_idx_map = NULL;
+		keyword_count = 0;
+	} else {
+		keyword_idx_map = array_get(&map->keyword_idx_map,
+					    &keyword_count);
+	}
+
 	for (i = 0, idx = 0; i < ext->record_size; i++) {
-		if (((const char *)data)[i] == 0)
+		if (((const unsigned char *)data)[i] == 0)
 			continue;
 
+		idx = i * CHAR_BIT;
 		for (j = 0; j < CHAR_BIT; j++, idx++) {
-			if ((((const char *)data)[i] & (1 << j)) == 0)
+			if ((((const unsigned char *)data)[i] & (1 << j)) == 0)
 				continue;
 
-			if (idx >= map->keywords_count) {
+			if (idx >= keyword_count) {
 				/* keyword header is updated, re-read
 				   it so we know what this one is
 				   called */
 				if (mail_index_map_read_keywords(view->index,
 								 map) < 0)
 					return -1;
-				if (idx >= map->keywords_count) {
+
+				if (!array_is_created(&map->keyword_idx_map))
+					return ret;
+
+				keyword_idx_map =
+					array_get(&map->keyword_idx_map,
+						  &keyword_count);
+
+				if (idx >= keyword_count) {
 					/* extra bits set in keyword bytes.
 					   shouldn't happen, but just ignore. */
 					break;
 				}
 			}
-			buffer_append(buf, &map->keywords[idx],
-				      sizeof(const char *));
+
+			index_idx = keyword_idx_map[idx];
+			array_append(keyword_idx, &index_idx, 1);
 		}
 	}
-	buffer_append_zero(buf, sizeof(const char *));
-	*keywords_r = buf->data;
-
 	return ret;
 }
 

Index: mail-index.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-index.c,v
retrieving revision 1.196
retrieving revision 1.197
diff -u -d -r1.196 -r1.197
--- mail-index.c	29 Mar 2005 12:18:49 -0000	1.196
+++ mail-index.c	2 Apr 2005 21:09:05 -0000	1.197
@@ -2,6 +2,7 @@
 
 #include "lib.h"
 #include "buffer.h"
+#include "hash.h"
 #include "mmap-util.h"
 #include "read-full.h"
 #include "write-full.h"
@@ -45,23 +46,25 @@
 	index->keywords_ext_id =
 		mail_index_ext_register(index, "keywords", 128, 2, 1);
 	index->keywords_pool = pool_alloconly_create("keywords", 512);
-	ARRAY_CREATE(&index->keywords_arr, default_pool,
-		     const char *, 16);
-	(void)array_modifyable_append(&index->keywords_arr);
-	index->keywords = array_idx(&index->keywords_arr, 0);
+	ARRAY_CREATE(&index->keywords, default_pool, const char *, 16);
+	index->keywords_hash =
+		hash_create(default_pool, index->keywords_pool, 0,
+			    strcase_hash, (hash_cmp_callback_t *)strcasecmp);
 	return index;
 }
 
 void mail_index_free(struct mail_index *index)
 {
 	mail_index_close(index);
+
+	hash_destroy(index->keywords_hash);
 	pool_unref(index->extension_pool);
 	pool_unref(index->keywords_pool);
 
 	array_free(&index->sync_handlers);
 	array_free(&index->sync_lost_handlers);
 	array_free(&index->expunge_handlers);
-	array_free(&index->keywords_arr);
+	array_free(&index->keywords);
 
 	i_free(index->error);
 	i_free(index->dir);
@@ -333,20 +336,45 @@
 	return 1;
 }
 
+int mail_index_keyword_lookup(struct mail_index *index,
+			      const char *keyword, int autocreate,
+			      unsigned int *idx_r)
+{
+	char *keyword_dup;
+	void *value;
+
+	if (hash_lookup_full(index->keywords_hash, keyword, NULL, &value)) {
+		*idx_r = POINTER_CAST_TO(value, unsigned int);
+		return TRUE;
+	}
+
+	if (!autocreate) {
+		*idx_r = (unsigned int)-1;
+		return FALSE;
+	}
+
+	keyword = keyword_dup = p_strdup(index->keywords_pool, keyword);
+	*idx_r = array_count(&index->keywords);
+
+	hash_insert(index->keywords_hash, keyword_dup, POINTER_CAST(*idx_r));
+	array_append(&index->keywords, &keyword, 1);
+	return TRUE;
+}
+
 int mail_index_map_read_keywords(struct mail_index *index,
 				 struct mail_index_map *map)
 {
 	const struct mail_index_ext *ext;
 	const struct mail_index_keyword_header *kw_hdr;
 	const struct mail_index_keyword_header_rec *kw_rec;
-	const char *name, **keywords_list;
-	unsigned int i, name_len;
+	const char *name;
+	unsigned int i, name_len, old_count;
 	uint32_t ext_id;
 
 	ext_id = mail_index_map_lookup_ext(map, "keywords");
 	if (ext_id == (uint32_t)-1) {
-		map->keywords = NULL;
-		map->keywords_count = 0;
+		if (array_is_created(&map->keyword_idx_map))
+			array_clear(&map->keyword_idx_map);
 		return 0;
 	}
 
@@ -356,6 +384,23 @@
 	kw_rec = (const void *)(kw_hdr + 1);
 	name = (const char *)(kw_rec + kw_hdr->keywords_count);
 
+	old_count = !array_is_created(&map->keyword_idx_map) ? 0 :
+		array_count(&map->keyword_idx_map);
+
+	/* Keywords can only be added in mapping. */
+	if (kw_hdr->keywords_count == old_count) {
+		/* nothing changed */
+		return 0;
+	}
+
+	/* make sure the header is valid */
+	if (kw_hdr->keywords_count < old_count) {
+		mail_index_set_error(index, "Corrupted index file %s: "
+				     "Keywords removed unexpectedly",
+				     index->filepath);
+		return -1;
+	}
+
 	if ((size_t)(name - (const char *)kw_hdr) > ext->hdr_size) {
 		mail_index_set_error(index, "Corrupted index file %s: "
 				     "keywords_count larger than header size",
@@ -363,7 +408,6 @@
 		return -1;
 	}
 
-	/* make sure the header is valid */
 	name_len = (const char *)kw_hdr + ext->hdr_size - name;
 	for (i = 0; i < kw_hdr->keywords_count; i++) {
 		if (kw_rec[i].name_offset > name_len) {
@@ -380,42 +424,43 @@
 		return -1;
 	}
 
-	if (map->keywords_pool == NULL)
-		map->keywords_pool = pool_alloconly_create("keywords", 1024);
-
-	/* Save keywords in memory. Only new keywords should come into the
-	   mapping, so keep the existing keyword strings in memory to allow
-	   mail_index_lookup_keywords() to safely return direct pointers
-	   into them. */
-	if (kw_hdr->keywords_count < map->keywords_count) {
-		mail_index_set_error(index, "Corrupted index file %s: "
-				     "Keywords removed unexpectedly",
-				     index->filepath);
-		return -1;
-	}
-	if (kw_hdr->keywords_count == map->keywords_count) {
-		/* nothing changed */
-		return 0;
+	/* create file -> index mapping */
+	if (!array_is_created(&map->keyword_idx_map)) {
+		ARRAY_CREATE(&map->keyword_idx_map, default_pool,
+			     unsigned int, kw_hdr->keywords_count);
 	}
 
-	/* @UNSAFE */
-	keywords_list = p_new(map->keywords_pool,
-			      const char *, kw_hdr->keywords_count + 1);
-	for (i = 0; i < map->keywords_count; i++)
-		keywords_list[i] = map->keywords[i];
+#ifdef DEBUG
+	for (i = 0; i < array_count(&map->keyword_idx_map); i++) {
+		const char *keyword = name + kw_rec[i].name_offset;
+		const unsigned int *old_idx;
+		unsigned int idx;
+
+		old_idx = array_idx(&map->keyword_idx_map, i);
+		if (!mail_index_keyword_lookup(index, keyword, FALSE, &idx) ||
+		    idx != *old_idx) {
+			mail_index_set_error(index, "Corrupted index file %s: "
+					     "Keywords changed unexpectedly",
+					     index->filepath);
+			return -1;
+		}
+	}
+#endif
+	i = array_count(&map->keyword_idx_map);
 	for (; i < kw_hdr->keywords_count; i++) {
-		keywords_list[i] = p_strdup(map->keywords_pool,
-					    name + kw_rec[i].name_offset);
+		const char *keyword = name + kw_rec[i].name_offset;
+		unsigned int idx;
+
+		(void)mail_index_keyword_lookup(index, keyword, TRUE, &idx);
+		array_append(&map->keyword_idx_map, &idx, 1);
 	}
-	map->keywords = keywords_list;
-	map->keywords_count = kw_hdr->keywords_count;
 	return 0;
 }
 
-const char *const *mail_index_get_keywords(struct mail_index *index)
+const array_t *mail_index_get_keywords(struct mail_index *index)
 {
 	(void)mail_index_map_read_keywords(index, index->map);
-	return index->map->keywords;
+	return &index->keywords;
 }
 
 static int mail_index_check_header(struct mail_index *index,
@@ -508,8 +553,8 @@
 	mail_index_map_clear(index, map);
 	if (map->extension_pool != NULL)
 		pool_unref(map->extension_pool);
-	if (map->keywords_pool != NULL)
-		pool_unref(map->keywords_pool);
+	if (array_is_created(&map->keyword_idx_map))
+		array_free(&map->keyword_idx_map);
 	buffer_free(map->hdr_copy_buf);
 	i_free(map);
 }

Index: mail-index.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-index.h,v
retrieving revision 1.145
retrieving revision 1.146
diff -u -d -r1.145 -r1.146
--- mail-index.h	27 Mar 2005 12:22:21 -0000	1.145
+++ mail-index.h	2 Apr 2005 21:09:05 -0000	1.146
@@ -106,6 +106,14 @@
 	uint8_t flags; /* enum mail_flags | enum mail_index_mail_flags */
 };
 
+struct mail_keywords {
+	struct mail_index *index;
+	unsigned int count;
+
+        /* variable sized list of keyword indexes */
+	unsigned int idx[1];
+};
+
 enum mail_index_sync_type {
 	MAIL_INDEX_SYNC_TYPE_APPEND		= 0x01,
 	MAIL_INDEX_SYNC_TYPE_EXPUNGE		= 0x02,
@@ -124,11 +132,10 @@
 	uint8_t add_flags;
 	uint8_t remove_flags;
 
-	/* MAIL_INDEX_SYNC_TYPE_KEYWORDS: */
+	/* MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD, .._REMOVE: */
 	unsigned int keyword_idx;
 };
 
-struct mail_keywords;
 struct mail_index;
 struct mail_index_map;
 struct mail_index_view;
@@ -256,7 +263,7 @@
 			   struct mail_index_map **map_r,
 			   const struct mail_index_record **rec_r);
 int mail_index_lookup_keywords(struct mail_index_view *view, uint32_t seq,
-			       buffer_t *buf, const char *const **keywords_r);
+			       array_t *keyword_idx);
 /* Returns the UID for given message. May be slightly faster than
    mail_index_lookup()->uid. */
 int mail_index_lookup_uid(struct mail_index_view *view, uint32_t seq,
@@ -291,13 +298,24 @@
 				   enum modify_type modify_type,
 				   enum mail_flags flags);
 
-/* Return a NULL-terminated list of all existing keywords. */
-const char *const *mail_index_get_keywords(struct mail_index *index);
+/* Lookup a keyword, returns TRUE if found, FALSE if not. If autocreate is
+   TRUE, the keyword is automatically created and TRUE is always returned. */
+int mail_index_keyword_lookup(struct mail_index *index,
+			      const char *keyword, int autocreate,
+			      unsigned int *idx_r);
+/* Return a pointer to array of NULL-terminated list of keywords. Note that
+   the array contents (and thus pointers inside it) may change after calling
+   mail_index_keywords_create() or mail_index_sync_begin(). */
+const array_t *mail_index_get_keywords(struct mail_index *index);
+
 /* Create a keyword list structure. It's freed automatically at the end of
    the transaction. */
 struct mail_keywords *
 mail_index_keywords_create(struct mail_index_transaction *t,
 			   const char *const keywords[]);
+struct mail_keywords *
+mail_index_keywords_create_from_indexes(struct mail_index_transaction *t,
+					const array_t *keyword_indexes);
 /* Free the keywords. */
 void mail_index_keywords_free(struct mail_keywords *keywords);
 /* Update keywords for given message. */
@@ -317,15 +335,14 @@
 /* Reset the error message. */
 void mail_index_reset_error(struct mail_index *index);
 
-/* Return a pointer to NULL-terminated list of keywords which are referenced
-   in mail_index_sync_rec->keyword_idx. Note tat the pointer may change after
-   calling mail_index_keywords_create(). */
-const char *const *const *
-mail_index_sync_get_keywords(struct mail_index_sync_ctx *ctx);
 /* Apply changes in MAIL_INDEX_SYNC_TYPE_FLAGS typed sync records to given
-   flags variables. */
+   flags variable. */
 void mail_index_sync_flags_apply(const struct mail_index_sync_rec *sync_rec,
 				 uint8_t *flags);
+/* Apply changes in MAIL_INDEX_SYNC_TYPE_KEYWORD_* typed sync records to given
+   keywords array. Returns TRUE If something was changed. */
+int mail_index_sync_keywords_apply(const struct mail_index_sync_rec *sync_rec,
+				   array_t *keywords);
 
 /* register index extension. name is a unique identifier for the extension.
    returns unique identifier for the name. */

Index: mail-transaction-log-append.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/lib-index/mail-transaction-log-append.c,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -d -r1.7 -r1.8
--- mail-transaction-log-append.c	29 Mar 2005 12:18:49 -0000	1.7
+++ mail-transaction-log-append.c	2 Apr 2005 21:09:05 -0000	1.8
@@ -272,37 +272,56 @@
 	return 0;
 }
 
+static int
+log_append_keyword_update(struct mail_transaction_log_file *file,
+			  struct mail_index_transaction *t,
+			  buffer_t *hdr_buf, enum modify_type modify_type,
+			  const char *keyword, const buffer_t *buffer)
+{
+	struct mail_transaction_keyword_update kt_hdr;
+
+	memset(&kt_hdr, 0, sizeof(kt_hdr));
+	kt_hdr.modify_type = modify_type;
+	kt_hdr.name_size = strlen(keyword);
+
+	buffer_set_used_size(hdr_buf, 0);
+	buffer_append(hdr_buf, &kt_hdr, sizeof(kt_hdr));
+	buffer_append(hdr_buf, keyword, kt_hdr.name_size);
+	if ((hdr_buf->used % 4) != 0)
+		buffer_append_zero(hdr_buf, 4 - (hdr_buf->used % 4));
+
+	return log_append_buffer(file, buffer, hdr_buf,
+				 MAIL_TRANSACTION_KEYWORD_UPDATE, t->external);
+}
+
 static int log_append_keyword_updates(struct mail_transaction_log_file *file,
 				      struct mail_index_transaction *t)
 {
-	struct mail_index *index = t->view->index;
-	struct mail_transaction_keyword_update kt_hdr;
+        const struct mail_index_transaction_keyword_update *updates;
+	const char *const *keywords;
 	buffer_t *hdr_buf;
-	array_t *updates;
-	unsigned int i, count;
+	unsigned int i, count, keywords_count;
 
 	hdr_buf = buffer_create_dynamic(pool_datastack_create(), 64);
 
+	keywords = array_get_modifyable(&t->view->index->keywords,
+					&keywords_count);
 	updates = array_get_modifyable(&t->keyword_updates, &count);
-	for (i = 0; i < count; i++) {
-		if (!array_is_created(&updates[i]))
-			continue;
-
-		buffer_set_used_size(hdr_buf, 0);
-
-		memset(&kt_hdr, 0, sizeof(kt_hdr));
-		kt_hdr.modify_type = (i & 1) == 0 ? MODIFY_ADD : MODIFY_REMOVE;
-		kt_hdr.name_size = strlen(index->keywords[i / 2]);
-		buffer_append(hdr_buf, &kt_hdr, sizeof(kt_hdr));
-		buffer_append(hdr_buf, index->keywords[i / 2],
-			      kt_hdr.name_size);
-		if ((hdr_buf->used % 4) != 0)
-			buffer_append_zero(hdr_buf, 4 - (hdr_buf->used % 4));
+	i_assert(count <= keywords_count);
 
-		if (log_append_buffer(file, updates[i].buffer, hdr_buf,
-				      MAIL_TRANSACTION_KEYWORD_UPDATE,
-				      t->external) < 0)
-			return -1;
+	for (i = 0; i < count; i++) {
+		if (array_is_created(&updates[i].add_seq)) {
+			if (log_append_keyword_update(file, t, hdr_buf,
+					MODIFY_ADD, keywords[i],
+					updates[i].add_seq.buffer) < 0)
+				return -1;
+		}
+		if (array_is_created(&updates[i].remove_seq)) {
+			if (log_append_keyword_update(file, t, hdr_buf,
+					MODIFY_REMOVE, keywords[i],
+					updates[i].remove_seq.buffer) < 0)
+				return -1;
+		}
 	}
 
 	return 0;



More information about the dovecot-cvs mailing list