dovecot: Cache code cleanups

dovecot at dovecot.org dovecot at dovecot.org
Thu Jun 14 03:20:22 EEST 2007


details:   http://hg.dovecot.org/dovecot/rev/5f0832288007
changeset: 5734:5f0832288007
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Jun 14 03:20:18 2007 +0300
description:
Cache code cleanups

diffstat:

5 files changed, 207 insertions(+), 220 deletions(-)
src/lib-index/mail-cache-decisions.c   |    4 
src/lib-index/mail-cache-lookup.c      |  351 ++++++++++++++++----------------
src/lib-index/mail-cache-private.h     |   10 
src/lib-index/mail-cache-transaction.c |   58 +----
src/lib-index/mail-cache.c             |    4 

diffs (truncated from 753 to 300 lines):

diff -r 4b5ce642957d -r 5f0832288007 src/lib-index/mail-cache-decisions.c
--- a/src/lib-index/mail-cache-decisions.c	Thu Jun 14 03:05:51 2007 +0300
+++ b/src/lib-index/mail-cache-decisions.c	Thu Jun 14 03:20:18 2007 +0300
@@ -70,8 +70,8 @@
 #include "ioloop.h"
 #include "mail-cache-private.h"
 
-void mail_cache_decision_lookup(struct mail_cache_view *view, uint32_t seq,
-				unsigned int field)
+void mail_cache_decision_state_update(struct mail_cache_view *view,
+				      uint32_t seq, unsigned int field)
 {
 	struct mail_cache *cache = view->cache;
 	const struct mail_index_header *hdr;
diff -r 4b5ce642957d -r 5f0832288007 src/lib-index/mail-cache-lookup.c
--- a/src/lib-index/mail-cache-lookup.c	Thu Jun 14 03:05:51 2007 +0300
+++ b/src/lib-index/mail-cache-lookup.c	Thu Jun 14 03:20:18 2007 +0300
@@ -13,39 +13,38 @@ int mail_cache_get_record(struct mail_ca
 int mail_cache_get_record(struct mail_cache *cache, uint32_t offset,
 			  const struct mail_cache_record **rec_r)
 {
-	const struct mail_cache_record *cache_rec;
-
-	*rec_r = NULL;
-	if (offset == 0)
-		return 0;
-
-	if (mail_cache_map(cache, offset,
-			   sizeof(*cache_rec) + CACHE_PREFETCH) < 0)
-		return -1;
-
-	if (offset + sizeof(*cache_rec) > cache->mmap_length) {
+	const struct mail_cache_record *rec;
+
+	i_assert(offset != 0);
+
+	/* we don't know yet how large the record is, so just guess */
+	if (mail_cache_map(cache, offset, sizeof(*rec) + CACHE_PREFETCH) < 0)
+		return -1;
+
+	if (offset + sizeof(*rec) > cache->mmap_length) {
 		mail_cache_set_corrupted(cache, "record points outside file");
 		return -1;
 	}
-	cache_rec = CACHE_RECORD(cache, offset);
-
-	if (cache_rec->size < sizeof(*cache_rec)) {
+	rec = CACHE_RECORD(cache, offset);
+
+	if (rec->size < sizeof(*rec)) {
 		mail_cache_set_corrupted(cache, "invalid record size");
 		return -1;
 	}
-	if (cache_rec->size > CACHE_PREFETCH) {
-		if (mail_cache_map(cache, offset, cache_rec->size) < 0)
+	if (rec->size > CACHE_PREFETCH) {
+		/* larger than we guessed. map the rest of the record. */
+		if (mail_cache_map(cache, offset, rec->size) < 0)
 			return -1;
-		cache_rec = CACHE_RECORD(cache, offset);
-	}
-
-	if (cache_rec->size > cache->mmap_length ||
-	    offset + cache_rec->size > cache->mmap_length) {
+		rec = CACHE_RECORD(cache, offset);
+	}
+
+	if (rec->size > cache->mmap_length ||
+	    offset + rec->size > cache->mmap_length) {
 		mail_cache_set_corrupted(cache, "record points outside file");
 		return -1;
 	}
 
-	*rec_r = cache_rec;
+	*rec_r = rec;
 	return 0;
 }
 
@@ -62,30 +61,31 @@ mail_cache_lookup_offset(struct mail_cac
 	if (mail_index_lookup_ext_full(view, seq, cache->ext_id,
 				       &map, &data) < 0)
 		return -1;
-	if (data == NULL)
+	if (data == NULL || *((const uint32_t *)data) == 0) {
+		/* nothing in cache (for this record) */
 		return 0;
-
-	if (!mail_index_map_get_ext_idx(map, cache->ext_id, &idx)) {
-		/* no cache */
-		return 0;
-	}
-
+	}
+
+	if (!mail_index_map_get_ext_idx(map, cache->ext_id, &idx))
+		i_unreached();
 	ext = array_idx(&map->extensions, idx);
 
-	for (i = 0; i < 2; i++) {
-		if (cache->hdr->file_seq == ext->reset_id) {
-			*offset_r = *((const uint32_t *)data);
-			return 1;
-		}
-
-		if ((ret = mail_cache_reopen(cache)) <= 0)
+	/* reset_id must match file_seq or the offset is for a different cache
+	   file. if this happens, try if reopening the cache helps. if not,
+	   it was probably for an old cache file that's already lost by now. */
+	i = 0;
+	while (cache->hdr->file_seq != ext->reset_id) {
+		if (++i == 2)
+			return 0;
+
+		if ((ret = mail_cache_reopen(cache)) <= 0) {
+			/* error / we already have the latest file open */
 			return ret;
-
-		if (MAIL_CACHE_IS_UNUSABLE(cache))
-			return 0;
-	}
-
-	return 0;
+		}
+	}
+
+	*offset_r = *((const uint32_t *)data);
+	return 1;
 }
 
 static int
@@ -93,30 +93,18 @@ mail_cache_foreach_rec(struct mail_cache
 		       mail_cache_foreach_callback_t *callback, void *context)
 {
 	struct mail_cache *cache = view->cache;
-	const struct mail_cache_record *cache_rec;
-	size_t pos, next_pos, max_size;
+	const struct mail_cache_record *rec;
 	unsigned int data_size;
-	uint32_t file_field;
+	uint32_t pos, rec_size, file_field;
 	unsigned int field;
 	int ret;
 
-	if (mail_cache_get_record(view->cache, *offset, &cache_rec) < 0)
-		return -1;
-	if (cache_rec == NULL) {
-		*offset = 0;
-		return 1;
-	}
-
-	max_size = cache_rec->size;
-	if (max_size < sizeof(*cache_rec) + sizeof(uint32_t)*2) {
-		mail_cache_set_corrupted(cache, "record has invalid size");
-		return -1;
-	}
-	max_size -= sizeof(uint32_t);
-
-	for (pos = sizeof(*cache_rec); pos < max_size; ) {
-		file_field =
-			*((const uint32_t *)CONST_PTR_OFFSET(cache_rec, pos));
+	if (mail_cache_get_record(view->cache, *offset, &rec) < 0)
+		return -1;
+
+	rec_size = rec->size;
+	for (pos = sizeof(*rec); pos + sizeof(uint32_t) <= rec_size; ) {
+		file_field = *((const uint32_t *)CONST_PTR_OFFSET(rec, pos));
 		pos += sizeof(uint32_t);
 
 		if (file_field >= cache->file_fields_count) {
@@ -132,50 +120,60 @@ mail_cache_foreach_rec(struct mail_cache
 			}
 
 			/* field reading might have re-mmaped the file and
-			   caused cache_rec to break. need to get it again. */
+			   caused rec pointer to break. need to get it again. */
 			if (mail_cache_get_record(view->cache, *offset,
-						  &cache_rec) < 0)
+						  &rec) < 0)
 				return -1;
-			i_assert(cache_rec != NULL);
 		}
 
 		field = cache->file_field_map[file_field];
 		data_size = cache->fields[field].field.field_size;
 		if (data_size == (unsigned int)-1) {
-			data_size = *((const uint32_t *)
-				      CONST_PTR_OFFSET(cache_rec, pos));
-			pos += sizeof(uint32_t);
-		}
-
-		next_pos = pos + ((data_size + 3) & ~3);
-		if (data_size > cache_rec->size || next_pos > cache_rec->size) {
+			/* variable size field. get its size from the file. */
+			if (pos + sizeof(uint32_t) > rec_size) {
+				/* broken. we'll catch this error below. */
+			} else {
+				data_size = *((const uint32_t *)
+					      CONST_PTR_OFFSET(rec, pos));
+				pos += sizeof(uint32_t);
+			}
+		}
+
+		if (rec_size - pos < data_size) {
 			mail_cache_set_corrupted(cache,
 				"record continues outside its allocated size");
 			return -1;
 		}
 
-		ret = callback(view, field, CONST_PTR_OFFSET(cache_rec, pos),
+		ret = callback(view, field, CONST_PTR_OFFSET(rec, pos),
 			       data_size, context);
 		if (ret != 1)
 			return ret;
 
-		pos = next_pos;
-	}
-
-	*offset = cache_rec->prev_offset;
-	return 1;
-}
-
-static bool find_offset(struct mail_cache_view *view, uint32_t offset)
+		/* each record begins from 32bit aligned position */
+		pos += (data_size + sizeof(uint32_t)-1) & ~(sizeof(uint32_t)-1);
+	}
+
+	if (pos != rec_size) {
+		mail_cache_set_corrupted(cache, "record has invalid size");
+		return -1;
+	}
+
+	*offset = rec->prev_offset;
+	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(&view->tmp_offsets, &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;
 }
 
@@ -196,14 +194,13 @@ int mail_cache_foreach(struct mail_cache
 		return ret;
 
 	ret = 1;
-	array_clear(&view->tmp_offsets);
+	array_clear(&view->looping_offsets);
 	while (offset != 0 && ret > 0) {
-		if (find_offset(view, offset)) {
+		if (mail_cache_track_loops(&view->looping_offsets, offset)) {
 			mail_cache_set_corrupted(view->cache,
 						 "record list is circular");
 			return -1;
 		}
-		array_append(&view->tmp_offsets, &offset, 1);
 		ret = mail_cache_foreach_rec(view, &offset,
 					     callback, context);
 	}
@@ -211,14 +208,14 @@ int mail_cache_foreach(struct mail_cache
 	if (ret > 0 && view->trans_seq1 <= seq && view->trans_seq2 >= seq &&
 	    mail_cache_lookup_offset(view->cache, view->trans_view,
 				     seq, &offset) > 0) {
-		array_clear(&view->tmp_offsets);
+		array_clear(&view->looping_offsets);
 		while (offset != 0 && ret > 0) {
-			if (find_offset(view, offset)) {
+			if (mail_cache_track_loops(&view->looping_offsets,
+						   offset)) {
 				mail_cache_set_corrupted(view->cache,
 					"record list is circular");
 				return -1;
 			}
-			array_append(&view->tmp_offsets, &offset, 1);
 			ret = mail_cache_foreach_rec(view, &offset,
 						     callback, context);
 		}
@@ -244,9 +241,7 @@ static int mail_cache_seq(struct mail_ca
 
 	if (++view->cached_exists_value == 0) {
 		/* wrapped, we'll have to clear the buffer */
-		memset(buffer_get_modifiable_data(view->cached_exists_buf,
-						  NULL), 0,
-		       buffer_get_size(view->cached_exists_buf));
+		buffer_reset(view->cached_exists_buf);
 		view->cached_exists_value++;
 	}
 
@@ -255,31 +250,35 @@ static int mail_cache_seq(struct mail_ca
 	return ret < 0 ? -1 : 0;
 }
 


More information about the dovecot-cvs mailing list