]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Cache file compression works now and compressed cache file is reopened.
authorTimo Sirainen <tss@iki.fi>
Sun, 4 Jul 2004 11:50:48 +0000 (14:50 +0300)
committerTimo Sirainen <tss@iki.fi>
Sun, 4 Jul 2004 11:50:48 +0000 (14:50 +0300)
Several other cleanups related to opening - cache file isn't created
immediately anymore.

--HG--
branch : HEAD

src/lib-index/mail-cache-compress.c
src/lib-index/mail-cache-decisions.c
src/lib-index/mail-cache-lookup.c
src/lib-index/mail-cache-private.h
src/lib-index/mail-cache-transaction.c
src/lib-index/mail-cache.c
src/lib-index/mail-cache.h
src/lib-index/mail-index-sync.c
src/lib-storage/index/index-mail.c
src/lib-storage/index/index-storage.h

index 56c004d69e47fb46127bcf5fc7d2cc4eaf1d7ac7..555ff7ffd8f055b3fbc58155e2dcbb31dad785c6 100644 (file)
@@ -4,6 +4,7 @@
 #include "buffer.h"
 #include "byteorder.h"
 #include "ostream.h"
+#include "file-set-size.h"
 #include "mail-cache-private.h"
 
 static unsigned char null4[4] = { 0, 0, 0, 0 };
@@ -100,39 +101,46 @@ mail_cache_copy(struct mail_cache *cache, struct mail_index_view *view, int fd)
           removed. */
        if (mail_index_get_header(view, &idx_hdr) < 0)
                return -1;
-       if (mail_index_lookup_uid_range(view, idx_hdr->day_first_uid[7],
-                                       (uint32_t)-1, &first_new_seq,
-                                       &message_count) < 0)
-               return -1;
-       if (first_new_seq == 0)
-               first_new_seq = message_count+1;
+       if (idx_hdr->day_first_uid[7] == 0) {
+               first_new_seq = 1;
+               message_count = mail_index_view_get_message_count(view);
+       } else {
+               if (mail_index_lookup_uid_range(view, idx_hdr->day_first_uid[7],
+                                               (uint32_t)-1, &first_new_seq,
+                                               &message_count) < 0)
+                       return -1;
+               if (first_new_seq == 0)
+                       first_new_seq = message_count+1;
+       }
 
        cache_view = mail_cache_view_open(cache, view);
        t = mail_index_transaction_begin(view, FALSE);
        output = o_stream_create_file(fd, default_pool, 0, FALSE);
 
        memset(&hdr, 0, sizeof(hdr));
