dovecot-1.1: Optimized cache record loop tracking.
dovecot at dovecot.org
dovecot at dovecot.org
Sun Mar 2 02:50:05 EET 2008
details: http://hg.dovecot.org/dovecot-1.1/rev/6f59434cf229
changeset: 7312:6f59434cf229
user: Timo Sirainen <tss at iki.fi>
date: Sun Mar 02 02:50:00 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 fce616c59597 -r 6f59434cf229 src/lib-index/mail-cache-lookup.c
--- a/src/lib-index/mail-cache-lookup.c Sat Mar 01 00:15:34 2008 +0200
+++ b/src/lib-index/mail-cache-lookup.c Sun Mar 02 02:50:00 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 fce616c59597 -r 6f59434cf229 src/lib-index/mail-cache-private.h
--- a/src/lib-index/mail-cache-private.h Sat Mar 01 00:15:34 2008 +0200
+++ b/src/lib-index/mail-cache-private.h Sun Mar 02 02:50:00 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 fce616c59597 -r 6f59434cf229 src/lib-index/mail-cache-transaction.c
--- a/src/lib-index/mail-cache-transaction.c Sat Mar 01 00:15:34 2008 +0200
+++ b/src/lib-index/mail-cache-transaction.c Sun Mar 02 02:50:00 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 fce616c59597 -r 6f59434cf229 src/lib-index/mail-cache.c
--- a/src/lib-index/mail-cache.c Sat Mar 01 00:15:34 2008 +0200
+++ b/src/lib-index/mail-cache.c Sun Mar 02 02:50:00 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