diff src/lib-index/mail-cache-compress.c @ 2327:7d02e2a7672d HEAD

Header caching redesigned. New design allows caching decisions per field, so they can be divided to temporary/permanent. Cached headers are now always returned in original order, old code didn't guarantee it. Some other caching changes. (still missing code to store changes in caching decisions)
author Timo Sirainen <tss@iki.fi>
date Sun, 18 Jul 2004 05:25:06 +0300
parents ef0cd18d674c
children 406692edc12d
line wrap: on
line diff
--- a/src/lib-index/mail-cache-compress.c	Sun Jul 18 04:44:59 2004 +0300
+++ b/src/lib-index/mail-cache-compress.c	Sun Jul 18 05:25:06 2004 +0300
@@ -10,49 +10,40 @@
 
 struct mail_cache_copy_context {
 	int new_msg;
-	char field_seen[32], keep_fields[32], temp_fields[32];
-	buffer_t *buffer, *header;
+	buffer_t *buffer, *field_seen;
+	uint8_t field_seen_value;
 };
 
 static int
-mail_cache_compress_callback(struct mail_cache_view *view __attr_unused__,
-			     enum mail_cache_field field,
+mail_cache_compress_callback(struct mail_cache_view *view, uint32_t file_field,
 			     const void *data, size_t data_size, void *context)
 {
-        struct mail_cache_copy_context *ctx = context;
+	struct mail_cache_copy_context *ctx = context;
+	enum mail_cache_decision_type dec;
+	unsigned int field;
+	uint8_t *field_seen;
 	uint32_t size32;
-	int i;
 
+	field_seen = buffer_get_space_unsafe(ctx->field_seen, file_field, 1);
+	if (*field_seen == ctx->field_seen_value) {
+		/* duplicate */
+		return 1;
+	}
+	*field_seen = ctx->field_seen_value;
+
+	field = view->cache->file_field_map[file_field];
+	dec = view->cache->fields[field].decision & ~MAIL_CACHE_DECISION_FORCED;
 	if (ctx->new_msg) {
-		if (!ctx->temp_fields[field])
+		if (dec == MAIL_CACHE_DECISION_NO)
 			return 1;
 	} else {
-		if (!ctx->keep_fields[field])
+		if (dec != MAIL_CACHE_DECISION_YES)
 			return 1;
 	}
 
-	if (ctx->field_seen[field]) {
-		/* drop duplicates */
-		return 1;
-	}
-	ctx->field_seen[field] = TRUE;
+	buffer_append(ctx->buffer, &file_field, sizeof(file_field));
 
-	for (i = 0; i < MAIL_CACHE_HEADERS_COUNT; i++) {
-		if (mail_cache_header_fields[i] == field) {
-			/* it's header - save it into header field */
-			size32 = buffer_get_used_size(ctx->header);
-			if (size32 > 0) {
-				/* remove old terminating \0 */
-				buffer_set_used_size(ctx->header, size32-1);
-			}
-			buffer_append(ctx->header, data, data_size);
-			return 1;
-		}
-	}
-
-	buffer_append(ctx->buffer, &field, sizeof(field));
-
-	if (mail_cache_field_sizes[field] == (unsigned int)-1) {
+	if (view->cache->fields[field].field_size == (unsigned int)-1) {
 		size32 = (uint32_t)data_size;
 		buffer_append(ctx->buffer, &size32, sizeof(size32));
 	}
@@ -72,12 +63,11 @@
 	const struct mail_index_header *idx_hdr;
 	struct mail_cache_header hdr;
 	struct mail_cache_record cache_rec;
-        enum mail_cache_field field;
 	struct ostream *output;
-	const char *str;
-	uint32_t size32, message_count, seq, first_new_seq, old_offset;
+	buffer_t *buffer;
+	size_t size;
+	uint32_t message_count, seq, first_new_seq, old_offset;
 	uoff_t offset;
-	int i, ret, header_idx;
 
 	/* get sequence of first message which doesn't need it's temp fields
 	   removed. */
@@ -104,85 +94,44 @@
 	hdr.indexid = idx_hdr->indexid;
 	hdr.file_seq = idx_hdr->cache_file_seq + 1;
 
-	if (cache->hdr != NULL) {
-		memcpy(hdr.field_usage_decision_type,
-		       cache->hdr->field_usage_decision_type,
-		       sizeof(hdr.field_usage_decision_type));
-		memcpy(hdr.field_usage_last_used,
-		       cache->hdr->field_usage_last_used,
-		       sizeof(hdr.field_usage_last_used));
-	} else {
-		memcpy(hdr.field_usage_decision_type,
-		       cache->default_field_usage_decision_type,
-		       sizeof(hdr.field_usage_decision_type));
+	if (cache->fields_count != 0) {
+		hdr.field_header_offset =
+			mail_cache_uint32_to_offset(sizeof(hdr));
+	}
+	o_stream_send(output, &hdr, sizeof(hdr));
+
+	if (cache->fields_count != 0) {
+		t_push();
+		buffer = buffer_create_dynamic(pool_datastack_create(),
+					       256, (size_t)-1);
+		mail_cache_header_fields_get(cache, buffer);
+		o_stream_send(output, buffer_get_data(buffer, NULL),
+			      buffer_get_used_size(buffer));
+		t_pop();
 	}
 
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.buffer = buffer_create_dynamic(default_pool, 4096, (size_t)-1);
-	ctx.header = buffer_create_dynamic(default_pool, 4096, (size_t)-1);
-
-	for (i = 0; i < 32; i++) {
-		if (hdr.field_usage_decision_type[i] & MAIL_CACHE_DECISION_YES)
-			ctx.keep_fields[i] = TRUE;
-		else if (hdr.field_usage_decision_type[i] &
-			 MAIL_CACHE_DECISION_TEMP) {
-			ctx.temp_fields[i] = TRUE;
-			ctx.keep_fields[i] = TRUE;
-		}
-	}
-
-	o_stream_send(output, &hdr, sizeof(hdr));
-
-	/* merge all the header pieces into one. if some message doesn't have
-	   all the required pieces, we'll just have to drop them all. */
-	for (i = MAIL_CACHE_HEADERS_COUNT-1; i >= 0; i--) {
-		str = mail_cache_get_header_fields_str(cache, i);
-		if (str != NULL)
-			break;
-	}
-
-	if (str == NULL)
-		header_idx = -1;
-	else {
-		hdr.header_offsets[0] =
-			mail_cache_uint32_to_offset(output->offset);
-		header_idx = i;
-
-		size32 = strlen(str) + 1;
-		o_stream_send(output, &size32, sizeof(size32));
-		o_stream_send(output, str, size32);
-		if ((size32 & 3) != 0)
-			o_stream_send(output, null4, 4 - (size32 & 3));
-	}
+	ctx.field_seen = buffer_create_dynamic(default_pool, 64, (size_t)-1);
+	ctx.field_seen_value = 0;
 
 	mail_index_reset_cache(t, hdr.file_seq);
 
-	ret = 0;
 	for (seq = 1; seq <= message_count; seq++) {
 		ctx.new_msg = seq >= first_new_seq;
 		buffer_set_used_size(ctx.buffer, 0);
-		buffer_set_used_size(ctx.header, 0);
-		memset(ctx.field_seen, 0, sizeof(ctx.field_seen));
+
+		if (++ctx.field_seen_value == 0) {
+			memset(buffer_get_modifyable_data(ctx.field_seen, NULL),
+			       0, buffer_get_size(ctx.field_seen));
+			ctx.field_seen_value++;
+		}
 
 		memset(&cache_rec, 0, sizeof(cache_rec));
 		buffer_append(ctx.buffer, &cache_rec, sizeof(cache_rec));
 
-		mail_cache_foreach(cache_view, seq,
-				   mail_cache_compress_callback, &ctx);
-
-		size32 = buffer_get_used_size(ctx.header);
-		if (size32 > 0 && ctx.field_seen[header_idx]) {
-			field = MAIL_CACHE_HEADERS1;
-			buffer_append(ctx.buffer, &field, sizeof(field));
-			buffer_append(ctx.buffer, &size32, sizeof(size32));
-			buffer_append(ctx.buffer,
-				      buffer_get_data(ctx.header, NULL),
-				      size32);
-			if ((size32 & 3) != 0) {
-				buffer_append(ctx.buffer, null4,
-					      4 - (size32 & 3));
-			}
-		}
+		(void)mail_cache_foreach(cache_view, seq,
+					 mail_cache_compress_callback, &ctx);
 
 		cache_rec.size = buffer_get_used_size(ctx.buffer);
 		if (cache_rec.size == sizeof(cache_rec))
@@ -197,7 +146,6 @@
 	}
 	hdr.used_file_size = output->offset;
 	buffer_free(ctx.buffer);
-	buffer_free(ctx.header);
 
 	o_stream_seek(output, 0);
 	o_stream_send(output, &hdr, sizeof(hdr));
@@ -236,6 +184,12 @@
 		return -1;
 	locked = ret > 0;
 
+	/* get the latest info on fields */
+	if (mail_cache_header_fields_read(cache) < 0) {
+		if (locked) mail_cache_unlock(cache);
+		return -1;
+	}
+
 #ifdef DEBUG
 	i_warning("Compressing cache file %s", cache->filepath);
 #endif
@@ -246,6 +200,7 @@
 			       MAIL_CACHE_LOCK_IMMEDIATE_TIMEOUT, NULL, NULL);
 	if (fd == -1) {
 		mail_cache_set_syscall_error(cache, "file_dotlock_open()");
+		if (locked) mail_cache_unlock(cache);
 		return -1;
 	}
 
@@ -268,13 +223,11 @@
 
 			if (mail_cache_map(cache, 0, 0) < 0)
 				ret = -1;
+			else if (mail_cache_header_fields_read(cache) < 0)
+				ret = -1;
 		}
 	}
 
-	/* headers could have changed, reread them */
-	memset(cache->split_offsets, 0, sizeof(cache->split_offsets));
-	memset(cache->split_headers, 0, sizeof(cache->split_headers));
-
 	if (locked)
 		mail_cache_unlock(cache);