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