On Thu, 2011-12-08 at 07:53 +0200, Timo Sirainen wrote:

> But yes, it is a problem that dsync doesn't update caching decisions..
> Hmm. I guess I'll have to fix that for v2.1.

Could you try if the attached patch fixes your problems when patching
against latest v2.1 hg? It's annoyingly large, and it makes v2.1 dsync
incompatible with v2.0, but maybe it's better to do it sooner than
later..

diff -r ddfe3a0f75e6 src/doveadm/doveadm-dump-index.c
--- a/src/doveadm/doveadm-dump-index.c	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/doveadm/doveadm-dump-index.c	Thu Dec 08 09:32:03 2011 +0200
@@ -9,7 +9,6 @@
 #include "message-part-serialize.h"
 #include "mail-index-private.h"
 #include "mail-cache-private.h"
-#include "mail-cache-private.h"
 #include "mail-index-modseq.h"
 #include "doveadm-dump.h"
 
@@ -344,7 +343,7 @@
 			printf("   - ");
 		printf("%-4s %.16s\n",
 		       cache_decision2str(field->decision),
-		       unixdate2str(cache->fields[cache_idx].last_used));
+		       unixdate2str(field->last_used));
 	}
 }
 
diff -r ddfe3a0f75e6 src/dsync/dsync-data.c
--- a/src/dsync/dsync-data.c	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/dsync/dsync-data.c	Thu Dec 08 09:32:03 2011 +0200
@@ -10,7 +10,8 @@
 dsync_mailbox_dup(pool_t pool, const struct dsync_mailbox *box)
 {
 	struct dsync_mailbox *dest;
-	const char *const *cache_fields = NULL, *dup;
+	const struct mailbox_cache_field *cache_fields = NULL;
+	struct mailbox_cache_field *dup;
 	unsigned int i, count = 0;
 
 	dest = p_new(pool, struct dsync_mailbox, 1);
@@ -24,8 +25,9 @@
 	else {
 		p_array_init(&dest->cache_fields, pool, count);
 		for (i = 0; i < count; i++) {
-			dup = p_strdup(pool, cache_fields[i]);
-			array_append(&dest->cache_fields, &dup, 1);
+			dup = array_append_space(&dest->cache_fields);
+			*dup = cache_fields[i];
+			dup->name = p_strdup(pool, dup->name);
 		}
 	}
 	return dest;
diff -r ddfe3a0f75e6 src/dsync/dsync-data.h
--- a/src/dsync/dsync-data.h	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/dsync/dsync-data.h	Thu Dec 08 09:32:03 2011 +0200
@@ -28,7 +28,7 @@
 	   otherwise it's the last rename timestamp. */
 	time_t last_change;
 	enum dsync_mailbox_flags flags;
-	ARRAY_TYPE(const_string) cache_fields;
+	ARRAY_TYPE(mailbox_cache_field) cache_fields;
 };
 ARRAY_DEFINE_TYPE(dsync_mailbox, struct dsync_mailbox *);
 #define dsync_mailbox_is_noselect(dsync_box) \
diff -r ddfe3a0f75e6 src/dsync/dsync-proxy-client.c
--- a/src/dsync/dsync-proxy-client.c	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/dsync/dsync-proxy-client.c	Thu Dec 08 09:32:03 2011 +0200
@@ -893,7 +893,7 @@
 static void
 proxy_client_worker_select_mailbox(struct dsync_worker *_worker,
 				   const mailbox_guid_t *mailbox,
-				   const ARRAY_TYPE(const_string) *cache_fields)
+				   const ARRAY_TYPE(mailbox_cache_field) *cache_fields)
 {
 	struct proxy_client_dsync_worker *worker =
 		(struct proxy_client_dsync_worker *)_worker;
@@ -908,7 +908,7 @@
 		str_append(str, "BOX-SELECT\t");
 		dsync_proxy_mailbox_guid_export(str, mailbox);
 		if (cache_fields != NULL)
-			dsync_proxy_strings_export(str, cache_fields);
+			dsync_proxy_cache_fields_export(str, cache_fields);
 		str_append_c(str, '\n');
 		proxy_client_worker_cmd(worker, str);
 	} T_END;
