# HG changeset patch # User Timo Sirainen # Date 1199931803 -7200 # Node ID 876c7bca351cb6f6c6cb0f974c104f7a2c82f02a # Parent c33c87781ab45438b1aaaee9e4656f785171d31e Link cache records together directly when writing the new records, instead of delaying them until later and causing lots of small writes. We still do this delayed check and do the writes when it's required, but it shouldn't happen normally. diff -r c33c87781ab4 -r 876c7bca351c src/lib-index/mail-cache-lookup.c --- a/src/lib-index/mail-cache-lookup.c Mon Jan 07 12:49:40 2008 +0200 +++ b/src/lib-index/mail-cache-lookup.c Thu Jan 10 04:23:23 2008 +0200 @@ -48,24 +48,39 @@ return 0; } +uint32_t mail_cache_lookup_cur_offset(struct mail_index_view *view, + uint32_t seq, uint32_t *reset_id_r) +{ + struct mail_cache *cache = mail_index_view_get_index(view)->cache; + struct mail_index_map *map; + const void *data; + uint32_t offset; + + mail_index_lookup_ext_full(view, seq, cache->ext_id, + &map, &data, NULL); + if (data == NULL) { + /* no cache offsets */ + return 0; + } + offset = *((const uint32_t *)data); + if (offset == 0) + return 0; + + if (!mail_index_ext_get_reset_id(view, map, cache->ext_id, reset_id_r)) + i_unreached(); + return offset; +} + static int mail_cache_lookup_offset(struct mail_cache *cache, struct mail_index_view *view, uint32_t seq, uint32_t *offset_r) { - struct mail_index_map *map; - const void *data; - uint32_t reset_id; + uint32_t offset, reset_id; int i, ret; - mail_index_lookup_ext_full(view, seq, cache->ext_id, - &map, &data, NULL); - if (data == NULL || *((const uint32_t *)data) == 0) { - /* nothing in cache (for this record) */ + offset = mail_cache_lookup_cur_offset(view, seq, &reset_id); + if (offset == 0) return 0; - } - - if (!mail_index_ext_get_reset_id(view, map, cache->ext_id, &reset_id)) - i_unreached(); /* 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, @@ -86,7 +101,7 @@ } } - *offset_r = *((const uint32_t *)data); + *offset_r = offset; return 1; } diff -r c33c87781ab4 -r 876c7bca351c src/lib-index/mail-cache-private.h --- a/src/lib-index/mail-cache-private.h Mon Jan 07 12:49:40 2008 +0200 +++ b/src/lib-index/mail-cache-private.h Thu Jan 10 04:23:23 2008 +0200 @@ -230,6 +230,8 @@ int mail_cache_header_fields_get_next_offset(struct mail_cache *cache, uint32_t *offset_r); +uint32_t mail_cache_lookup_cur_offset(struct mail_index_view *view, + uint32_t seq, uint32_t *reset_id_r); int mail_cache_get_record(struct mail_cache *cache, uint32_t offset, const struct mail_cache_record **rec_r); uint32_t mail_cache_get_first_new_seq(struct mail_index_view *view); diff -r c33c87781ab4 -r 876c7bca351c src/lib-index/mail-cache-transaction.c --- a/src/lib-index/mail-cache-transaction.c Mon Jan 07 12:49:40 2008 +0200 +++ b/src/lib-index/mail-cache-transaction.c Thu Jan 10 04:23:23 2008 +0200 @@ -673,6 +673,7 @@ struct mail_cache_record *rec, new_rec; void *data; size_t size; + uint32_t reset_id; if (ctx->prev_seq != 0) { /* fix record size */ @@ -681,6 +682,15 @@ rec->size = size - ctx->prev_pos; i_assert(rec->size > sizeof(*rec)); + /* set prev_offset if possible */ + rec->prev_offset = + mail_cache_lookup_cur_offset(ctx->view->view, + ctx->prev_seq, &reset_id); + if (reset_id != ctx->cache->hdr->file_seq) + rec->prev_offset = 0; + else + ctx->cache->hdr_copy.continued_record_count++; + array_append(&ctx->cache_data_seq, &ctx->prev_seq, 1); ctx->prev_pos = size; } else if (ctx->cache_data == NULL) { @@ -1025,18 +1035,36 @@ int mail_cache_link(struct mail_cache *cache, uint32_t old_offset, uint32_t new_offset) { + const struct mail_cache_record *rec; + i_assert(cache->locked); if (MAIL_CACHE_IS_UNUSABLE(cache)) return -1; - if (new_offset + sizeof(struct mail_cache_record) > - cache->hdr_copy.used_file_size) { + /* this function is called for each added cache record (or cache + extension record update actually) with new_offset pointing to the + new record and old_offset pointing to the previous record. + + we want to keep the old and new records linked so both old and new + cached data is found. normally they are already linked correctly. + the problem only comes when multiple processes are adding cache + records at the same time. we'd rather not lose those additions, so + force the linking order to be new_offset -> old_offset if it isn't + already. */ + if (mail_cache_map(cache, new_offset, sizeof(*rec)) < 0) + return -1; + if (new_offset + sizeof(*rec) > cache->mmap_length) { mail_cache_set_corrupted(cache, "Cache record offset %u points outside file", new_offset); return -1; } + rec = CACHE_RECORD(cache, new_offset); + if (rec->prev_offset == old_offset) { + /* link is already correct */ + return 0; + } if (mail_cache_link_unlocked(cache, old_offset, new_offset) < 0) return -1;