dovecot: Optimized cache record loop tracking.

dovecot at dovecot.org dovecot at dovecot.org
Sun Mar 2 02:50:01 EET 2008


details:   http://hg.dovecot.org/dovecot/rev/fea46320f834
changeset: 7307:fea46320f834
user:      Timo Sirainen <tss at iki.fi>
date:      Sun Mar 02 02:49:55 2008 +0200
description:
Optimized cache record loop tracking.

diffstat:

4 files changed, 55 insertions(+), 41 deletions(-)
src/lib-index/mail-cache-lookup.c      |   46 ++++++++++++++++++++------------
src/lib-index/mail-cache-private.h     |   17 ++++++++---
src/lib-index/mail-cache-transaction.c |   31 +++++++++------------
src/lib-index/mail-cache.c             |    2 -

diffs (193 lines):

diff -r 29a6eec987e5 -r fea46320f834 src/lib-index/mail-cache-lookup.c
--- a/src/lib-index/mail-cache-lookup.c	Sat Mar 01 00:15:30 2008 +0200
+++ b/src/lib-index/mail-cache-lookup.c	Sun Mar 02 02:49:55 2008 +0200
@@ -105,18 +105,29 @@ mail_cache_lookup_offset(struct mail_cac
 	return 1;
 }
 
-bool mail_cache_track_loops(ARRAY_TYPE(uint32_t) *array, uint32_t offset)
-{
-	const uint32_t *offsets;
-	unsigned int i, count;
-
-	offsets = array_get(array, &count);
-	for (i = 0; i < count; i++) {
-		if (offsets[i] == offset)
-			return TRUE;
-	}
-	array_append(array, &offset, 1);
-	return FALSE;
+bool mail_cache_track_loops(struct mail_cache_loop_track *loop_track,
+			    uoff_t offset, uoff_t size)
+{
+	i_assert(offset != 0);
+	i_assert(size != 0);
+
+	/* looping happens only in rare error conditions, so it's enough if we
+	   just catch it eventually. we do this by checking if we've seen
+	   more record data than possible in the accessed file area. */
+	if (loop_track->size_sum == 0) {
+		/* first call */
+		loop_track->min_offset = offset;
+		loop_track->max_offset = offset + size;
+	} else {
+		if (loop_track->min_offset > offset)
+			loop_track->min_offset = offset;
+		if (loop_track->max_offset < offset + size)
+			loop_track->max_offset = offset + size;
+	}
+
+	loop_track->size_sum += size;
+	return loop_track->size_sum >
+		(loop_track->max_offset - loop_track->min_offset);
 }
 
 void mail_cache_lookup_iter_init(struct mail_cache_view *view, uint32_t seq,
@@ -143,7 +154,7 @@ void mail_cache_lookup_iter_init(struct 
 	}
 	ctx->remap_counter = view->cache->remap_counter;
 
-	array_clear(&view->looping_offsets);
+	memset(&view->loop_track, 0, sizeof(view->loop_track));
 }
 
 static int
@@ -168,17 +179,18 @@ mail_cache_lookup_iter_next_record(struc
 
 		ctx->appends_checked = TRUE;
 		ctx->remap_counter = view->cache->remap_counter;
-		array_clear(&view->looping_offsets);
+		memset(&view->loop_track, 0, sizeof(view->loop_track));
 	}
 
 	/* look up the next record */
-	if (mail_cache_track_loops(&view->looping_offsets, ctx->offset)) {
+	if (mail_cache_get_record(view->cache, ctx->offset, &ctx->rec) < 0)
+		return -1;
+	if (mail_cache_track_loops(&view->loop_track, ctx->offset,
+				   ctx->rec->size)) {
 		mail_cache_set_corrupted(view->cache,
 					 "record list is circular");
 		return -1;
 	}
-	if (mail_cache_get_record(view->cache, ctx->offset, &ctx->rec) < 0)
-		return -1;
 	ctx->remap_counter = view->cache->remap_counter;
 
 	ctx->pos = sizeof(*ctx->rec);
diff -r 29a6eec987e5 -r fea46320f834 src/lib-index/mail-cache-private.h
--- a/src/lib-index/mail-cache-private.h	Sat Mar 01 00:15:30 2008 +0200
+++ b/src/lib-index/mail-cache-private.h	Sun Mar 02 02:49:55 2008 +0200
@@ -175,6 +175,12 @@ struct mail_cache {
 	unsigned int field_header_write_pending:1;
 };
 
+struct mail_cache_loop_track {
+	/* we're looping if size_sum > (max_offset-min_offset) */
+	uoff_t min_offset, max_offset;
+	uoff_t size_sum;
+};
+
 struct mail_cache_view {
 	struct mail_cache *cache;
 	struct mail_index_view *view, *trans_view;
@@ -182,8 +188,7 @@ struct mail_cache_view {
 	struct mail_cache_transaction_ctx *transaction;
 	uint32_t trans_seq1, trans_seq2;
 
-	/* temporary array, just to avoid mallocs. */
-	ARRAY_TYPE(uint32_t) looping_offsets;
+	struct mail_cache_loop_track loop_track;
 
 	/* if cached_exists_buf[field] == cached_exists_value, it's cached.
 	   this allows us to avoid constantly clearing the whole buffer.
@@ -236,9 +241,11 @@ int mail_cache_get_record(struct mail_ca
 			  const struct mail_cache_record **rec_r);
 uint32_t mail_cache_get_first_new_seq(struct mail_index_view *view);
 
-/* Returns TRUE if offset is already in given array. Otherwise return FALSE
-   and add the offset to the array. */
-bool mail_cache_track_loops(ARRAY_TYPE(uint32_t) *array, uint32_t offset);
+/* Returns TRUE if offset..size area has been tracked before.
+   Returns FALSE if the area may or may not have been tracked before,
+   but we don't know for sure yet. */
+bool mail_cache_track_loops(struct mail_cache_loop_track *loop_track,
+			    uoff_t offset, uoff_t size);
 
 /* Iterate through a message's cached fields. */
 void mail_cache_lookup_iter_init(struct mail_cache_view *view, uint32_t seq,
diff -r 29a6eec987e5 -r fea46320f834 src/lib-index/mail-cache-transaction.c
--- a/src/lib-index/mail-cache-transaction.c	Sat Mar 01 00:15:30 2008 +0200
+++ b/src/lib-index/mail-cache-transaction.c	Sun Mar 02 02:49:55 2008 +0200
@@ -1072,7 +1072,8 @@ static int mail_cache_delete_real(struct
 static int mail_cache_delete_real(struct mail_cache *cache, uint32_t offset)
 {
 	const struct mail_cache_record *rec;
-	ARRAY_TYPE(uint32_t) looping_offsets;
+	struct mail_cache_loop_track loop_track;
+	int ret = 0;
 
 	i_assert(cache->locked);
 
@@ -1081,30 +1082,26 @@ static int mail_cache_delete_real(struct
 	   the data. also it's actually useful as some index views are still
 	   able to ask cached data from messages that have already been
 	   expunged. */
-	t_array_init(&looping_offsets, 8);
-	array_append(&looping_offsets, &offset, 1);
-	while (mail_cache_get_record(cache, offset, &rec) == 0) {
+	memset(&loop_track, 0, sizeof(loop_track));
+	while (offset != 0 &&
+	       (ret = mail_cache_get_record(cache, offset, &rec)) == 0) {
+		if (mail_cache_track_loops(&loop_track, offset, rec->size)) {
+			mail_cache_set_corrupted(cache,
+						 "record list is circular");
+			return -1;
+		}
+
 		cache->hdr_copy.deleted_space += rec->size;
 		offset = rec->prev_offset;
-
-		if (offset == 0) {
-			/* successfully got to the end of the list */
-			return 0;
-		}
-
-		if (mail_cache_track_loops(&looping_offsets, offset)) {
-			mail_cache_set_corrupted(cache,
-						 "record list is circular");
-			return -1;
-		}
-	}
-	return -1;
+	}
+	return ret;
 }
 
 int mail_cache_delete(struct mail_cache *cache, uint32_t offset)
 {
 	int ret;
 
+	i_assert(cache->locked);
 	T_BEGIN {
 		ret = mail_cache_delete_real(cache, offset);
 	} T_END;
diff -r 29a6eec987e5 -r fea46320f834 src/lib-index/mail-cache.c
--- a/src/lib-index/mail-cache.c	Sat Mar 01 00:15:30 2008 +0200
+++ b/src/lib-index/mail-cache.c	Sun Mar 02 02:49:55 2008 +0200
@@ -656,7 +656,6 @@ mail_cache_view_open(struct mail_cache *
 	view = i_new(struct mail_cache_view, 1);
 	view->cache = cache;
 	view->view = iview;
-	i_array_init(&view->looping_offsets, 32);
 	view->cached_exists_buf =
 		buffer_create_dynamic(default_pool,
 				      cache->file_fields_count + 10);
@@ -670,7 +669,6 @@ void mail_cache_view_close(struct mail_c
 	if (view->cache->field_header_write_pending)
                 (void)mail_cache_header_fields_update(view->cache);
 
-	array_free(&view->looping_offsets);
 	buffer_free(&view->cached_exists_buf);
 	i_free(view);
 }


More information about the dovecot-cvs mailing list