diff -r ddfe3a0f75e6 src/dsync/dsync-proxy-server-cmd.c
--- a/src/dsync/dsync-proxy-server-cmd.c	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/dsync/dsync-proxy-server-cmd.c	Thu Dec 08 09:32:03 2011 +0200
@@ -315,7 +315,7 @@
 cmd_box_select(struct dsync_proxy_server *server, const char *const *args)
 {
 	struct dsync_mailbox box;
-	unsigned int i, count;
+	const char *error;
 
 	memset(&box, 0, sizeof(box));
 	if (args[0] == NULL ||
@@ -325,10 +325,11 @@
 	}
 	args++;
 
-	count = str_array_length(args);
-	t_array_init(&box.cache_fields, count + 1);
-	for (i = 0; i < count; i++)
-		array_append(&box.cache_fields, &args[i], 1);
+	if (dsync_proxy_cache_fields_import(args, pool_datastack_create(),
+					    &box.cache_fields, &error) < 0) {
+		i_error("box-select: %s", error);
+		return -1;
+	}
 	dsync_worker_select_mailbox(server->worker, &box);
 	return 1;
 }
diff -r ddfe3a0f75e6 src/dsync/dsync-proxy.c
--- a/src/dsync/dsync-proxy.c	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/dsync/dsync-proxy.c	Thu Dec 08 09:32:03 2011 +0200
@@ -8,27 +8,104 @@
 #include "hex-binary.h"
 #include "mail-types.h"
 #include "imap-util.h"
+#include "mail-cache.h"
 #include "dsync-data.h"
 #include "dsync-proxy.h"
 
 #include <stdlib.h>
 
-void dsync_proxy_strings_export(string_t *str,
-				const ARRAY_TYPE(const_string) *strings)
+#define DSYNC_CACHE_DECISION_NO 'n'
+#define DSYNC_CACHE_DECISION_YES 'y'
+#define DSYNC_CACHE_DECISION_TEMP 't'
+#define DSYNC_CACHE_DECISION_FORCED 'f'
+
+void dsync_proxy_cache_fields_export(string_t *str,
+				     const ARRAY_TYPE(mailbox_cache_field) *_fields)
 {
-	const char *const *fields;
+	const struct mailbox_cache_field *fields;
 	unsigned int i, count;
 
-	if (!array_is_created(strings))
+	if (!array_is_created(_fields))
 		return;
 
-	fields = array_get(strings, &count);
+	fields = array_get(_fields, &count);
 	for (i = 0; i < count; i++) {
 		str_append_c(str, '\t');
-		str_tabescape_write(str, fields[i]);
+		str_tabescape_write(str, fields[i].name);
+		str_append_c(str, '\t');
+		switch (fields[i].decision & ~MAIL_CACHE_DECISION_FORCED) {
+		case MAIL_CACHE_DECISION_NO:
+			str_append_c(str, DSYNC_CACHE_DECISION_NO);
+			break;
+		case MAIL_CACHE_DECISION_YES:
+			str_append_c(str, DSYNC_CACHE_DECISION_YES);
+			break;
+		case MAIL_CACHE_DECISION_TEMP:
+			str_append_c(str, DSYNC_CACHE_DECISION_TEMP);
+			break;
+		}
+		if ((fields[i].decision & MAIL_CACHE_DECISION_FORCED) != 0)
+			str_append_c(str, DSYNC_CACHE_DECISION_FORCED);
+		str_printfa(str, "\t%ld", fields[i].last_used);
 	}
 }
 
+static int dsync_proxy_cache_dec_parse(const char *str,
+				       enum mail_cache_decision_type *dec_r)
+{
+	switch (*str++) {
+	case DSYNC_CACHE_DECISION_NO:
+		*dec_r = MAIL_CACHE_DECISION_NO;
+		break;
+	case DSYNC_CACHE_DECISION_YES:
+		*dec_r = MAIL_CACHE_DECISION_YES;
+		break;
+	case DSYNC_CACHE_DECISION_TEMP:
+		*dec_r = MAIL_CACHE_DECISION_TEMP;
+		break;
+	default:
+		return -1;
+	}
+	if (*str == DSYNC_CACHE_DECISION_FORCED) {
+		*dec_r |= MAIL_CACHE_DECISION_FORCED;
+		str++;
+	}
+	if (*str != '\0')
+		return -1;
+	return 0;
+}
+
+int dsync_proxy_cache_fields_import(const char *const *args, pool_t pool,
+				    ARRAY_TYPE(mailbox_cache_field) *fields,
+				    const char **error_r)
+{
+	struct mailbox_cache_field *cache_field;
+	enum mail_cache_decision_type dec;
+	unsigned int i, count = str_array_length(args);
+
+	if (count % 3 != 0) {
+		*error_r = "Invalid mailbox cache fields";
+		return -1;
+	}
+	if (!array_is_created(fields))
+		p_array_init(fields, pool, (count/3) + 1);
+	for (i = 0; i < count; i += 3) {
+		cache_field = array_append_space(fields);
+		cache_field->name = p_strdup(pool, args[i]);
+
+		if (dsync_proxy_cache_dec_parse(args[i+1], &dec) < 0) {
+			*error_r = "Invalid cache decision";
+			return -1;
+		}
+		cache_field->decision = dec;
+		if (str_to_time(args[i+2], &cache_field->last_used) < 0) {
+			*error_r = "Invalid cache last_used";
+			return -1;
+		}
+	}
+	return 0;
+}
+
 void dsync_proxy_msg_export(string_t *str,
 			    const struct dsync_message *msg)
 {
@@ -178,7 +255,7 @@
 		    box->uid_validity, box->uid_next, box->message_count,
 		    (unsigned long long)box->highest_modseq,
 		    box->first_recent_uid);