-       hdr.indexid = cache->hdr->indexid;
-       hdr.file_seq = cache->hdr->file_seq + 1;
-
-       memcpy(hdr.field_usage_decision_type,
-              cache->hdr->field_usage_decision_type,
-              sizeof(hdr.field_usage_decision_type));
-       memcpy(hdr.field_usage_last_used,
-              cache->hdr->field_usage_last_used,
-              sizeof(hdr.field_usage_last_used));
-
-        keep_fields = temp_fields = 0;
-       for (i = 0; i < 32; i++) {
-               if (cache->hdr->field_usage_decision_type[i] &
-                   MAIL_CACHE_DECISION_YES)
-                       keep_fields |= 1 << i;
-               else if (cache->hdr->field_usage_decision_type[i] &
-                        MAIL_CACHE_DECISION_TEMP)
-                       temp_fields |= 1 << i;
+       hdr.indexid = idx_hdr->indexid;
+       hdr.file_seq = idx_hdr->cache_file_seq + 1;
+
+       if (cache->hdr != NULL) {
+               memcpy(hdr.field_usage_decision_type,
+                      cache->hdr->field_usage_decision_type,
+                      sizeof(hdr.field_usage_decision_type));
+               memcpy(hdr.field_usage_last_used,
+                      cache->hdr->field_usage_last_used,
+                      sizeof(hdr.field_usage_last_used));
+
+               keep_fields = temp_fields = 0;
+               for (i = 0; i < 32; i++) {
+                       if (cache->hdr->field_usage_decision_type[i] &
+                           MAIL_CACHE_DECISION_YES)
+                               keep_fields |= 1 << i;
+                       else if (cache->hdr->field_usage_decision_type[i] &
+                                MAIL_CACHE_DECISION_TEMP)
+                               temp_fields |= 1 << i;
+               }
        }
 
-       offset = sizeof(hdr);
+       o_stream_send(output, &hdr, sizeof(hdr));
 
        /* merge all the header pieces into one. if some message doesn't have
           all the required pieces, we'll just have to drop them all. */
@@ -145,7 +153,8 @@ mail_cache_copy(struct mail_cache *cache, struct mail_index_view *view, int fd)
        if (str == NULL)
                header_idx = -1;
        else {
-               hdr.header_offsets[0] = mail_cache_uint32_to_offset(offset);
+               hdr.header_offsets[0] =
+                       mail_cache_uint32_to_offset(output->offset);
                header_idx = i;
 
                size = strlen(str) + 1;
@@ -198,9 +207,26 @@ mail_cache_copy(struct mail_cache *cache, struct mail_index_view *view, int fd)
        }
        hdr.used_file_size = uint32_to_nbo(output->offset);
 
-       o_stream_unref(output);
+       o_stream_seek(output, 0);
+       o_stream_send(output, &hdr, sizeof(hdr));
+
        mail_cache_view_close(cache_view);
 
+       if (o_stream_flush(output) < 0) {
+               errno = output->stream_errno;
+               mail_cache_set_syscall_error(cache, "o_stream_flush()");
+               (void)mail_index_transaction_rollback(t);
+               o_stream_unref(output);
+               return -1;
+       }
+
+       if (output->offset < MAIL_CACHE_INITIAL_SIZE) {
+               /* grow the file some more. doesn't matter if it fails */
+               (void)file_set_size(fd, MAIL_CACHE_INITIAL_SIZE);
+       }
+
+       o_stream_unref(output);
+
        if (fdatasync(fd) < 0) {
                mail_cache_set_syscall_error(cache, "fdatasync()");
                (void)mail_index_transaction_rollback(t);
@@ -212,12 +238,13 @@ mail_cache_copy(struct mail_cache *cache, struct mail_index_view *view, int fd)
 
 int mail_cache_compress(struct mail_cache *cache, struct mail_index_view *view)
 {
-       int fd, ret;
+       int fd, ret, locked;
 
        i_assert(cache->trans_ctx == NULL);
 
-       if ((ret = mail_cache_lock(cache, TRUE)) <= 0)
-               return ret;
+       if ((ret = mail_cache_lock(cache, TRUE)) < 0)
+               return -1;
+       locked = ret > 0;
 
 #ifdef DEBUG
        i_warning("Compressing cache file %s", cache->filepath);
@@ -232,6 +259,7 @@ int mail_cache_compress(struct mail_cache *cache, struct mail_index_view *view)
                return -1;
        }
 
+       ret = 0;
        if (mail_cache_copy(cache, view, fd) < 0) {
                (void)file_dotlock_delete(cache->filepath, NULL, fd);
                ret = -1;
@@ -246,7 +274,7 @@ int mail_cache_compress(struct mail_cache *cache, struct mail_index_view *view)
                        mail_cache_file_close(cache);
                        cache->fd = fd;
 
-                       if (mail_cache_mmap_update(cache, 0, 0) < 0)
+                       if (mail_cache_map(cache, 0, 0) < 0)
                                ret = -1;
                }
        }
@@ -255,8 +283,10 @@ int mail_cache_compress(struct mail_cache *cache, struct mail_index_view *view)
        memset(cache->split_offsets, 0, sizeof(cache->split_offsets));
        memset(cache->split_headers, 0, sizeof(cache->split_headers));
 
-       if (mail_cache_unlock(cache) < 0)
-               return -1;
+       if (locked) {
+               if (mail_cache_unlock(cache) < 0)
+                       return -1;
+       }
 
        if (ret == 0)
                 cache->need_compress = FALSE;
@@ -265,5 +295,5 @@ int mail_cache_compress(struct mail_cache *cache, struct mail_index_view *view)
 
 int mail_cache_need_compress(struct mail_cache *cache)
 {
-       return FALSE; //FIXME:cache->need_compress;
+       return cache->need_compress;
 }
index d26532b95a47cfd29867aba6b76535f882f8c0d8..870cf3e6dd6ec6afb118aa21a25d67500f7917be 100644 (file)
@@ -132,6 +132,9 @@ void mail_cache_mark_missing(struct mail_cache_view *view, uint32_t seq,
        unsigned int idx;
        uint32_t uid;
 
+       if (MAIL_CACHE_IS_UNUSABLE(view->cache))
+               return;
+
        idx = mail_cache_field_index(field);
        if (view->cache->hdr->field_usage_decision_type[idx] !=
            MAIL_CACHE_DECISION_NO) {
index b6b9c9f5b8e6e113d83c8629601daf204815ad35..ddd81c71d97f043ca057942dd0f510f07d1684a2 100644 (file)
@@ -13,7 +13,7 @@ mail_cache_get_header_fields_str(struct mail_cache *cache, unsigned int idx)
        uint32_t offset, data_size;
        unsigned char *buf;
 
-       if (cache->disabled)
+       if (MAIL_CACHE_IS_UNUSABLE(cache))
                return NULL;
 
        offset = mail_cache_offset_to_uint32(cache->hdr->header_offsets[idx]);
@@ -21,7 +21,7 @@ mail_cache_get_header_fields_str(struct mail_cache *cache, unsigned int idx)
        if (offset == 0)
                return NULL;
 
-       if (mail_cache_mmap_update(cache, offset, CACHE_PREFETCH) < 0)
+       if (mail_cache_map(cache, offset, CACHE_PREFETCH) < 0)
                return NULL;
 
        if (offset + sizeof(data_size) > cache->mmap_length) {
@@ -42,7 +42,7 @@ mail_cache_get_header_fields_str(struct mail_cache *cache, unsigned int idx)
        }
 
        if (data_size + sizeof(data_size) > CACHE_PREFETCH) {
-               if (mail_cache_mmap_update(cache, offset, data_size) < 0)
+               if (mail_cache_map(cache, offset, data_size) < 0)
                        return NULL;
        }
 
@@ -93,7 +93,7 @@ const char *const *mail_cache_get_header_fields(struct mail_cache_view *view,
 
        i_assert(idx < MAIL_CACHE_HEADERS_COUNT);
 
-       if (view->cache->disabled)
+       if (MAIL_CACHE_IS_UNUSABLE(view->cache))
                return NULL;
 
        /* t_strsplit() is a bit slow, so we cache it */
@@ -127,8 +127,8 @@ mail_cache_get_record(struct mail_cache *cache, uint32_t offset,
        if (offset == 0)
                return NULL;
 
-       if (mail_cache_mmap_update(cache, offset,
-                                  sizeof(*cache_rec) + CACHE_PREFETCH) < 0)
+       if (mail_cache_map(cache, offset,
+                          sizeof(*cache_rec) + CACHE_PREFETCH) < 0)
                return NULL;
 
        if (offset + sizeof(*cache_rec) > cache->mmap_length) {
@@ -143,7 +143,7 @@ mail_cache_get_record(struct mail_cache *cache, uint32_t offset,
                return NULL;
        }
        if (size > CACHE_PREFETCH) {
-               if (mail_cache_mmap_update(cache, offset, size) < 0)
+               if (mail_cache_map(cache, offset, size) < 0)
                        return NULL;
        }
 
@@ -154,42 +154,48 @@ mail_cache_get_record(struct mail_cache *cache, uint32_t offset,
        return cache_rec;
 }
 
-struct mail_cache_record *
-mail_cache_get_next_record(struct mail_cache *cache,
-                          struct mail_cache_record *rec)
+int mail_cache_lookup_offset(struct mail_cache_view *view, uint32_t seq,
+                            uint32_t *offset_r, int skip_expunged)
 {
-       struct mail_cache_record *next;
+       const struct mail_index_record *rec;
+       struct mail_index_map *map;
+       int i, ret;
+
+       for (i = 0; i < 2; i++) {
+               ret = mail_index_lookup_full(view->view, seq, &map, &rec);
+               if (ret < 0)
+                       return -1;
+               if (ret == 0 && skip_expunged)
+                       return 0;
+
+               if (map->hdr->cache_file_seq == view->cache->hdr->file_seq) {
+                       *offset_r = rec->cache_offset;
+                       return 1;
+               }
 
-       next = mail_cache_get_record(cache, rec->next_offset, FALSE);
-       if (next != NULL && next <= rec) {
-               mail_cache_set_corrupted(cache, "next_offset points backwards");
-               return NULL;
+               if ((ret = mail_cache_reopen(view->cache)) <= 0)
+                       return ret;
        }
-       return next;
+
+       return 0;
 }
 
 struct mail_cache_record *
 mail_cache_lookup(struct mail_cache_view *view, uint32_t seq,
                  enum mail_cache_field fields)
 {
-       const struct mail_index_record *rec;
-       struct mail_index_map *map;
+       uint32_t offset;
 
        if (mail_cache_transaction_autocommit(view, seq, fields) < 0)
                return NULL;
 
-       if (view->cache->disabled)
+       if (MAIL_CACHE_IS_UNUSABLE(view->cache))
                return NULL;
 
-       if (mail_index_lookup_full(view->view, seq, &map, &rec) < 0)
+       if (mail_cache_lookup_offset(view, seq, &offset, FALSE) <= 0)
                return NULL;
 
-       if (map->hdr->cache_file_seq != view->cache->hdr->file_seq) {
-               /* FIXME: we should check if newer file is available? */
-               return NULL;
-       }
-
-       return mail_cache_get_record(view->cache, rec->cache_offset, TRUE);
+       return mail_cache_get_record(view->cache, offset, TRUE);
 }
 
 enum mail_cache_field
@@ -201,7 +207,9 @@ mail_cache_get_fields(struct mail_cache_view *view, uint32_t seq)
        cache_rec = mail_cache_lookup(view, seq, 0);
        while (cache_rec != NULL) {
                fields |= cache_rec->fields;
-               cache_rec = mail_cache_get_next_record(view->cache, cache_rec);
+               cache_rec = mail_cache_get_record(view->cache,
+                                                 cache_rec->next_offset,
+                                                 FALSE);
        }
 
        return fields;
@@ -280,7 +288,9 @@ int mail_cache_lookup_field(struct mail_cache_view *view, uint32_t seq,
                        return cache_get_field(view->cache, cache_rec, field,
                                               data_r, size_r);
                }
-               cache_rec = mail_cache_get_next_record(view->cache, cache_rec);
+               cache_rec = mail_cache_get_record(view->cache,
+                                                 cache_rec->next_offset,
+                                                 FALSE);
        }
 
        return FALSE;
index a57442ad2178795603d847aea7709e71e22f227a..2cf9552e7c30cd3fc0f98830b9f1fbce8877db79 100644 (file)
@@ -27,6 +27,9 @@
 #define CACHE_RECORD(cache, offset) \
        ((struct mail_cache_record *) ((char *) (cache)->mmap_base + offset))
 
+#define MAIL_CACHE_IS_UNUSABLE(cache) \
+       ((cache)->hdr == NULL)
+
 enum mail_cache_decision_type {
        /* Not needed currently */
        MAIL_CACHE_DECISION_NO          = 0x00,
@@ -83,10 +86,7 @@ struct mail_cache {
         struct mail_cache_transaction_ctx *trans_ctx;
        unsigned int locks;
 
-       unsigned int mmap_refresh:1;
        unsigned int need_compress:1;
-       unsigned int silent:1;
-       unsigned int disabled:1;
 };
 
 struct mail_cache_view {
@@ -111,10 +111,9 @@ mail_cache_split_header(struct mail_cache *cache, const char *header);
 struct mail_cache_record *
 mail_cache_get_record(struct mail_cache *cache, uint32_t offset,
                      int index_offset);
-struct mail_cache_record *
-mail_cache_get_next_record(struct mail_cache *cache,
-                          struct mail_cache_record *rec);
 
+int mail_cache_lookup_offset(struct mail_cache_view *view, uint32_t seq,
+                            uint32_t *offset, int skip_expunged);
 struct mail_cache_record *
 mail_cache_lookup(struct mail_cache_view *view, uint32_t seq,
                  enum mail_cache_field fields);
@@ -123,9 +122,9 @@ int
 mail_cache_transaction_autocommit(struct mail_cache_view *view,
                                  uint32_t seq, enum mail_cache_field fields);
 
-int mail_cache_mmap_update(struct mail_cache *cache,
-                          size_t offset, size_t size);
+int mail_cache_map(struct mail_cache *cache, size_t offset, size_t size);
 void mail_cache_file_close(struct mail_cache *cache);
+int mail_cache_reopen(struct mail_cache *cache);
 
 void mail_cache_handle_decisions(struct mail_cache_view *view, uint32_t seq,
                                 enum mail_cache_field field);
index 054cd0f35f4b722c3fdbe7f4125f100cad0625cb..210358b72b89ebfc7919b62ab54d431e985ce3d6 100644 (file)
@@ -7,6 +7,7 @@
 #include "mmap-util.h"
 #include "mail-cache-private.h"
 
+#include <stddef.h>
 #include <sys/stat.h>
 
 struct mail_cache_transaction_ctx {
@@ -174,7 +175,7 @@ mail_cache_grow(struct mail_cache_transaction_ctx *ctx, uint32_t size)
 
        if (ctx->used_file_size + size <= (uoff_t)st.st_size) {
                /* no need to grow, just update mmap */
-               if (mail_cache_mmap_update(cache, 0, 0) < 0)
+               if (mail_cache_map(cache, 0, (size_t)st.st_size) < 0)
                        return -1;
 
                i_assert(cache->mmap_length >= (uoff_t)st.st_size);
@@ -186,7 +187,7 @@ mail_cache_grow(struct mail_cache_transaction_ctx *ctx, uint32_t size)
                return -1;
        }
 
-       return mail_cache_mmap_update(cache, 0, 0);
+       return mail_cache_map(cache, 0, (size_t)new_fsize);
 }
 
 static uint32_t mail_cache_append_space(struct mail_cache_transaction_ctx *ctx,
@@ -217,10 +218,8 @@ static uint32_t mail_cache_append_space(struct mail_cache_transaction_ctx *ctx,
 static int mail_cache_write(struct mail_cache_transaction_ctx *ctx)
 {
        struct mail_cache *cache = ctx->cache;
-       struct mail_cache_record *cache_rec, *next;
-       const struct mail_index_record *rec;
-       struct mail_index_map *map;
-       uint32_t write_offset, update_offset;
+       struct mail_cache_record *cache_rec;
+       uint32_t offset, write_offset;
        const void *buf;
        size_t size, buf_size;
        int ret;
@@ -230,16 +229,10 @@ static int mail_cache_write(struct mail_cache_transaction_ctx *ctx)
        size = sizeof(*cache_rec) + buf_size;
        ctx->cache_rec.size = uint32_to_nbo(size);
 
-       ret = mail_index_lookup_full(ctx->view->view, ctx->prev_seq,
-                                    &map, &rec);
+        ret = mail_cache_lookup_offset(ctx->view, ctx->prev_seq, &offset, TRUE);
        if (ret < 0)
                return -1;
 
-       if (map->hdr->cache_file_seq != cache->hdr->file_seq) {
-               /* FIXME: we should check if newer file is available? */
-               ret = 0;
-       }
-
        if (ret == 0) {
                /* it's been expunged already, do nothing */
        } else {
@@ -247,22 +240,25 @@ static int mail_cache_write(struct mail_cache_transaction_ctx *ctx)
                if (write_offset == 0)
                        return -1;
 
-               cache_rec = mail_cache_get_record(cache, rec->cache_offset,
-                                                 TRUE);
+               cache_rec = mail_cache_get_record(cache, offset, TRUE);
                if (cache_rec == NULL) {
                        /* first cache record - update offset in index file */
                        mail_index_update_cache(ctx->trans, ctx->prev_seq,
                                                write_offset);
                } else {
-                       /* find the last cache record */
-                       while ((next = mail_cache_get_next_record(cache,
-                                                                 cache_rec)) != NULL)
-                               cache_rec = next;
+                       /* find offset to last cache record */
+                       for (;;) {
+                               cache_rec = mail_cache_get_record(cache, offset,
+                                                                 FALSE);
+                               if (cache_rec == NULL)
+                                       break;
+                               offset = cache_rec->next_offset;
+                       }
 
                        /* mark next_offset to be updated later */
-                       update_offset = (char *) &cache_rec->next_offset -
-                               (char *) cache->mmap_base;
-                       mark_update(&ctx->cache_marks, update_offset,
+                       offset = mail_cache_offset_to_uint32(offset) +
+                               offsetof(struct mail_cache_record, next_offset);
+                       mark_update(&ctx->cache_marks, offset,
                                    mail_cache_uint32_to_offset(write_offset));
                }
 
@@ -285,7 +281,7 @@ int mail_cache_transaction_commit(struct mail_cache_transaction_ctx *ctx)
 {
        int ret = 0;
 
-       if (ctx->cache->disabled) {
+       if (MAIL_CACHE_IS_UNUSABLE(ctx->cache)) {
                mail_cache_transaction_flush(ctx);
                return 0;
        }
@@ -541,7 +537,8 @@ int mail_cache_delete(struct mail_cache_transaction_ctx *ctx, uint32_t seq)
 
        do {
                deleted_space -= nbo_to_uint32(cache_rec->size);
-               cache_rec = mail_cache_get_next_record(cache, cache_rec);
+               cache_rec = mail_cache_get_record(cache, cache_rec->next_offset,
+                                                 FALSE);
        } while (cache_rec != NULL);
 
        /* see if we've reached the max. deleted space in file */
index 6686f81bf69cdfc5b03328a076c7f30f0c85dfc9..e04e2f76887a5b71dc02b1460dfc291b15d6b2f7 100644 (file)
@@ -9,7 +9,6 @@
 #include "mail-cache-private.h"
 
 #include <unistd.h>
-#include <sys/stat.h>
 
 unsigned int mail_cache_field_sizes[32] = {
        sizeof(enum mail_cache_record_flag),
@@ -92,10 +91,8 @@ void mail_cache_set_corrupted(struct mail_cache *cache, const char *fmt, ...)
 {
        va_list va;
 
-        (void)mail_cache_reset(cache);
-
-       if (cache->silent)
-               return;
+       (void)unlink(cache->filepath);
+       mail_cache_file_close(cache);
 
        va_start(va, fmt);
        t_push();
@@ -123,20 +120,37 @@ void mail_cache_file_close(struct mail_cache *cache)
        }
 }
 
-static int mail_cache_file_reopen(struct mail_cache *cache)
+int mail_cache_reopen(struct mail_cache *cache)
 {
-       int fd;
+       if (MAIL_CACHE_IS_UNUSABLE(cache) && cache->need_compress) {
+               /* unusable, we're just waiting for compression */
+               return 0;
+       }
 
-       fd = open(cache->filepath, O_RDWR);
-       if (fd == -1) {
-               mail_cache_set_syscall_error(cache, "open()");
+       mail_cache_file_close(cache);
+
+       cache->fd = open(cache->filepath, O_RDWR);
+       if (cache->fd == -1) {
+               if (errno == ENOENT)
+                       cache->need_compress = TRUE;
+               else
+                       mail_cache_set_syscall_error(cache, "open()");
                return -1;
        }
 
-       mail_cache_file_close(cache);
+       if (mail_cache_map(cache, 0, 0) < 0)
+               return -1;
 
-       cache->fd = fd;
-       return 0;
+       if (cache->hdr->file_seq != cache->index->hdr->cache_file_seq) {
+               /* still different - maybe a race condition or maybe the
+                  file_seq really is corrupted. either way, this shouldn't
+                  happen often so we'll just mark cache to be compressed
+                  later which fixes this. */
+               cache->need_compress = TRUE;
+               return 0;
+       }
+
+       return 1;
 }
 
 static int mmap_verify_header(struct mail_cache *cache)
@@ -147,75 +161,52 @@ static int mmap_verify_header(struct mail_cache *cache)
        /* check that the header is still ok */
        if (cache->mmap_length < sizeof(struct mail_cache_header)) {
                mail_cache_set_corrupted(cache, "File too small");
-               return 0;
+               return FALSE;
        }
        cache->hdr = hdr = cache->mmap_base;
 
        if (cache->hdr->indexid != cache->index->indexid) {
                /* index id changed */
-               if (cache->hdr->indexid != 0)
-                       mail_cache_set_corrupted(cache, "indexid changed");
-               return 0;
+               mail_cache_set_corrupted(cache, "indexid changed");
+               return FALSE;
        }
 
        if (cache->trans_ctx != NULL) {
                /* we've updated used_file_size, do nothing */
-               return 1;
+               return TRUE;
        }
 
        /* only check the header if we're locked */
        if (cache->locks == 0)
-               return 1;
+               return TRUE;
 
        used_file_size = nbo_to_uint32(hdr->used_file_size);
        if (used_file_size < sizeof(struct mail_cache_header)) {
                mail_cache_set_corrupted(cache, "used_file_size too small");
-               return 0;
+               return FALSE;
        }
        if ((used_file_size % sizeof(uint32_t)) != 0) {
                mail_cache_set_corrupted(cache, "used_file_size not aligned");
-               return 0;
+               return FALSE;
        }
 
        if (used_file_size > cache->mmap_length) {
                mail_cache_set_corrupted(cache, "used_file_size too large");
-               return 0;
+               return FALSE;
        }
-       return 1;
+       return TRUE;
 }
 
-static int mmap_update_nocheck(struct mail_cache *cache,
-                              size_t offset, size_t size)
+int mail_cache_map(struct mail_cache *cache, size_t offset, size_t size)
 {
-       struct stat st;
-
-#if 0 // FIXME
-       /* if sequence has changed, the file has to be reopened.
-          note that if main index isn't locked, it may change again */
-       if (cache->hdr->file_seq != cache->index->hdr->cache_file_seq &&
-           cache->mmap_base != NULL) {
-               if (mail_cache_file_reopen(cache) < 0)
-                       return -1;
-       }
-#endif
+       if (size == 0)
+               size = sizeof(struct mail_cache_header);
 
        if (offset < cache->mmap_length &&
-           size <= cache->mmap_length - offset &&
-           !cache->mmap_refresh) {
+           size <= cache->mmap_length - offset) {
                /* already mapped */
-               if (size != 0)
-                       return 1;
-
-               /* requesting the whole file - see if we need to
-                  re-mmap */
-               if (fstat(cache->fd, &st) < 0) {
-                       mail_cache_set_syscall_error(cache, "fstat()");
-                       return -1;
-               }
-               if ((uoff_t)st.st_size == cache->mmap_length)
-                       return 1;
+               return 0;
        }
-       cache->mmap_refresh = FALSE;
 
        if (cache->mmap_base != NULL) {
                if (cache->locks != 0) {
@@ -229,10 +220,14 @@ static int mmap_update_nocheck(struct mail_cache *cache,
 
                if (munmap(cache->mmap_base, cache->mmap_length) < 0)
                        mail_cache_set_syscall_error(cache, "munmap()");
+       } else {
+               if (cache->fd == -1) {
+                       /* unusable, waiting for compression */
+                       i_assert(cache->need_compress);
+                       return -1;
+               }
        }
 
-       i_assert(cache->fd != -1);
-
        /* map the whole file */
        cache->hdr = NULL;
        cache->mmap_length = 0;
@@ -244,156 +239,48 @@ static int mmap_update_nocheck(struct mail_cache *cache,
                return -1;
        }
 
-       /* re-mmaped, check header */
-       return 0;
-}
-
-int mail_cache_mmap_update(struct mail_cache *cache, size_t offset, size_t size)
-{
-       int synced, ret;
-
-       ret = mmap_update_nocheck(cache, offset, size);
-       if (ret > 0)
-               return 0;
-       if (ret < 0)
-               return -1;
-
-       if (mmap_verify_header(cache) <= 0)
+       if (!mmap_verify_header(cache)) {
+               cache->need_compress = TRUE;
                return -1;
+       }
 
-#if 0 // FIXME
-               /* see if cache file was rebuilt - do it only once to avoid
-                  infinite looping */
-               if (cache->hdr->file_seq == cache->index->hdr->cache_file_seq ||
-                   synced)
-                       break;
-
-               if (mail_cache_file_reopen(cache) < 0)
-                       return -1;
-#endif
        return 0;
 }
 
-static int mail_cache_open_and_verify(struct mail_cache *cache, int silent)
+static int mail_cache_open_and_verify(struct mail_cache *cache)
 {
-       struct stat st;
-       int ret;
-
-       mail_cache_file_close(cache);
+       cache->filepath = i_strconcat(cache->index->filepath,
+                                     MAIL_CACHE_FILE_PREFIX, NULL);
 
        cache->fd = open(cache->filepath, O_RDWR);
        if (cache->fd == -1) {
-               if (errno == ENOENT)
+               if (errno == ENOENT) {
+                       cache->need_compress = TRUE;
                        return 0;
+               }
 
                mail_cache_set_syscall_error(cache, "open()");
                return -1;
        }
 
-       if (fstat(cache->fd, &st) < 0) {
-               mail_cache_set_syscall_error(cache, "fstat()");
-               return -1;
-       }
-
-       if (st.st_size < sizeof(struct mail_cache_header))
-               return 0;
-
-       cache->mmap_refresh = TRUE;
-       if (mmap_update_nocheck(cache, 0, sizeof(struct mail_cache_header)) < 0)
-               return -1;
-
-       /* verify that this really is the cache for wanted index */
-       cache->silent = silent;
-       if ((ret = mmap_verify_header(cache)) <= 0) {
-               cache->silent = FALSE;
-               return ret;
-       }
-
-       cache->silent = FALSE;
-       return 1;
-}
-
-static int mail_cache_open_or_create_file(struct mail_cache *cache,
-                                         struct mail_cache_header *hdr)
-{
-       int ret, fd;
-
-       cache->filepath = i_strconcat(cache->index->filepath,
-                                     MAIL_CACHE_FILE_PREFIX, NULL);
-
-       ret = mail_cache_open_and_verify(cache, FALSE);
-       if (ret != 0)
-               return ret < 0 ? -1 : 0;
-
-       /* maybe a rebuild.. */
-       fd = file_dotlock_open(cache->filepath, NULL, NULL,
-                              MAIL_CACHE_LOCK_TIMEOUT,
-                              MAIL_CACHE_LOCK_CHANGE_TIMEOUT,
-                              MAIL_CACHE_LOCK_IMMEDIATE_TIMEOUT, NULL, NULL);
-       if (fd == -1) {
-               mail_cache_set_syscall_error(cache, "file_dotlock_open()");
-               return -1;
-       }
-
-       /* see if someone else just created the cache file */
-       ret = mail_cache_open_and_verify(cache, TRUE);
-       if (ret != 0) {
-               (void)file_dotlock_delete(cache->filepath, NULL, fd);
-               return ret < 0 ? -1 : 0;
-       }
-
-       /* rebuild then */
-       if (write_full(fd, hdr, sizeof(*hdr)) < 0) {
-               mail_cache_set_syscall_error(cache, "write_full()");
-               (void)file_dotlock_delete(cache->filepath, NULL, fd);
-               return -1;
-       }
-       if (file_set_size(fd, MAIL_CACHE_INITIAL_SIZE) < 0) {
-               mail_cache_set_syscall_error(cache, "file_set_size()");
-               (void)file_dotlock_delete(cache->filepath, NULL, fd);
-               return -1;
-       }
-
-       mail_cache_file_close(cache);
-       cache->fd = dup(fd);
-
-       if (file_dotlock_replace(cache->filepath, NULL, fd, FALSE) < 0) {
-               mail_cache_set_syscall_error(cache, "file_dotlock_replace()");
-               return -1;
-       }
-
-       if (mail_cache_mmap_update(cache, 0,
-                                  sizeof(struct mail_cache_header)) < 0)
-               return -1;
-
-       return 0;
+       return mail_cache_map(cache, 0, sizeof(struct mail_cache_header));
 }
 
 struct mail_cache *mail_cache_open_or_create(struct mail_index *index)
 {
-        struct mail_cache_header hdr;
        struct mail_cache *cache;
 
-       memset(&hdr, 0, sizeof(hdr));
-       hdr.indexid = index->indexid;
-       hdr.file_seq = index->hdr->cache_file_seq + 1;
-       hdr.used_file_size = uint32_to_nbo(sizeof(hdr));
-
        cache = i_new(struct mail_cache, 1);
        cache->index = index;
        cache->fd = -1;
         cache->split_header_pool = pool_alloconly_create("Headers", 512);
 
-       if (index->mmap_disable ||
-           mail_cache_open_or_create_file(cache, &hdr) < 0) {
-               /* failed for some reason - doesn't really matter,
-                  just disable caching. */
-               mail_cache_file_close(cache);
-
-               i_free(cache->filepath);
-               cache->filepath = i_strdup_printf("(disabled cache for %s)",
-                                                 index->filepath);
-               cache->disabled = TRUE;
+       if (!index->mmap_disable) {
+               if (mail_cache_open_and_verify(cache) < 0) {
+                       /* failed for some reason - doesn't really matter,
+                          it's disabled for now. */
+                       mail_cache_file_close(cache);
+               }
        }
 
        return cache;
@@ -418,83 +305,51 @@ void mail_cache_set_defaults(struct mail_cache *cache,
        cache->never_cache_fields = never_cache_fields;
 }
 
-int mail_cache_reset(struct mail_cache *cache)
-{
-       struct mail_cache_header hdr;
-       int fd;
-
-       memset(&hdr, 0, sizeof(hdr));
-       hdr.indexid = cache->index->indexid;
-       hdr.file_seq = cache->index->hdr->cache_file_seq + 1;
-       hdr.used_file_size = uint32_to_nbo(sizeof(hdr));
-
-       fd = file_dotlock_open(cache->filepath, NULL, NULL,
-                              MAIL_CACHE_LOCK_TIMEOUT,
-                              MAIL_CACHE_LOCK_CHANGE_TIMEOUT,
-                              MAIL_CACHE_LOCK_IMMEDIATE_TIMEOUT, NULL, NULL);
-       if (fd == -1) {
-               mail_cache_set_syscall_error(cache, "file_dotlock_open()");
-               return -1;
-       }
-
-       if (write_full(fd, &hdr, sizeof(hdr)) < 0) {
-               mail_cache_set_syscall_error(cache, "write_full()");
-               (void)file_dotlock_delete(cache->filepath, NULL, fd);
-               return -1;
-       }
-       if (file_set_size(fd, MAIL_CACHE_INITIAL_SIZE) < 0) {
-               mail_cache_set_syscall_error(cache, "file_set_size()");
-               (void)file_dotlock_delete(cache->filepath, NULL, fd);
-               return -1;
-       }
-
-       mail_cache_file_close(cache);
-       cache->fd = dup(fd);
-
-       if (file_dotlock_replace(cache->filepath, NULL, fd, FALSE) < 0) {
-               mail_cache_set_syscall_error(cache, "file_dotlock_replace()");
-               return -1;
-       }
-
-       cache->mmap_refresh = TRUE;
-       if (mail_cache_mmap_update(cache, 0,
-                                  sizeof(struct mail_cache_header)) < 0)
-               return -1;
-
-       return 0;
-}
-
 int mail_cache_lock(struct mail_cache *cache, int nonblock)
 {
-       int ret;
+       int i, ret;
 
        if (cache->locks != 0)
                return 1;
 
-       if (cache->disabled)
+       if (MAIL_CACHE_IS_UNUSABLE(cache))
                return 0;
 
-       if (nonblock) {
-               ret = file_try_lock(cache->fd, F_WRLCK);
-               if (ret < 0)
-                       mail_cache_set_syscall_error(cache, "file_try_lock()");
-       } else {
-               ret = file_wait_lock(cache->fd, F_WRLCK);
-               if (ret <= 0)
-                       mail_cache_set_syscall_error(cache, "file_wait_lock()");
+       if (cache->hdr->file_seq != cache->index->hdr->cache_file_seq) {
+               /* we want the latest cache file */
+               if ((ret = mail_cache_reopen(cache)) <= 0)
+                       return ret;
        }
 
-       if (ret > 0) {
-               if (mail_cache_mmap_update(cache, 0, 0) < 0) {
-                       (void)mail_cache_unlock(cache);
-                       return -1;
+       for (i = 0; i < 3; i++) {
+               if (nonblock) {
+                       ret = file_try_lock(cache->fd, F_WRLCK);
+                       if (ret < 0) {
+                               mail_cache_set_syscall_error(cache,
+                                                            "file_try_lock()");
+                       }
+               } else {
+                       ret = file_wait_lock(cache->fd, F_WRLCK);
+                       if (ret <= 0) {
+                               mail_cache_set_syscall_error(cache,
+                                       "file_wait_lock()");
+                       }
                }
 
-               if (cache->hdr->file_seq != cache->index->hdr->cache_file_seq) {
-                       mail_cache_unlock(cache);
-                       return 0;
+               if (ret <= 0)
+                       break;
+
+               if (cache->hdr->file_seq == cache->index->hdr->cache_file_seq) {
+                       /* got it */
+                       cache->locks++;
+                       break;
                }
-               cache->locks++;
+
+               /* okay, so it was just compressed. try again. */
+               mail_cache_unlock(cache);
+               if ((ret = mail_cache_reopen(cache)) <= 0)
+                       return ret;
+               ret = 0;
        }
        return ret;
 }
@@ -517,19 +372,6 @@ int mail_cache_is_locked(struct mail_cache *cache)
        return cache->locks > 0;
 }
 
-int mail_cache_need_reset(struct mail_cache *cache, uint32_t *new_file_seq_r)
-{
-       if (!cache->disabled &&
-           cache->hdr->file_seq != cache->index->hdr->cache_file_seq) {
-               if (mail_cache_lock(cache, TRUE) == 0) {
-                       *new_file_seq_r = cache->hdr->file_seq;
-                       return TRUE;
-               }
-       }
-
-       return FALSE;
-}
-
 struct mail_cache_view *
 mail_cache_view_open(struct mail_cache *cache, struct mail_index_view *iview)
 {
index 8ef3ae707502602ef94c4a1649ddeaa2836fab9b..9b889de5a29705d740b1b8686f5c161a35084893 100644 (file)
@@ -83,20 +83,14 @@ int mail_cache_need_compress(struct mail_cache *cache);
 /* Compress cache file. */
 int mail_cache_compress(struct mail_cache *cache, struct mail_index_view *view);
 
-/* Reset the cache file, clearing all data. */
-int mail_cache_reset(struct mail_cache *cache);
-
-/* Explicitly lock the cache file. Returns -1 if error, 1 if ok,
-   0 if we couldn't lock (nonblock = TRUE or index file needs a cache reset) */
+/* Explicitly lock the cache file. Returns -1 if error, 1 if ok, 0 if we
+   couldn't lock */
 int mail_cache_lock(struct mail_cache *cache, int nonblock);
 int mail_cache_unlock(struct mail_cache *cache);
 
 /* Returns TRUE if cache file is locked. */
 int mail_cache_is_locked(struct mail_cache *cache);
 
-/* Returns TRUE if index's cache_file_seq doesn't match the latest cache file */
-int mail_cache_need_reset(struct mail_cache *cache, uint32_t *new_file_seq_r);
-
 struct mail_cache_view *
 mail_cache_view_open(struct mail_cache *cache, struct mail_index_view *iview);
 void mail_cache_view_close(struct mail_cache_view *view);
index bc6fb6122756d3cb0f1b4d3cbcfcd91ab62956a0..15993128c48892bc259a2c6cadd7db63750038ac 100644 (file)
@@ -207,7 +207,7 @@ static int mail_index_need_lock(struct mail_index *index,
             (index->hdr->log_file_seq == log_file_seq &&
              index->hdr->log_file_offset >= log_file_offset)) {
                /* already synced */
-               return 0;
+               return mail_cache_need_compress(index->cache);
        }
 
        return 1;
@@ -219,7 +219,7 @@ int mail_index_sync_begin(struct mail_index *index,
                          uint32_t log_file_seq, uoff_t log_file_offset)
 {
        struct mail_index_sync_ctx *ctx;
-       uint32_t seq, new_file_seq;
+       uint32_t seq;
        uoff_t offset;
        unsigned int lock_id;
 
@@ -270,17 +270,6 @@ int mail_index_sync_begin(struct mail_index *index,
                return -1;
        }
 
-       /* check here if cache file's sequence has changed unexpectedly */
-       if (mail_cache_need_reset(index->cache, &new_file_seq)) {
-               uint32_t seq;
-               uoff_t offset;
-               struct mail_index_transaction *t;
-
-               t = mail_index_transaction_begin(ctx->view, FALSE);
-               mail_index_reset_cache(t, new_file_seq);
-                mail_index_transaction_commit(t, &seq, &offset);
-       }
-
        *ctx_r = ctx;
        *view_r = ctx->view;
        return 1;
index ff4092de97cc3c83f342685270e8df93dc2e1b4c..d5d40c9bccfe4f4cc85e0625238f94d4db5022e7 100644 (file)
@@ -128,10 +128,17 @@ int index_mail_cache_transaction_begin(struct index_mail *mail)
        if (mail->trans->cache_trans != NULL)
                return TRUE;
 
+       if (mail->trans->cache_trans_failed) {
+               /* don't try more than once */
+               return FALSE;
+       }
+
        if (mail_cache_transaction_begin(mail->trans->cache_view, TRUE,
                                         mail->trans->trans,
-                                        &mail->trans->cache_trans) <= 0)
+                                        &mail->trans->cache_trans) <= 0) {
+                mail->trans->cache_trans_failed = TRUE;
                return FALSE;
+       }
 
        mail->data.cached_fields =
                mail_cache_get_fields(mail->trans->cache_view, mail->data.seq);
index d2ff2328db5612bb00cd0ad6d5f37cadb7518836..6f262d961da35769813886d09cace13eeab95e83 100644 (file)
@@ -118,6 +118,7 @@ struct index_transaction_context {
        struct mail_cache_transaction_ctx *cache_trans;
 
        struct index_mail fetch_mail; /* for index_storage_fetch() */
+       unsigned int cache_trans_failed:1;
 };
 
 int mail_storage_set_index_error(struct index_mailbox *ibox);