-	dsync_proxy_strings_export(str, &box->cache_fields);
+	dsync_proxy_cache_fields_export(str, &box->cache_fields);
 }
 
 int dsync_proxy_mailbox_import_unescaped(pool_t pool, const char *const *args,
@@ -270,11 +347,9 @@
 
 	args += i;
 	count -= i;
-	p_array_init(&box_r->cache_fields, pool, count + 1);
-	for (i = 0; i < count; i++) {
-		const char *field_name = p_strdup(pool, args[i]);
-		array_append(&box_r->cache_fields, &field_name, 1);
-	}
+	if (dsync_proxy_cache_fields_import(args, pool, &box_r->cache_fields,
+					    error_r) < 0)
+		return -1;
 	return 0;
 }
 
diff -r ddfe3a0f75e6 src/dsync/dsync-proxy.h
--- a/src/dsync/dsync-proxy.h	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/dsync/dsync-proxy.h	Thu Dec 08 09:32:03 2011 +0200
@@ -6,14 +6,17 @@
 #define DSYNC_PROXY_CLIENT_TIMEOUT_MSECS (14*60*1000)
 #define DSYNC_PROXY_SERVER_TIMEOUT_MSECS (15*60*1000)
 
-#define DSYNC_PROXY_CLIENT_GREETING_LINE "dsync-client\t1"
-#define DSYNC_PROXY_SERVER_GREETING_LINE "dsync-server\t1"
+#define DSYNC_PROXY_CLIENT_GREETING_LINE "dsync-client\t2"
+#define DSYNC_PROXY_SERVER_GREETING_LINE "dsync-server\t2"
 
 struct dsync_message;
 struct dsync_mailbox;
 
-void dsync_proxy_strings_export(string_t *str,
-				const ARRAY_TYPE(const_string) *strings);
+void dsync_proxy_cache_fields_export(string_t *str,
+				     const ARRAY_TYPE(mailbox_cache_field) *fields);
+int dsync_proxy_cache_fields_import(const char *const *args, pool_t pool,
+				    ARRAY_TYPE(mailbox_cache_field) *fields,
+				    const char **error_r);
 
 void dsync_proxy_msg_export(string_t *str, const struct dsync_message *msg);
 int dsync_proxy_msg_parse_flags(pool_t pool, const char *str,
diff -r ddfe3a0f75e6 src/dsync/dsync-worker-local.c
--- a/src/dsync/dsync-worker-local.c	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/dsync/dsync-worker-local.c	Thu Dec 08 09:32:03 2011 +0200
@@ -528,8 +528,8 @@
 	struct local_dsync_dir_change *dir_change, change_lookup;
 	struct local_dsync_mailbox *old_lbox;
 	enum mail_error error;
-	const char *const *fields;
-	unsigned int i, field_count;
+	struct mailbox_cache_field *cache_fields;
+	unsigned int i, cache_field_count;
 
 	memset(dsync_box_r, 0, sizeof(*dsync_box_r));
 
@@ -595,12 +595,14 @@
 	dsync_box_r->highest_modseq = status.highest_modseq;
 
 	p_clear(iter->ret_pool);
-	fields = array_get(metadata.cache_fields, &field_count);
-	p_array_init(&dsync_box_r->cache_fields, iter->ret_pool, field_count);
-	for (i = 0; i < field_count; i++) {
-		const char *field_name = p_strdup(iter->ret_pool, fields[i]);
-
-		array_append(&dsync_box_r->cache_fields, &field_name, 1);
+	p_array_init(&dsync_box_r->cache_fields, iter->ret_pool,
+		     array_count(metadata.cache_fields));
+	array_append_array(&dsync_box_r->cache_fields, metadata.cache_fields);
+	cache_fields = array_get_modifiable(&dsync_box_r->cache_fields,
+					    &cache_field_count);
+	for (i = 0; i < cache_field_count; i++) {
+		cache_fields[i].name =
+			p_strdup(iter->ret_pool, cache_fields[i].name);
 	}
 
 	old_lbox = hash_table_lookup(worker->mailbox_hash,
@@ -1443,25 +1445,26 @@
 
 static void
 local_worker_set_cache_fields(struct local_dsync_worker *worker,
-			      const ARRAY_TYPE(const_string) *cache_fields)
+			      const ARRAY_TYPE(mailbox_cache_field) *cache_fields)
 {
 	struct mailbox_update update;
-	const char *const *fields, **new_fields;
+	const struct mailbox_cache_field *fields;
+	struct mailbox_cache_field *new_fields;
 	unsigned int count;
 
 	fields = array_get(cache_fields, &count);
-	new_fields = t_new(const char *, count + 1);
-	memcpy(new_fields, fields, sizeof(const char *) * count);
+	new_fields = t_new(struct mailbox_cache_field, count + 1);
+	memcpy(new_fields, fields, sizeof(struct mailbox_cache_field) * count);
 
 	memset(&update, 0, sizeof(update));
-	update.cache_fields = new_fields;
+	update.cache_updates = new_fields;
 	mailbox_update(worker->selected_box, &update);
 }
 
 static void
 local_worker_select_mailbox(struct dsync_worker *_worker,
 			    const mailbox_guid_t *mailbox,
-			    const ARRAY_TYPE(const_string) *cache_fields)
+			    const ARRAY_TYPE(mailbox_cache_field) *cache_fields)
 {
 	struct local_dsync_worker *worker =
 		(struct local_dsync_worker *)_worker;
diff -r ddfe3a0f75e6 src/dsync/dsync-worker-private.h
--- a/src/dsync/dsync-worker-private.h	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/dsync/dsync-worker-private.h	Thu Dec 08 09:32:03 2011 +0200
@@ -50,7 +50,7 @@
 
 	void (*select_mailbox)(struct dsync_worker *worker,
 			       const mailbox_guid_t *mailbox,
-			       const ARRAY_TYPE(const_string) *cache_fields);
+			       const ARRAY_TYPE(mailbox_cache_field) *cache_fields);
 	void (*msg_update_metadata)(struct dsync_worker *worker,
 				    const struct dsync_message *msg);
 	void (*msg_update_uid)(struct dsync_worker *worker,
diff -r ddfe3a0f75e6 src/dsync/test-dsync-common.c
--- a/src/dsync/test-dsync-common.c	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/dsync/test-dsync-common.c	Thu Dec 08 09:32:03 2011 +0200
@@ -44,7 +44,7 @@
 bool dsync_mailboxes_equal(const struct dsync_mailbox *box1,
 			   const struct dsync_mailbox *box2)
 {
-	const char *const *f1 = NULL, *const *f2 = NULL;
+	const struct mailbox_cache_field *f1 = NULL, *f2 = NULL;
 	unsigned int i, f1_count = 0, f2_count = 0;
 
 	if (strcmp(box1->name, box2->name) != 0 ||
@@ -63,7 +63,9 @@
 	if (f1_count != f2_count)
 		return FALSE;
 	for (i = 0; i < f1_count; i++) {
-		if (strcmp(f1[i], f2[i]) != 0)
+		if (strcmp(f1[i].name, f2[i].name) != 0 ||
+		    f1[i].decision != f2[i].decision ||
+		    f1[i].last_used != f2[i].last_used)
 			return FALSE;
 	}
 	return TRUE;
diff -r ddfe3a0f75e6 src/dsync/test-dsync-proxy.c
--- a/src/dsync/test-dsync-proxy.c	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/dsync/test-dsync-proxy.c	Thu Dec 08 09:32:03 2011 +0200
@@ -3,6 +3,7 @@
 #include "lib.h"
 #include "array.h"
 #include "str.h"
+#include "mail-cache.h"
 #include "dsync-proxy.h"
 #include "test-dsync-common.h"
 #include "test-common.h"
@@ -85,8 +86,10 @@
 
 static void test_dsync_proxy_mailbox(void)
 {
-	static const char *cache1 = "cache1";
-	static const char *cache2 = "cache2";
+	static struct mailbox_cache_field cache1 =
+		{ "cache1", MAIL_CACHE_DECISION_NO, 1234 };
+	static struct mailbox_cache_field cache2 =
+		{ "cache2", MAIL_CACHE_DECISION_TEMP | MAIL_CACHE_DECISION_FORCED, 0 };
 	string_t *str;
 	struct dsync_mailbox box_in, box_out;
 	const char *error;
diff -r ddfe3a0f75e6 src/dsync/test-dsync-worker.c
--- a/src/dsync/test-dsync-worker.c	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/dsync/test-dsync-worker.c	Thu Dec 08 09:32:03 2011 +0200
@@ -285,7 +285,7 @@
 static void
 test_worker_select_mailbox(struct dsync_worker *_worker,
 			   const mailbox_guid_t *mailbox,
-			   const ARRAY_TYPE(const_string) *cache_fields)
+			   const ARRAY_TYPE(mailbox_cache_field) *cache_fields)
 {
 	struct test_dsync_worker *worker = (struct test_dsync_worker *)_worker;
 	struct dsync_mailbox box;
diff -r ddfe3a0f75e6 src/dsync/test-dsync-worker.h
--- a/src/dsync/test-dsync-worker.h	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/dsync/test-dsync-worker.h	Thu Dec 08 09:32:03 2011 +0200
@@ -83,7 +83,7 @@
 	mailbox_guid_t selected_mailbox;
 	mailbox_guid_t *msg_iter_mailboxes;
 	unsigned int msg_iter_mailbox_count;
-	const ARRAY_TYPE(const_string) *cache_fields;
+	const ARRAY_TYPE(mailbox_cache_field) *cache_fields;
 };
 
 struct dsync_worker *dsync_worker_init_test(void);
diff -r ddfe3a0f75e6 src/lib-index/mail-cache-compress.c
--- a/src/lib-index/mail-cache-compress.c	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/lib-index/mail-cache-compress.c	Thu Dec 08 09:32:03 2011 +0200
@@ -208,7 +208,7 @@
 			/* if the decision isn't forced and this field hasn't
 			   been accessed for a while, drop it */
 			if ((dec & MAIL_CACHE_DECISION_FORCED) == 0 &&
-			    (time_t)priv->last_used < max_drop_time &&
+			    priv->field.last_used < max_drop_time &&
 			    !priv->adding) {
 				dec = MAIL_CACHE_DECISION_NO;
 				priv->field.decision = dec;
@@ -218,7 +218,7 @@
 			if ((dec & ~MAIL_CACHE_DECISION_FORCED) ==
 			    MAIL_CACHE_DECISION_NO && !priv->adding) {
 				priv->used = FALSE;
-				priv->last_used = 0;
+				priv->field.last_used = 0;
 			}
 
 			ctx.field_file_map[i] = !priv->used ?
diff -r ddfe3a0f75e6 src/lib-index/mail-cache-decisions.c
--- a/src/lib-index/mail-cache-decisions.c	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/lib-index/mail-cache-decisions.c	Thu Dec 08 09:32:03 2011 +0200
@@ -85,9 +85,9 @@
 	mail_index_lookup_uid(view->view, seq, &uid);
 	hdr = mail_index_get_header(view->view);
 
-	if (ioloop_time - cache->fields[field].last_used > 3600*24) {
+	if (ioloop_time - cache->fields[field].field.last_used > 3600*24) {
 		/* update last_used about once a day */
-		cache->fields[field].last_used = (uint32_t)ioloop_time;
+		cache->fields[field].field.last_used = (uint32_t)ioloop_time;
 		if (cache->field_file_map[field] != (uint32_t)-1)
 			cache->field_header_write_pending = TRUE;
 	}
diff -r ddfe3a0f75e6 src/lib-index/mail-cache-fields.c
--- a/src/lib-index/mail-cache-fields.c	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/lib-index/mail-cache-fields.c	Thu Dec 08 09:32:03 2011 +0200
@@ -65,11 +65,35 @@
 	return 0;
 }
 
+static void
+mail_cache_field_update(struct mail_cache *cache,
+			const struct mail_cache_field *newfield)
+{
+	struct mail_cache_field_private *orig;
+
+	i_assert(newfield->type < MAIL_CACHE_FIELD_COUNT);
+
+	orig = &cache->fields[newfield->idx];
+	if (newfield->decision != MAIL_CACHE_DECISION_NO &&
+	    orig->field.decision != newfield->decision) {
+		orig->field.decision = newfield->decision;
+		orig->decision_dirty = TRUE;
+	}
+	if (orig->field.last_used < newfield->last_used) {
+		orig->field.last_used = newfield->last_used;
+		orig->decision_dirty = TRUE;
+	}
+	if (orig->decision_dirty)
+		cache->field_header_write_pending = TRUE;
+
+	(void)field_type_verify(cache, newfield->idx,
+				newfield->type, newfield->field_size);
+}
+
 void mail_cache_register_fields(struct mail_cache *cache,
 				struct mail_cache_field *fields,
 				unsigned int fields_count)
 {
-	struct mail_cache_field *orig_field;
 	void *orig_key, *orig_value;
 	char *name;
 	unsigned int new_idx;
@@ -80,18 +104,9 @@
 		if (hash_table_lookup_full(cache->field_name_hash,
 					   fields[i].name,
 					   &orig_key, &orig_value)) {
-			i_assert(fields[i].type < MAIL_CACHE_FIELD_COUNT);
-
 			fields[i].idx =
 				POINTER_CAST_TO(orig_value, unsigned int);
-
-			orig_field = &cache->fields[fields[i].idx].field;
-			if (orig_field->decision == MAIL_CACHE_DECISION_NO)
-				orig_field->decision = fields[i].decision;
-
-			(void)field_type_verify(cache, fields[i].idx,
-						fields[i].type,
-						fields[i].field_size);
+			mail_cache_field_update(cache, &fields[i]);
 			continue;
 		}
 
@@ -130,6 +145,7 @@
 		name = p_strdup(cache->field_pool, fields[i].name);
 		cache->fields[idx].field = fields[i];
 		cache->fields[idx].field.name = name;
+		cache->fields[idx].field.last_used = fields[i].last_used;
 		cache->field_file_map[idx] = (uint32_t)-1;
 
 		if (!field_has_fixed_size(cache->fields[idx].field.type))
@@ -387,12 +403,12 @@
 		cache->file_field_map[i] = fidx;
 
 		/* update last_used if it's newer than ours */
-		if (last_used[i] > cache->fields[fidx].last_used)
-			cache->fields[fidx].last_used = last_used[i];
+		if (last_used[i] > cache->fields[fidx].field.last_used)
+			cache->fields[fidx].field.last_used = last_used[i];
 
 		dec = cache->fields[fidx].field.decision;
-		if ((time_t)cache->fields[fidx].last_used < max_drop_time &&
-		    cache->fields[fidx].last_used != 0 &&
+		if (cache->fields[fidx].field.last_used < max_drop_time &&
+		    cache->fields[fidx].field.last_used != 0 &&
 		    (dec & MAIL_CACHE_DECISION_FORCED) == 0 &&
 		    dec != MAIL_CACHE_DECISION_NO) {
 			/* time to drop this field. don't bother dropping
@@ -469,7 +485,7 @@
 	buffer = buffer_create_dynamic(pool_datastack_create(), 256);
 
 	copy_to_buf(cache, buffer, FALSE,
-		    offsetof(struct mail_cache_field_private, last_used),
+		    offsetof(struct mail_cache_field, last_used),
 		    sizeof(uint32_t));
 	ret = mail_cache_write(cache, buffer->data, buffer->used,
 			       offset + MAIL_CACHE_FIELD_LAST_USED());
@@ -532,7 +548,7 @@
 
 	/* we have to keep the field order for the existing fields. */
 	copy_to_buf(cache, dest, TRUE,
-		    offsetof(struct mail_cache_field_private, last_used),
+		    offsetof(struct mail_cache_field, last_used),
 		    sizeof(uint32_t));
 	copy_to_buf(cache, dest, TRUE,
 		    offsetof(struct mail_cache_field, field_size),
diff -r ddfe3a0f75e6 src/lib-index/mail-cache-private.h
--- a/src/lib-index/mail-cache-private.h	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/lib-index/mail-cache-private.h	Thu Dec 08 09:32:03 2011 +0200
@@ -117,7 +117,6 @@
 	struct mail_cache_field field;
 
 	uint32_t uid_highwater;
-	uint32_t last_used;
 
 	/* Unused fields aren't written to cache file */
 	unsigned int used:1;
diff -r ddfe3a0f75e6 src/lib-index/mail-cache.h
--- a/src/lib-index/mail-cache.h	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/lib-index/mail-cache.h	Thu Dec 08 09:32:03 2011 +0200
@@ -38,6 +38,8 @@
 	enum mail_cache_field_type type;
 	unsigned int field_size;
 	enum mail_cache_decision_type decision;
+	/* If higher than the current last_used field, update it */
+	time_t last_used;
 };
 
 struct mail_cache *mail_cache_open_or_create(struct mail_index *index);
diff -r ddfe3a0f75e6 src/lib-storage/index/dbox-multi/mdbox-storage.c
--- a/src/lib-storage/index/dbox-multi/mdbox-storage.c	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/lib-storage/index/dbox-multi/mdbox-storage.c	Thu Dec 08 09:32:03 2011 +0200
@@ -401,8 +401,8 @@
 		if (mailbox_open(box) < 0)
 			return -1;
 	}
-	if (update->cache_fields != NULL)
-		index_storage_mailbox_update_cache_fields(box, update);
+	if (update->cache_updates != NULL)
+		index_storage_mailbox_update_cache(box, update);
 	return mdbox_write_index_header(box, update, NULL);
 }
 
diff -r ddfe3a0f75e6 src/lib-storage/index/dbox-single/sdbox-storage.c
--- a/src/lib-storage/index/dbox-single/sdbox-storage.c	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/lib-storage/index/dbox-single/sdbox-storage.c	Thu Dec 08 09:32:03 2011 +0200
@@ -287,8 +287,8 @@
 		if (mailbox_open(box) < 0)
 			return -1;
 	}
-	if (update->cache_fields != NULL)
-		index_storage_mailbox_update_cache_fields(box, update);
+	if (update->cache_updates != NULL)
+		index_storage_mailbox_update_cache(box, update);
 	return sdbox_mailbox_create_indexes(box, update, NULL);
 }
 
diff -r ddfe3a0f75e6 src/lib-storage/index/index-status.c
--- a/src/lib-storage/index/index-status.c	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/lib-storage/index/index-status.c	Thu Dec 08 09:32:03 2011 +0200
@@ -94,18 +94,23 @@
 {
 	const struct mail_cache_field *fields;
 	enum mail_cache_decision_type dec;
-	ARRAY_TYPE(const_string) *cache_fields;
+	ARRAY_TYPE(mailbox_cache_field) *cache_fields;
+	struct mailbox_cache_field *cf;
 	unsigned int i, count;
 
 	fields = mail_cache_register_get_list(box->cache,
 					      pool_datastack_create(), &count);
 
-	cache_fields = t_new(ARRAY_TYPE(const_string), 1);
+	cache_fields = t_new(ARRAY_TYPE(mailbox_cache_field), 1);
 	t_array_init(cache_fields, count);
 	for (i = 0; i < count; i++) {
 		dec = fields[i].decision & ~MAIL_CACHE_DECISION_FORCED;
-		if (dec != MAIL_CACHE_DECISION_NO)
-			array_append(cache_fields, &fields[i].name, 1);
+		if (dec != MAIL_CACHE_DECISION_NO) {
+			cf = array_append_space(cache_fields);
+			cf->name = fields[i].name;
+			cf->decision = fields[i].decision;
+			cf->last_used = fields[i].last_used;
+		}
 	}
 	metadata_r->cache_fields = cache_fields;
 }
diff -r ddfe3a0f75e6 src/lib-storage/index/index-storage.c
--- a/src/lib-storage/index/index-storage.c	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/lib-storage/index/index-storage.c	Thu Dec 08 09:32:03 2011 +0200
@@ -353,10 +353,10 @@
 		mail_index_alloc_cache_unref(&box->index);
 }
 
-void index_storage_mailbox_update_cache_fields(struct mailbox *box,
-					       const struct mailbox_update *update)
+void index_storage_mailbox_update_cache(struct mailbox *box,
+					const struct mailbox_update *update)
 {
-	const char *const *field_names = update->cache_fields;
+	const struct mailbox_cache_field *updates = update->cache_updates;
 	ARRAY_DEFINE(new_fields, struct mail_cache_field);
 	const struct mail_cache_field *old_fields;
 	struct mail_cache_field field;
@@ -368,28 +368,28 @@
 
 	/* There shouldn't be many fields, so don't worry about O(n^2). */
 	t_array_init(&new_fields, 32);
-	for (i = 0; field_names[i] != NULL; i++) {
+	for (i = 0; updates[i].name != NULL; i++) {
 		/* see if it's an existing field */
 		for (j = 0; j < old_count; j++) {
-			if (strcmp(field_names[i], old_fields[j].name) == 0)
+			if (strcmp(updates[i].name, old_fields[j].name) == 0)
 				break;
 		}
 		if (j != old_count) {
 			field = old_fields[j];
-			if (field.decision == MAIL_CACHE_DECISION_NO)
-				field.decision = MAIL_CACHE_DECISION_TEMP;
-			array_append(&new_fields, &field, 1);
-		} else if (strncmp(field_names[i], "hdr.", 4) == 0) {
+		} else if (strncmp(updates[i].name, "hdr.", 4) == 0) {
 			/* new header */
 			memset(&field, 0, sizeof(field));
-			field.name = field_names[i];
+			field.name = updates[i].name;
 			field.type = MAIL_CACHE_FIELD_HEADER;
-			field.decision = MAIL_CACHE_DECISION_TEMP;
-			array_append(&new_fields, &field, 1);
 		} else {
 			/* new unknown field. we can't do anything about
 			   this since we don't know its type */
+			continue;
 		}
+		field.decision = updates[i].decision;
+		if (updates[i].last_used != (time_t)-1)
+			field.last_used = updates[i].last_used;
+		array_append(&new_fields, &field, 1);
 	}
 	if (array_count(&new_fields) > 0) {
 		mail_cache_register_fields(box->cache,
@@ -408,8 +408,8 @@
 
 	if (mailbox_open(box) < 0)
 		return -1;
-	if (update->cache_fields != NULL)
-		index_storage_mailbox_update_cache_fields(box, update);
+	if (update->cache_updates != NULL)
+		index_storage_mailbox_update_cache(box, update);
 
 	/* make sure we get the latest index info */
 	(void)mail_index_refresh(box->index);
@@ -641,7 +641,7 @@
 {
 	T_BEGIN {
 		struct mailbox_metadata src_metadata;
-		const char *const *namep;
+		const struct mailbox_cache_field *field;
 		buffer_t *buf;
 
 		if (mailbox_get_metadata(src_mail->box,
@@ -650,9 +650,9 @@
 			i_unreached();
 
 		buf = buffer_create_dynamic(pool_datastack_create(), 1024);
-		array_foreach(src_metadata.cache_fields, namep) {
+		array_foreach(src_metadata.cache_fields, field) {
 			mail_copy_cache_field(ctx, src_mail, dest_seq,
-					      *namep, buf);
+					      field->name, buf);
 		}
 	} T_END;
 }
diff -r ddfe3a0f75e6 src/lib-storage/index/index-storage.h
--- a/src/lib-storage/index/index-storage.h	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/lib-storage/index/index-storage.h	Thu Dec 08 09:32:03 2011 +0200
@@ -69,8 +69,8 @@
 void index_storage_mailbox_free(struct mailbox *box);
 int index_storage_mailbox_update(struct mailbox *box,
 				 const struct mailbox_update *update);
-void index_storage_mailbox_update_cache_fields(struct mailbox *box,
-					       const struct mailbox_update *update);
+void index_storage_mailbox_update_cache(struct mailbox *box,
+					const struct mailbox_update *update);
 int index_storage_mailbox_delete(struct mailbox *box);
 int index_storage_mailbox_delete_dir(struct mailbox *box, bool mailbox_deleted);
 int index_storage_mailbox_rename(struct mailbox *src, struct mailbox *dest,
diff -r ddfe3a0f75e6 src/lib-storage/mail-storage.h
--- a/src/lib-storage/mail-storage.h	Thu Dec 08 09:30:14 2011 +0200
+++ b/src/lib-storage/mail-storage.h	Thu Dec 08 09:32:03 2011 +0200
@@ -225,12 +225,20 @@
 	unsigned int allow_new_keywords:1;
 };
 
+struct mailbox_cache_field {
+	const char *name;
+	int decision; /* enum mail_cache_decision_type */
+	/* last_used is unchanged, if it's (time_t)-1 */
+	time_t last_used;
+};
+ARRAY_DEFINE_TYPE(mailbox_cache_field, struct mailbox_cache_field);
+
 struct mailbox_metadata {
 	guid_128_t guid;
 	/* sum of virtual size of all messages in mailbox */
 	uint64_t virtual_size;
 	/* Fields that have "temp" or "yes" caching decision. */
-	const ARRAY_TYPE(const_string) *cache_fields;
+	const ARRAY_TYPE(mailbox_cache_field) *cache_fields;
 	/* Fields that should be precached */
 	enum mail_fetch_field precache_fields;
 };
@@ -242,8 +250,8 @@
 	uint32_t min_next_uid;
 	uint32_t min_first_recent_uid;
 	uint64_t min_highest_modseq;
-	/* Add these fields to be temporarily cached, if they aren't already. */
-	const char *const *cache_fields;
+	/* Modify caching decisions, terminated by name=NULL */
+	const struct mailbox_cache_field *cache_updates;
 };
 
 struct mail_transaction_commit_changes {

Reply via email to