]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Cache file fixes, API changes, etc. It's still in somewhat ugly state, but
authorTimo Sirainen <tss@iki.fi>
Thu, 8 Jul 2004 20:26:15 +0000 (23:26 +0300)
committerTimo Sirainen <tss@iki.fi>
Thu, 8 Jul 2004 20:26:15 +0000 (23:26 +0300)
getting better..

--HG--
branch : HEAD

19 files changed:
src/lib-imap/imap-bodystructure.c
src/lib-imap/imap-bodystructure.h
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-storage/index/index-fetch.c
src/lib-storage/index/index-mail-headers.c
src/lib-storage/index/index-mail.c
src/lib-storage/index/index-mail.h
src/lib-storage/index/index-search.c
src/lib-storage/index/index-storage.c
src/lib-storage/index/maildir/maildir-mail.c
src/lib-storage/index/maildir/maildir-save.c
src/lib-storage/index/mbox/mbox-mail.c
src/lib-storage/index/mbox/mbox-save.c

index 257f90092aa3f290d03e37355246c710720f24e0..502df5eb40493c02deb21adc8156489a5d02ecbb 100644 (file)
@@ -36,9 +36,6 @@ struct message_part_body_data {
        unsigned int charset_found:1;
 };
 
-static void part_write_bodystructure(struct message_part *part,
-                                    string_t *str, int extended);
-
 static void parse_content_type(const unsigned char *value, size_t value_len,
                               void *context)
 {
@@ -294,7 +291,7 @@ static void part_write_body_multipart(struct message_part *part,
        }
 
        if (part->children != NULL)
-               part_write_bodystructure(part->children, str, extended);
+               imap_bodystructure_write(part->children, str, extended);
        else {
                /* no parts in multipart message,
                   that's not allowed. write a single
@@ -416,7 +413,7 @@ static void part_write_body(struct message_part *part,
                imap_envelope_write_part_data(env_data, str);
                str_append(str, ") ");
 
-               part_write_bodystructure(part->children, str, extended);
+               imap_bodystructure_write(part->children, str, extended);
                str_printfa(str, " %u", part->body_size.lines);
        }
 
@@ -459,37 +456,27 @@ static void part_write_body(struct message_part *part,
        }
 }
 
-static void part_write_bodystructure(struct message_part *part,
-                                    string_t *str, int extended)
+void imap_bodystructure_write(struct message_part *part,
+                             string_t *dest, int extended)
 {
        i_assert(part->parent != NULL || part->next == NULL);
 
        while (part != NULL) {
                if (part->parent != NULL)
-                       str_append_c(str, '(');
+                       str_append_c(dest, '(');
 
                if (part->flags & MESSAGE_PART_FLAG_MULTIPART)
-                       part_write_body_multipart(part, str, extended);
+                       part_write_body_multipart(part, dest, extended);
                else
-                       part_write_body(part, str, extended);
+                       part_write_body(part, dest, extended);
 
                if (part->parent != NULL)
-                       str_append_c(str, ')');
+                       str_append_c(dest, ')');
 
                part = part->next;
        }
 }
 
-const char *imap_bodystructure_parse_finish(struct message_part *root,
-                                           int extended)
-{
-       string_t *str;
-
-       str = t_str_new(2048);
-       part_write_bodystructure(root, str, extended);
-       return str_c(str);
-}
-
 static int str_append_imap_arg(string_t *str, const struct imap_arg *arg)
 {
        switch (arg->type) {
@@ -645,35 +632,27 @@ static int imap_parse_bodystructure_args(const struct imap_arg *args,
        return TRUE;
 }
 
-const char *imap_body_parse_from_bodystructure(const char *bodystructure)
+int imap_body_parse_from_bodystructure(const char *bodystructure,
+                                      string_t *dest)
 {
        struct istream *input;
        struct imap_parser *parser;
        struct imap_arg *args;
-       string_t *str;
-       const char *value;
-       size_t len;
        int ret;
 
-       len = strlen(bodystructure);
-       str = t_str_new(len);
-
        input = i_stream_create_from_data(pool_datastack_create(),
-                                         bodystructure, len);
+                                         bodystructure, strlen(bodystructure));
        (void)i_stream_read(input);
 
        parser = imap_parser_create(input, NULL, (size_t)-1);
        ret = imap_parser_finish_line(parser, 0, IMAP_PARSE_FLAG_NO_UNESCAPE |
                                      IMAP_PARSE_FLAG_LITERAL_TYPE, &args);
-       if (ret <= 0 || !imap_parse_bodystructure_args(args, str))
-               value = NULL;
-       else
-               value = str_c(str);
+       ret = ret > 0 && imap_parse_bodystructure_args(args, dest);
 
-       if (value == NULL)
+       if (!ret)
                i_error("Error parsing IMAP bodystructure: %s", bodystructure);
 
        imap_parser_destroy(parser);
        i_stream_unref(input);
-       return value;
+       return ret;
 }
index 7a8b417b1eca287392d1fb26555b32066e6a4967..6cf58853e98ee91fcbdec4948650a61befb24a64 100644 (file)
@@ -8,10 +8,11 @@ struct message_header_line;
 void imap_bodystructure_parse_header(pool_t pool, struct message_part *part,
                                     struct message_header_line *hdr);
 
-const char *imap_bodystructure_parse_finish(struct message_part *root,
-                                           int extended);
+void imap_bodystructure_write(struct message_part *part,
+                             string_t *dest, int extended);
 
 /* Return BODY part from BODYSTRUCTURE */
-const char *imap_body_parse_from_bodystructure(const char *bodystructure);
+int imap_body_parse_from_bodystructure(const char *bodystructure,
+                                      string_t *dest);
 
 #endif
index 916432e22447bd100bd2098d2f7cd1c5c99e65cc..31780c1c0bf478ddb1b2641cf5b77334b9513860 100644 (file)
@@ -8,98 +8,76 @@
 
 static unsigned char null4[4] = { 0, 0, 0, 0 };
 
-static const struct mail_cache_record *
-mail_cache_compress_record(struct mail_cache_view *view, uint32_t seq,
-                          enum mail_cache_field orig_cached_fields,
-                          int header_idx, uint32_t *size_r)
+struct mail_cache_copy_context {
+       int new_msg;
+       char field_seen[32], keep_fields[32], temp_fields[32];
+       buffer_t *buffer, *header;
+};
+
+static int
+mail_cache_compress_callback(struct mail_cache_view *view __attr_unused__,
+                            enum mail_cache_field field,
+                            const void *data, size_t data_size, void *context)
 {
-       enum mail_cache_field cached_fields, field;
-       struct mail_cache_record cache_rec;
-       buffer_t *buffer;
-       pool_t pool;
-       const void *data;
-       size_t size, pos;
-       uint32_t *p, size32 = 0;
+        struct mail_cache_copy_context *ctx = context;
+       uint32_t size32;
        int i;
 
-       memset(&cache_rec, 0, sizeof(cache_rec));
-       pool = pool_datastack_create();
-       buffer = buffer_create_dynamic(pool, 4096, (size_t)-1);
-
-       cached_fields = orig_cached_fields & ~MAIL_CACHE_HEADERS_MASK;
-       buffer_append(buffer, &cache_rec, sizeof(cache_rec));
-       for (i = 0, field = 1; i < 31; i++, field <<= 1) {
-               if ((cached_fields & field) == 0)
-                       continue;
-
-               pos = buffer_get_used_size(buffer);
-               if ((field & MAIL_CACHE_FIXED_MASK) == 0)
-                       buffer_append(buffer, &size32, sizeof(size32));
-
-               if (!mail_cache_lookup_field(view, buffer, seq, field)) {
-                       cached_fields &= ~field;
-                       buffer_set_used_size(buffer, pos);
-                       continue;
-               }
-
-               if ((field & MAIL_CACHE_FIXED_MASK) == 0) {
-                       p = buffer_get_space_unsafe(buffer, pos,
-                                                   sizeof(uint32_t));
-                       *p = (uint32_t)size;
-               }
-
-               if ((size & 3) != 0)
-                       buffer_append(buffer, null4, 4 - (size & 3));
+       if (ctx->new_msg) {
+               if (!ctx->temp_fields[field])
+                       return 1;
+       } else {
+               if (!ctx->keep_fields[field])
+                       return 1;
        }
 
-       /* now merge all the headers if we have them all */
-       if ((orig_cached_fields & mail_cache_header_fields[header_idx]) != 0) {
-               size32 = 0;
-               pos = buffer_get_used_size(buffer);
-               buffer_append(buffer, &size32, sizeof(size32));
-
-               for (i = 0; i <= header_idx; i++) {
-                       field = mail_cache_header_fields[i];
-                       if (mail_cache_lookup_field(view, buffer, seq, field)) {
-                               /* remove terminating \0 */
-                               buffer_set_used_size(buffer,
-                                       buffer_get_used_size(buffer)-1);
+       if (ctx->field_seen[field]) {
+               /* drop duplicates */
+               return 1;
+       }
+       ctx->field_seen[field] = TRUE;
+
+       for (i = 0; i < MAIL_CACHE_HEADERS_COUNT; i++) {
+               if (mail_cache_header_fields[i] == field) {
+                       /* it's header - save it into header field */
+                       size32 = buffer_get_used_size(ctx->header);
+                       if (size32 > 0) {
+                               /* remove old terminating \0 */
+                               buffer_set_used_size(ctx->header, size32-1);
                        }
+                       buffer_append(ctx->header, data, data_size);
+                       return 1;
                }
-               buffer_append(buffer, null4, 1);
+       }
 
-               size32 = buffer_get_used_size(buffer) - pos;
-               if ((size32 & 3) != 0)
-                       buffer_append(buffer, null4, 4 - (size32 & 3));
-               buffer_write(buffer, pos, &size32, sizeof(size32));
+       buffer_append(ctx->buffer, &field, sizeof(field));
 
-               cached_fields |= MAIL_CACHE_HEADERS1;
+       if (mail_cache_field_sizes[field] == (unsigned int)-1) {
+               size32 = (uint32_t)data_size;
+               buffer_append(ctx->buffer, &size32, sizeof(size32));
        }
 
-       cache_rec.fields = cached_fields;
-       cache_rec.size = buffer_get_used_size(buffer);
-       buffer_write(buffer, 0, &cache_rec, sizeof(cache_rec));
-
-       data = buffer_get_data(buffer, &size);
-       *size_r = size;
-       return data;
+       buffer_append(ctx->buffer, data, data_size);
+       if ((data_size & 3) != 0)
+               buffer_append(ctx->buffer, null4, 4 - (data_size & 3));
+       return 1;
 }
 
 static int
 mail_cache_copy(struct mail_cache *cache, struct mail_index_view *view, int fd)
 {
+        struct mail_cache_copy_context ctx;
        struct mail_cache_view *cache_view;
        struct mail_index_transaction *t;
        const struct mail_index_header *idx_hdr;
-       const struct mail_cache_record *cache_rec;
        struct mail_cache_header hdr;
+       struct mail_cache_record cache_rec;
+        enum mail_cache_field field;
        struct ostream *output;
-       enum mail_cache_field keep_fields, temp_fields;
-       enum mail_cache_field cached_fields, new_fields;
        const char *str;
-       uint32_t size, size32, message_count, seq, first_new_seq;
+       uint32_t size32, message_count, seq, first_new_seq, old_offset;
        uoff_t offset;
-       int i, header_idx, ret;
+       int i, ret, header_idx;
 
        /* get sequence of first message which doesn't need it's temp fields
           removed. */
@@ -133,15 +111,23 @@ mail_cache_copy(struct mail_cache *cache, struct mail_index_view *view, int fd)
                memcpy(hdr.field_usage_last_used,
                       cache->hdr->field_usage_last_used,
                       sizeof(hdr.field_usage_last_used));
+       } else {
+               memcpy(hdr.field_usage_decision_type,
+                      cache->default_field_usage_decision_type,
+                      sizeof(hdr.field_usage_decision_type));
+       }
 
-               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;
+       memset(&ctx, 0, sizeof(ctx));
+       ctx.buffer = buffer_create_dynamic(default_pool, 4096, (size_t)-1);
+       ctx.header = buffer_create_dynamic(default_pool, 4096, (size_t)-1);
+
+       for (i = 0; i < 32; i++) {
+               if (hdr.field_usage_decision_type[i] & MAIL_CACHE_DECISION_YES)
+                       ctx.keep_fields[i] = TRUE;
+               else if (hdr.field_usage_decision_type[i] &
+                        MAIL_CACHE_DECISION_TEMP) {
+                       ctx.temp_fields[i] = TRUE;
+                       ctx.keep_fields[i] = TRUE;
                }
        }
 
@@ -173,45 +159,42 @@ mail_cache_copy(struct mail_cache *cache, struct mail_index_view *view, int fd)
 
        ret = 0;
        for (seq = 1; seq <= message_count; seq++) {
-               cache_rec = mail_cache_lookup(cache_view, seq);
-               if (cache_rec == NULL)
-                       continue;
-
-               cached_fields = mail_cache_get_fields(cache_view, seq);
-                new_fields = cached_fields & keep_fields;
-               if ((cached_fields & temp_fields) != 0 &&
-                   seq >= first_new_seq) {
-                       /* new message, keep temp fields */
-                       new_fields |= cached_fields & temp_fields;
+               ctx.new_msg = seq >= first_new_seq;
+               buffer_set_used_size(ctx.buffer, 0);
+               buffer_set_used_size(ctx.header, 0);
+               memset(ctx.field_seen, 0, sizeof(ctx.field_seen));
+
+               memset(&cache_rec, 0, sizeof(cache_rec));
+               buffer_append(ctx.buffer, &cache_rec, sizeof(cache_rec));
+
+               mail_cache_foreach(cache_view, seq,
+                                  mail_cache_compress_callback, &ctx);
+
+               size32 = buffer_get_used_size(ctx.header);
+               if (size32 > 0 && ctx.field_seen[header_idx]) {
+                       field = MAIL_CACHE_HEADERS1;
+                       buffer_append(ctx.buffer, &field, sizeof(field));
+                       buffer_append(ctx.buffer, &size32, sizeof(size32));
+                       buffer_append(ctx.buffer,
+                                     buffer_get_data(ctx.header, NULL),
+                                     size32);
+                       if ((size32 & 3) != 0) {
+                               buffer_append(ctx.buffer, null4,
+                                             4 - (size32 & 3));
+                       }
                }
 
-               if (keep_fields == cached_fields &&
-                   cache_rec->prev_offset == 0) {
-                       /* just one unmodified block, save it */
-                       mail_index_update_cache(t, seq, hdr.file_seq,
-                                               output->offset, NULL);
-                       o_stream_send(output, cache_rec, cache_rec->size);
+               if (buffer_get_used_size(ctx.buffer) == sizeof(cache_rec))
+                       continue;
 
-                       if ((cache_rec->size & 3) != 0) {
-                               o_stream_send(output, null4,
-                                             4 - (cache_rec->size & 3));
-                       }
-               } else {
-                       /* a) dropping fields
-                          b) multiple blocks, sort them into buffer */
-                       mail_index_update_cache(t, seq, hdr.file_seq,
-                                               output->offset, NULL);
-
-                       t_push();
-                       cache_rec = mail_cache_compress_record(cache_view, seq,
-                                                              keep_fields,
-                                                              header_idx,
-                                                              &size);
-                       o_stream_send(output, cache_rec, size);
-                       t_pop();
-               }
+               mail_index_update_cache(t, seq, hdr.file_seq,
+                                       output->offset, &old_offset);
+               o_stream_send(output, buffer_get_data(ctx.buffer, NULL),
+                             buffer_get_used_size(ctx.buffer));
        }
        hdr.used_file_size = output->offset;
+       buffer_free(ctx.buffer);
+       buffer_free(ctx.header);
 
        o_stream_seek(output, 0);
        o_stream_send(output, &hdr, sizeof(hdr));
@@ -263,7 +246,7 @@ int mail_cache_compress(struct mail_cache *cache, struct mail_index_view *view)
                return -1;
        }
 
-       // FIXME: check that cache file was just recreated
+       // FIXME: check that cache file wasn't just recreated
 
        ret = 0;
        if (mail_cache_copy(cache, view, fd) < 0) {
index 870cf3e6dd6ec6afb118aa21a25d67500f7917be..73ccd506134e81ef844f9127fed67be5db2b3ee7 100644 (file)
@@ -73,7 +73,8 @@
 #include <stddef.h>
 
 static void
-mail_cache_set_decision_type(struct mail_cache *cache, uint32_t idx,
+mail_cache_set_decision_type(struct mail_cache *cache,
+                            enum mail_cache_field field,
                             enum mail_cache_decision_type type)
 {
        uint8_t value = type;
@@ -84,20 +85,18 @@ mail_cache_set_decision_type(struct mail_cache *cache, uint32_t idx,
           will be corrected sometimes later, not too bad.. */
        if (pwrite_full(cache->fd, &value, 1,
                        offsetof(struct mail_cache_header,
-                                field_usage_decision_type) + idx) < 0) {
+                                field_usage_decision_type) + field) < 0) {
                mail_cache_set_syscall_error(cache, "pwrite_full()");
        }
 }
 
-void mail_cache_handle_decisions(struct mail_cache_view *view, uint32_t seq,
-                                enum mail_cache_field field)
+void mail_cache_decision_lookup(struct mail_cache_view *view, uint32_t seq,
+                               enum mail_cache_field field)
 {
        const struct mail_index_header *hdr;
-       unsigned int idx;
        uint32_t uid;
 
-       idx = mail_cache_field_index(field);
-       if (view->cache->hdr->field_usage_decision_type[idx] !=
+       if (view->cache->hdr->field_usage_decision_type[field] !=
            MAIL_CACHE_DECISION_TEMP) {
                /* a) forced decision
                   b) not cached, mail_cache_mark_missing() will handle this
@@ -110,7 +109,7 @@ void mail_cache_handle_decisions(struct mail_cache_view *view, uint32_t seq,
            mail_index_get_header(view->view, &hdr) < 0)
                return;
 
-       if (uid < view->cache->field_usage_uid_highwater[idx] ||
+       if (uid < view->cache->field_usage_uid_highwater[field] ||
            uid < hdr->day_first_uid[7]) {
                /* a) nonordered access within this session. if client doesn't
                      request messages in growing order, we assume it doesn't
@@ -119,24 +118,22 @@ void mail_cache_handle_decisions(struct mail_cache_view *view, uint32_t seq,
                      client with no local cache. if it was just a new client
                      generating the local cache for the first time, we'll
                      drop back to TEMP within few months. */
-               mail_cache_set_decision_type(view->cache, idx,
+               mail_cache_set_decision_type(view->cache, field,
                                             MAIL_CACHE_DECISION_YES);
        } else {
-               view->cache->field_usage_uid_highwater[idx] = uid;
+               view->cache->field_usage_uid_highwater[field] = uid;
        }
 }
 
-void mail_cache_mark_missing(struct mail_cache_view *view, uint32_t seq,
+void mail_cache_decision_add(struct mail_cache_view *view, uint32_t seq,
                             enum mail_cache_field field)
 {
-       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] !=
+       if (view->cache->hdr->field_usage_decision_type[field] !=
            MAIL_CACHE_DECISION_NO) {
                /* a) forced decision
                   b) we're already caching it, so it just wasn't in cache */
@@ -144,9 +141,9 @@ void mail_cache_mark_missing(struct mail_cache_view *view, uint32_t seq,
        }
 
        /* field used the first time */
-       mail_cache_set_decision_type(view->cache, idx,
+       mail_cache_set_decision_type(view->cache, field,
                                     MAIL_CACHE_DECISION_TEMP);
 
        if (mail_index_lookup_uid(view->view, seq, &uid) == 0)
-               view->cache->field_usage_uid_highwater[idx] = uid;
+               view->cache->field_usage_uid_highwater[field] = uid;
 }
index fd795b587023049bc9b76f6906c29fbf47b20aa6..f9a9ecf00411369523f253f4959c11159fe0bd63 100644 (file)
@@ -171,112 +171,163 @@ static int mail_cache_lookup_offset(struct mail_cache_view *view, uint32_t seq,
        return 0;
 }
 
-struct mail_cache_record *
-mail_cache_lookup(struct mail_cache_view *view, uint32_t seq)
+int mail_cache_foreach(struct mail_cache_view *view, uint32_t seq,
+                      int (*callback)(struct mail_cache_view *view,
+                                      enum mail_cache_field field,
+                                      const void *data, size_t data_size,
+                                      void *context), void *context)
 {
-       uint32_t offset;
-
-       // FIXME: check transactions too
+       const struct mail_cache_record *cache_rec;
+       size_t pos, next_pos, max_size, data_size;
+       uint32_t offset, field;
+       int ret;
 
         if (MAIL_CACHE_IS_UNUSABLE(view->cache))
-               return NULL;
+               return 0;
 
-       if (mail_cache_lookup_offset(view, seq, &offset) <= 0)
-               return NULL;
+       if ((ret = mail_cache_lookup_offset(view, seq, &offset)) <= 0)
+               return ret;
 
-       return mail_cache_get_record(view->cache, offset);
-}
+       cache_rec = mail_cache_get_record(view->cache, offset);
+       while (cache_rec != NULL) {
+               max_size = cache_rec->size;
+               if (max_size < sizeof(*cache_rec) + sizeof(uint32_t)*2) {
+                       mail_cache_set_corrupted(view->cache,
+                               "record has invalid size");
+                       return -1;
+               }
+               max_size -= sizeof(uint32_t);
+
+               for (pos = sizeof(*cache_rec); pos < max_size; ) {
+                       field = *((const uint32_t *)
+                                 CONST_PTR_OFFSET(cache_rec, pos));
+                       pos += sizeof(uint32_t);
+
+                       data_size = mail_cache_field_sizes[field];
+                       if (data_size == (unsigned int)-1) {
+                               data_size = *((const uint32_t *)
+                                             CONST_PTR_OFFSET(cache_rec, pos));
+                               pos += sizeof(uint32_t);
+                       }
 
-enum mail_cache_field
-mail_cache_get_fields(struct mail_cache_view *view, uint32_t seq)
-{
-       struct mail_cache_record *cache_rec;
-        enum mail_cache_field fields = 0;
+                       next_pos = pos + ((data_size + 3) & ~3);
+                       if (next_pos > cache_rec->size) {
+                               mail_cache_set_corrupted(view->cache,
+                                       "Record continues outside it's "
+                                       "allocated size");
+                               return -1;
+                       }
 
-       cache_rec = mail_cache_lookup(view, seq);
-       while (cache_rec != NULL) {
-               fields |= cache_rec->fields;
+                       ret = callback(view, field,
+                                      CONST_PTR_OFFSET(cache_rec, pos),
+                                      data_size, context);
+                       if (ret <= 0)
+                               return ret;
+
+                       pos = next_pos;
+               }
                cache_rec = mail_cache_get_record(view->cache,
                                                  cache_rec->prev_offset);
        }
 
-       return fields;
+       if (view->transaction != NULL) {
+               // FIXME: update
+       }
+       return 1;
 }
 
-static int cache_get_field(struct mail_cache *cache,
-                          const struct mail_cache_record *cache_rec,
-                          enum mail_cache_field field, buffer_t *dest_buf)
+static int mail_cache_seq_callback(struct mail_cache_view *view,
+                                  enum mail_cache_field field,
+                                  const void *data __attr_unused__,
+                                  size_t data_size __attr_unused__,
+                                  void *context __attr_unused__)
 {
-       unsigned int mask;
-       uint32_t data_size;
-       size_t offset, prev_offset;
-       int i;
+       view->cached_exists[field] = TRUE;
+       return 1;
+}
 
-       offset = sizeof(*cache_rec);
+static int mail_cache_seq(struct mail_cache_view *view, uint32_t seq)
+{
+       int ret;
 
-       for (i = 0, mask = 1; i < 31; i++, mask <<= 1) {
-               if ((cache_rec->fields & mask) == 0)
-                       continue;
+       view->cached_exists_seq = seq;
+       memset(view->cached_exists, 0, sizeof(view->cached_exists));
 
-               /* all records are at least 32bit. we have to check this
-                  before getting data_size. */
-               if (offset + sizeof(uint32_t) > cache_rec->size) {
-                       mail_cache_set_corrupted(cache,
-                               "Record continues outside it's allocated size");
-                       return FALSE;
-               }
+       ret = mail_cache_foreach(view, seq, mail_cache_seq_callback, NULL);
+       return ret < 0 ? -1 : 0;
+}
 
-               if ((mask & MAIL_CACHE_FIXED_MASK) != 0)
-                       data_size = mail_cache_field_sizes[i];
-               else {
-                       memcpy(&data_size, CONST_PTR_OFFSET(cache_rec, offset),
-                              sizeof(data_size));
-                       offset += sizeof(data_size);
-               }
+int mail_cache_field_exists(struct mail_cache_view *view, uint32_t seq,
+                           enum mail_cache_field field)
+{
+       i_assert(field < MAIL_CACHE_FIELD_COUNT);
 
-               prev_offset = offset + ((data_size + 3) & ~3);
-               if (prev_offset > cache_rec->size) {
-                       mail_cache_set_corrupted(cache,
-                               "Record continues outside it's allocated size");
-                       return FALSE;
-               }
+        if (MAIL_CACHE_IS_UNUSABLE(view->cache))
+               return 0;
 
-               if (field == mask) {
-                       if (data_size == 0) {
-                               mail_cache_set_corrupted(cache,
-                                                        "Field size is 0");
-                               return FALSE;
-                       }
-                       buffer_append(dest_buf,
-                                     CONST_PTR_OFFSET(cache_rec, offset),
-                                     data_size);
-                       return TRUE;
-               }
-               offset = prev_offset;
+       if (view->cached_exists_seq != seq) {
+               if (mail_cache_seq(view, seq) < 0)
+                       return -1;
        }
+       return view->cached_exists[field];
+}
 
-       i_unreached();
-       return FALSE;
+enum mail_cache_decision_type
+mail_cache_field_get_decision(struct mail_cache *cache,
+                             enum mail_cache_field field)
+{
+       i_assert(field < MAIL_CACHE_FIELD_COUNT);
+
+        if (MAIL_CACHE_IS_UNUSABLE(cache))
+               return cache->default_field_usage_decision_type[field];
+
+       return cache->hdr->field_usage_decision_type[field];
+}
+
+struct mail_cache_lookup_context {
+       buffer_t *dest_buf;
+       enum mail_cache_field field;
+};
+
+static int
+mail_cache_lookup_callback(struct mail_cache_view *view __attr_unused__,
+                          enum mail_cache_field field,
+                          const void *data, size_t data_size, void *context)
+{
+        struct mail_cache_lookup_context *ctx = context;
+
+       if (ctx->field != field)
+               return 1;
+
+       buffer_append(ctx->dest_buf, data, data_size);
+       return 0;
 }
 
 int mail_cache_lookup_field(struct mail_cache_view *view, buffer_t *dest_buf,
                            uint32_t seq, enum mail_cache_field field)
 {
-       struct mail_cache_record *cache_rec;
+        struct mail_cache_lookup_context ctx;
 
-       mail_cache_handle_decisions(view, seq, field);
+       i_assert(field < MAIL_CACHE_FIELD_COUNT);
 
-       cache_rec = mail_cache_lookup(view, seq);
-       while (cache_rec != NULL) {
-               if ((cache_rec->fields & field) != 0) {
-                       return cache_get_field(view->cache, cache_rec, field,
-                                              dest_buf);
-               }
-               cache_rec = mail_cache_get_record(view->cache,
-                                                 cache_rec->prev_offset);
+        if (MAIL_CACHE_IS_UNUSABLE(view->cache))
+               return 0;
+
+       mail_cache_decision_lookup(view, seq, field);
+
+       if (view->cached_exists_seq != seq) {
+               if (mail_cache_seq(view, seq) < 0)
+                       return -1;
        }
 
-       return FALSE;
+       if (!view->cached_exists[field])
+               return 0;
+
+       /* should exist. find it. */
+       ctx.field = field;
+       ctx.dest_buf = dest_buf;
+       return mail_cache_foreach(view, seq, mail_cache_lookup_callback,
+                                 &ctx) == 0;
 }
 
 int mail_cache_lookup_string_field(struct mail_cache_view *view, string_t *dest,
@@ -284,21 +335,24 @@ int mail_cache_lookup_string_field(struct mail_cache_view *view, string_t *dest,
 {
        size_t old_size, new_size;
 
-       i_assert((field & MAIL_CACHE_STRING_MASK) != 0);
+       i_assert(field < MAIL_CACHE_FIELD_COUNT);
+
+        if (MAIL_CACHE_IS_UNUSABLE(view->cache))
+               return 0;
 
        old_size = str_len(dest);
        if (!mail_cache_lookup_field(view, dest, seq, field))
-               return FALSE;
+               return 0;
 
        new_size = str_len(dest);
        if (old_size == new_size ||
            str_data(dest)[new_size-1] != '\0') {
                mail_cache_set_corrupted(view->cache,
                        "String field %x doesn't end with NUL", field);
-               return FALSE;
+               return -1;
        }
        str_truncate(dest, new_size-1);
-       return TRUE;
+       return 1;
 }
 
 enum mail_cache_record_flag
index 128586d280ff805358900b5c89996c8ae42f1a9c..3481f43c7941274c62fee91883a5b542f86cc7f2 100644 (file)
 #define MAIL_CACHE_IS_UNUSABLE(cache) \
        ((cache)->hdr == NULL)
 
-enum mail_cache_decision_type {
-       /* Not needed currently */
-       MAIL_CACHE_DECISION_NO          = 0x00,
-       /* Needed only for new mails. Drop when compressing. */
-       MAIL_CACHE_DECISION_TEMP        = 0x01,
-       /* Needed. */
-       MAIL_CACHE_DECISION_YES         = 0x02,
-
-       /* This decision has been forced manually, don't change it. */
-       MAIL_CACHE_DECISION_FORCED      = 0x80
-};
-
 struct mail_cache_header {
        /* version is increased only when you can't have backwards
           compatibility. */
@@ -69,9 +57,9 @@ struct mail_cache_header {
 };
 
 struct mail_cache_record {
-       uint32_t fields; /* enum mail_cache_field */
        uint32_t prev_offset;
        uint32_t size; /* full record size, including this header */
+       /* array of { uint32_t field; [ uint32_t size; ] { .. } } */
 };
 
 struct mail_cache_hole_header {
@@ -101,9 +89,7 @@ struct mail_cache {
        uint32_t split_offsets[MAIL_CACHE_HEADERS_COUNT];
        const char *const *split_headers[MAIL_CACHE_HEADERS_COUNT];
 
-       enum mail_cache_field default_cache_fields;
-       enum mail_cache_field never_cache_fields;
-
+       uint8_t default_field_usage_decision_type[32];
        uint32_t field_usage_uid_highwater[32];
 
        unsigned int locked:1;
@@ -115,7 +101,9 @@ struct mail_cache_view {
        struct mail_cache *cache;
        struct mail_index_view *view;
 
-       unsigned int broken:1;
+       struct mail_cache_transaction_ctx *transaction;
+       char cached_exists[32];
+       uint32_t cached_exists_seq;
 };
 
 extern unsigned int mail_cache_field_sizes[32];
@@ -123,7 +111,6 @@ extern enum mail_cache_field mail_cache_header_fields[MAIL_CACHE_HEADERS_COUNT];
 
 uint32_t mail_cache_uint32_to_offset(uint32_t offset);
 uint32_t mail_cache_offset_to_uint32(uint32_t offset);
-unsigned int mail_cache_field_index(enum mail_cache_field field);
 
 /* Explicitly lock the cache file. Returns -1 if error, 1 if ok, 0 if we
    couldn't lock */
@@ -138,8 +125,11 @@ 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);
 
-struct mail_cache_record *
-mail_cache_lookup(struct mail_cache_view *view, uint32_t seq);
+int mail_cache_foreach(struct mail_cache_view *view, uint32_t seq,
+                      int (*callback)(struct mail_cache_view *view,
+                                      enum mail_cache_field field,
+                                      const void *data, size_t data_size,
+                                      void *context), void *context);
 
 int mail_cache_transaction_commit(struct mail_cache_transaction_ctx *ctx);
 void mail_cache_transaction_rollback(struct mail_cache_transaction_ctx *ctx);
@@ -154,8 +144,10 @@ int mail_cache_link(struct mail_cache *cache, uint32_t old_offset,
 /* Mark record in given offset to be deleted. */
 int mail_cache_delete(struct mail_cache *cache, uint32_t offset);
 
-void mail_cache_handle_decisions(struct mail_cache_view *view, uint32_t seq,
-                                enum mail_cache_field field);
+void mail_cache_decision_lookup(struct mail_cache_view *view, uint32_t seq,
+                               enum mail_cache_field field);
+void mail_cache_decision_add(struct mail_cache_view *view, uint32_t seq,
+                            enum mail_cache_field field);
 
 void mail_cache_set_syscall_error(struct mail_cache *cache,
                                  const char *function);
index 46e62be8d5951be24b8faac1aa03b67e55462969..40265e10200e04f03a039af067e68c2c5904d561 100644 (file)
@@ -28,7 +28,7 @@ struct mail_cache_transaction_ctx {
        uint32_t last_grow_size;
 
        uint32_t first_seq, last_seq;
-       enum mail_cache_field fields;
+       enum mail_cache_field fields[32];
 
        unsigned int changes:1;
 };
@@ -55,12 +55,17 @@ mail_cache_get_transaction(struct mail_cache_view *view,
        ctx->reservations =
                buffer_create_dynamic(system_pool, 256, (size_t)-1);
 
+       i_assert(view->transaction == NULL);
+       view->transaction = ctx;
+
        t->cache_trans_ctx = ctx;
        return ctx;
 }
 
 static void mail_cache_transaction_free(struct mail_cache_transaction_ctx *ctx)
 {
+       ctx->view->transaction = NULL;
+
        buffer_free(ctx->cache_data);
        buffer_free(ctx->cache_data_seq);
        buffer_free(ctx->reservations);
@@ -317,7 +322,7 @@ mail_cache_transaction_flush(struct mail_cache_transaction_ctx *ctx)
        struct mail_cache *cache = ctx->cache;
        const struct mail_cache_record *rec, *tmp_rec;
        const uint32_t *seq;
-       uint32_t write_offset, old_offset, rec_offset;
+       uint32_t write_offset, old_offset, rec_pos;
        size_t size, max_size, seq_idx, seq_limit, seq_count;
        int commit;
 
@@ -332,9 +337,10 @@ mail_cache_transaction_flush(struct mail_cache_transaction_ctx *ctx)
 
        seq = buffer_get_data(ctx->cache_data_seq, &seq_count);
        seq_count /= sizeof(*seq);
+       seq_limit = 0;
 
-       for (seq_idx = 0, rec_offset = 0; rec_offset < ctx->prev_pos;) {
-               max_size = ctx->prev_pos - rec_offset;
+       for (seq_idx = 0, rec_pos = 0; rec_pos < ctx->prev_pos;) {
+               max_size = ctx->prev_pos - rec_pos;
                write_offset = mail_cache_transaction_get_space(ctx, rec->size,
                                                                max_size,
                                                                &max_size,
@@ -344,7 +350,7 @@ mail_cache_transaction_flush(struct mail_cache_transaction_ctx *ctx)
                        return ctx->prev_pos == 0 ? 0 : -1;
                }
 
-               if (max_size < ctx->prev_pos) {
+               if (rec_pos + max_size < ctx->prev_pos) {
                        /* see how much we can really write there */
                        tmp_rec = rec;
                        for (size = 0; size + tmp_rec->size <= max_size; ) {
@@ -383,7 +389,7 @@ mail_cache_transaction_flush(struct mail_cache_transaction_ctx *ctx)
                        }
 
                        write_offset += rec->size;
-                       rec_offset += rec->size;
+                       rec_pos += rec->size;
                        rec = CONST_PTR_OFFSET(rec, rec->size);
                }
        }
@@ -391,7 +397,10 @@ mail_cache_transaction_flush(struct mail_cache_transaction_ctx *ctx)
        /* drop the written data from buffer */
        buffer_copy(ctx->cache_data, 0,
                    ctx->cache_data, ctx->prev_pos, (size_t)-1);
-       buffer_set_used_size(ctx->cache_data, size - ctx->prev_pos);
+       buffer_set_used_size(ctx->cache_data,
+                            buffer_get_used_size(ctx->cache_data) -
+                            ctx->prev_pos);
+       ctx->prev_pos = 0;
 
        buffer_set_used_size(ctx->cache_data_seq, 0);
        return 0;
@@ -409,6 +418,7 @@ mail_cache_transaction_switch_seq(struct mail_cache_transaction_ctx *ctx)
                data = buffer_get_modifyable_data(ctx->cache_data, &size);
                rec = PTR_OFFSET(data, ctx->prev_pos);
                rec->size = size - ctx->prev_pos;
+               i_assert(rec->size != 0);
 
                buffer_append(ctx->cache_data_seq, &ctx->prev_seq,
                              sizeof(ctx->prev_seq));
@@ -588,62 +598,23 @@ int mail_cache_set_header_fields(struct mail_cache_transaction_ctx *ctx,
        return offset > 0;
 }
 
-static size_t
-mail_cache_transaction_get_insert_pos(struct mail_cache_transaction_ctx *ctx,
-                                     enum mail_cache_field field)
-{
-       const struct mail_cache_record *cache_rec;
-       const void *data;
-       unsigned int mask;
-       uint32_t data_size;
-       size_t pos;
-       int i;
-
-       data = buffer_get_data(ctx->cache_data, NULL);
-       cache_rec = CONST_PTR_OFFSET(data, ctx->prev_pos);
-
-       pos = ctx->prev_pos + sizeof(*cache_rec);
-       for (i = 0, mask = 1; i < 31; i++, mask <<= 1) {
-               if ((field & mask) != 0)
-                       return pos;
-
-               if ((cache_rec->fields & mask) != 0) {
-                       if ((mask & MAIL_CACHE_FIXED_MASK) != 0)
-                               data_size = mail_cache_field_sizes[i];
-                       else {
-                               memcpy(&data_size, CONST_PTR_OFFSET(data, pos),
-                                      sizeof(data_size));
-                               pos += sizeof(data_size);
-                       }
-                       pos += (data_size + 3) & ~3;
-               }
-       }
-
-       i_unreached();
-       return pos;
-}
-
 void mail_cache_add(struct mail_cache_transaction_ctx *ctx, uint32_t seq,
                    enum mail_cache_field field,
                    const void *data, size_t data_size)
 {
-       struct mail_cache_record *cache_rec;
-       unsigned char *buf;
-       size_t full_size, pos;
-       uint32_t data_size32;
-       unsigned int field_idx;
+       uint32_t fixed_size, data_size32;
+       size_t full_size;
 
+       i_assert(field < MAIL_CACHE_FIELD_COUNT);
        i_assert(data_size > 0);
        i_assert(data_size < (uint32_t)-1);
 
-       data_size32 = (uint32_t)data_size;
+       mail_cache_decision_add(ctx->view, seq, field);
 
-       if ((field & MAIL_CACHE_FIXED_MASK) != 0) {
-               field_idx = mail_cache_field_index(field);
-               i_assert(mail_cache_field_sizes[field_idx] == data_size);
-       } else if ((field & MAIL_CACHE_STRING_MASK) != 0) {
-               i_assert(((char *) data)[data_size-1] == '\0');
-       }
+       fixed_size = mail_cache_field_sizes[field];
+       i_assert(fixed_size == (unsigned int)-1 || fixed_size == data_size);
+
+       data_size32 = (uint32_t)data_size;
 
        if (ctx->prev_seq != seq) {
                mail_cache_transaction_switch_seq(ctx);
@@ -655,11 +626,12 @@ void mail_cache_add(struct mail_cache_transaction_ctx *ctx, uint32_t seq,
                        ctx->first_seq = seq;
                if (seq > ctx->last_seq)
                        ctx->last_seq = seq;
-               ctx->fields |= field;
+               ctx->view->cached_exists[field] = TRUE;
+               ctx->fields[field] = TRUE;
        }
 
        full_size = (data_size + 3) & ~3;
-       if ((field & MAIL_CACHE_FIXED_MASK) == 0)
+       if (fixed_size == (unsigned int)-1)
                full_size += sizeof(data_size32);
 
        if (buffer_get_used_size(ctx->cache_data) + full_size >
@@ -669,24 +641,15 @@ void mail_cache_add(struct mail_cache_transaction_ctx *ctx, uint32_t seq,
                        return;
        }
 
-       /* fields must be ordered. find where to insert it. */
-       pos = mail_cache_transaction_get_insert_pos(ctx, field);
-       buffer_copy(ctx->cache_data, pos + full_size,
-                   ctx->cache_data, pos, (size_t)-1);
-
-       cache_rec = buffer_get_space_unsafe(ctx->cache_data, ctx->prev_pos,
-                                           sizeof(*cache_rec));
-       cache_rec->fields |= field;
-
-       /* @UNSAFE */
-       buf = buffer_get_space_unsafe(ctx->cache_data, pos, full_size);
-       if ((field & MAIL_CACHE_FIXED_MASK) == 0) {
-               memcpy(buf, &data_size32, sizeof(data_size32));
-               buf += sizeof(data_size32);
+       buffer_append(ctx->cache_data, &field, sizeof(field));
+       if (fixed_size == (unsigned int)-1) {
+               buffer_append(ctx->cache_data, &data_size32,
+                             sizeof(data_size32));
        }
-       memcpy(buf, data, data_size); buf += data_size;
+
+       buffer_append(ctx->cache_data, data, data_size);
        if ((data_size & 3) != 0)
-               memset(buf, 0, 4 - (data_size & 3));
+                buffer_append(ctx->cache_data, null4, 4 - (data_size & 3));
 }
 
 int mail_cache_update_record_flags(struct mail_cache_view *view, uint32_t seq,
index e4c487d8971b92501df14e8db79481d7b1764f8b..a806af3d5765d1d0aef7a39dca4873c22bbc503b 100644 (file)
@@ -15,13 +15,13 @@ unsigned int mail_cache_field_sizes[32] = {
        sizeof(time_t),
        sizeof(uoff_t),
 
-       0, 0, 0, 0, 0, 0, 0, 0,
-
        /* variable sized */
        (unsigned int)-1, (unsigned int)-1, (unsigned int)-1, (unsigned int)-1,
        (unsigned int)-1, (unsigned int)-1, (unsigned int)-1, (unsigned int)-1,
        (unsigned int)-1, (unsigned int)-1, (unsigned int)-1, (unsigned int)-1,
        (unsigned int)-1, (unsigned int)-1, (unsigned int)-1, (unsigned int)-1,
+       (unsigned int)-1, (unsigned int)-1, (unsigned int)-1, (unsigned int)-1,
+       (unsigned int)-1, (unsigned int)-1, (unsigned int)-1, (unsigned int)-1,
        (unsigned int)-1, (unsigned int)-1, (unsigned int)-1, (unsigned int)-1
 };
 
@@ -60,17 +60,6 @@ uint32_t mail_cache_offset_to_uint32(uint32_t offset)
                (((uint32_t)buf[0] & 0x7f) << 23);
 }
 
-unsigned int mail_cache_field_index(enum mail_cache_field field)
-{
-       unsigned int i, num;
-
-       for (i = 0, num = 1; i < 32; i++, num <<= 1) {
-               if (field == num)
-                       return i;
-       }
-       i_unreached();
-}
-
 void mail_cache_set_syscall_error(struct mail_cache *cache,
                                  const char *function)
 {
@@ -284,11 +273,10 @@ void mail_cache_free(struct mail_cache *cache)
 }
 
 void mail_cache_set_defaults(struct mail_cache *cache,
-                            enum mail_cache_field default_cache_fields,
-                            enum mail_cache_field never_cache_fields)
+                            const enum mail_cache_decision_type dec[32])
 {
-       cache->default_cache_fields = default_cache_fields;
-       cache->never_cache_fields = never_cache_fields;
+       memcpy(cache->default_field_usage_decision_type, dec,
+              sizeof(cache->default_field_usage_decision_type));
 }
 
 int mail_cache_lock(struct mail_cache *cache)
index 5abfa440c3afe15575088c0445c8f6e91eb4cf9a..44477d39968958c94300729fe92903757fbe5006 100644 (file)
@@ -11,6 +11,18 @@ struct mail_cache;
 struct mail_cache_view;
 struct mail_cache_transaction_ctx;
 
+enum mail_cache_decision_type {
+       /* Not needed currently */
+       MAIL_CACHE_DECISION_NO          = 0x00,
+       /* Needed only for new mails. Drop when compressing. */
+       MAIL_CACHE_DECISION_TEMP        = 0x01,
+       /* Needed. */
+       MAIL_CACHE_DECISION_YES         = 0x02,
+
+       /* This decision has been forced manually, don't change it. */
+       MAIL_CACHE_DECISION_FORCED      = 0x80
+};
+
 enum mail_cache_record_flag {
        /* If binary flags are set, it's not checked whether mail is
           missing CRs. So this flag may be set as an optimization for
@@ -28,40 +40,23 @@ enum mail_cache_record_flag {
 /* when modifying, remember to update mail_cache_field_sizes[] too */
 enum mail_cache_field {
        /* fixed size fields */
-       MAIL_CACHE_INDEX_FLAGS          = 0x00000001,
-       MAIL_CACHE_SENT_DATE            = 0x00000002,
-       MAIL_CACHE_RECEIVED_DATE        = 0x00000004,
-       MAIL_CACHE_VIRTUAL_FULL_SIZE    = 0x00000008,
+       MAIL_CACHE_INDEX_FLAGS = 0,
+       MAIL_CACHE_SENT_DATE,
+       MAIL_CACHE_RECEIVED_DATE,
+       MAIL_CACHE_VIRTUAL_FULL_SIZE,
 
        /* variable sized field */
-       MAIL_CACHE_HEADERS1             = 0x40000000,
-       MAIL_CACHE_HEADERS2             = 0x20000000,
-       MAIL_CACHE_HEADERS3             = 0x10000000,
-       MAIL_CACHE_HEADERS4             = 0x08000000,
-       MAIL_CACHE_LOCATION             = 0x04000000,
-       MAIL_CACHE_BODY                 = 0x02000000,
-       MAIL_CACHE_BODYSTRUCTURE        = 0x01000000,
-       MAIL_CACHE_ENVELOPE             = 0x00800000,
-       MAIL_CACHE_MESSAGEPART          = 0x00400000,
-       MAIL_CACHE_UID_STRING           = 0x00200000,
-
-       MAIL_CACHE_FIXED_MASK           = MAIL_CACHE_INDEX_FLAGS |
-                                         MAIL_CACHE_SENT_DATE |
-                                         MAIL_CACHE_RECEIVED_DATE |
-                                         MAIL_CACHE_VIRTUAL_FULL_SIZE,
-       MAIL_CACHE_HEADERS_MASK         = MAIL_CACHE_HEADERS1 |
-                                         MAIL_CACHE_HEADERS2 |
-                                         MAIL_CACHE_HEADERS3 |
-                                         MAIL_CACHE_HEADERS4,
-       MAIL_CACHE_STRING_MASK          = MAIL_CACHE_HEADERS_MASK |
-                                         MAIL_CACHE_LOCATION |
-                                         MAIL_CACHE_BODY |
-                                         MAIL_CACHE_BODYSTRUCTURE |
-                                         MAIL_CACHE_ENVELOPE |
-                                         MAIL_CACHE_UID_STRING,
-       MAIL_CACHE_BODYSTRUCTURE_MASK   = MAIL_CACHE_BODY |
-                                         MAIL_CACHE_BODYSTRUCTURE |
-                                          MAIL_CACHE_MESSAGEPART
+       MAIL_CACHE_HEADERS1,
+       MAIL_CACHE_HEADERS2,
+       MAIL_CACHE_HEADERS3,
+       MAIL_CACHE_HEADERS4,
+       MAIL_CACHE_BODY,
+       MAIL_CACHE_BODYSTRUCTURE,
+       MAIL_CACHE_ENVELOPE,
+       MAIL_CACHE_MESSAGEPART,
+       MAIL_CACHE_UID_STRING,
+
+       MAIL_CACHE_FIELD_COUNT
 };
 
 struct mail_sent_date {
@@ -75,8 +70,7 @@ struct mail_cache *mail_cache_open_or_create(struct mail_index *index);
 void mail_cache_free(struct mail_cache *cache);
 
 void mail_cache_set_defaults(struct mail_cache *cache,
-                            enum mail_cache_field default_cache_fields,
-                            enum mail_cache_field never_cache_fields);
+                            const enum mail_cache_decision_type dec[32]);
 
 /* Returns TRUE if cache should be compressed. */
 int mail_cache_need_compress(struct mail_cache *cache);
@@ -106,9 +100,13 @@ void mail_cache_add(struct mail_cache_transaction_ctx *ctx, uint32_t seq,
                    enum mail_cache_field field,
                    const void *data, size_t data_size);
 
-/* Return all fields that are currently cached for record. */
-enum mail_cache_field
-mail_cache_get_fields(struct mail_cache_view *view, uint32_t seq);
+/* Retursn TRUE if field exists. */
+int mail_cache_field_exists(struct mail_cache_view *view, uint32_t seq,
+                           enum mail_cache_field field);
+/* Returns current caching decision for given field. */
+enum mail_cache_decision_type
+mail_cache_field_get_decision(struct mail_cache *cache,
+                             enum mail_cache_field field);
 
 /* Set data_r and size_r to point to wanted field in cache file.
    Returns TRUE if field was found. If field contains multiple fields,
@@ -120,10 +118,6 @@ int mail_cache_lookup_field(struct mail_cache_view *view, buffer_t *dest_buf,
 int mail_cache_lookup_string_field(struct mail_cache_view *view, string_t *dest,
                                   uint32_t seq, enum mail_cache_field field);
 
-/* Mark given field as missing, ie. it should be cached when possible. */
-void mail_cache_mark_missing(struct mail_cache_view *view, uint32_t uid,
-                            enum mail_cache_field field);
-
 /* Return record flags. */
 enum mail_cache_record_flag
 mail_cache_get_record_flags(struct mail_cache_view *view, uint32_t seq);
index a4d4ebe428108d2eaa6d91069c89efe992e12de8..9da40eb61443265f7e758c19adea8f9a84cc10b8 100644 (file)
@@ -10,23 +10,13 @@ index_storage_fetch(struct mailbox_transaction_context *_t, uint32_t seq,
 {
        struct index_transaction_context *t =
                (struct index_transaction_context *)_t;
-        const struct mail_index_record *rec;
-
-       if (mail_index_lookup(t->trans_view, seq, &rec) < 0) {
-               mail_storage_set_index_error(t->ibox);
-               return NULL;
-       }
-
-       if (rec == NULL)
-               return NULL;
 
        if (t->fetch_mail.pool != NULL)
                index_mail_deinit(&t->fetch_mail);
 
        index_mail_init(t, &t->fetch_mail, wanted_fields, NULL);
-       if (index_mail_next(&t->fetch_mail, rec, seq, FALSE) <= 0)
+       if (index_mail_next(&t->fetch_mail, seq) < 0)
                return NULL;
-
        return &t->fetch_mail.mail;
 }
 
index 423966e7fee8f0353d5ae80354e61d66f81f80a7..ee353ba7b82fd005223e9ba1d66b37d3bef13c0e 100644 (file)
@@ -191,8 +191,9 @@ static int mail_find_wanted_headers(struct index_mail *mail,
                return -1;
 
        for (; idx < MAIL_CACHE_HEADERS_COUNT; idx++) {
-               if ((mail->data.cached_fields &
-                    mail_cache_header_fields[idx]) != 0)
+               if (mail_cache_field_exists(mail->trans->cache_view,
+                                           mail->data.seq,
+                                           mail_cache_header_fields[idx]) > 0)
                        return idx;
        }
 
@@ -320,9 +321,9 @@ int index_mail_parse_header(struct message_part *part,
                        data->save_sent_date = FALSE;
                }
                if (data->sent_date.time != (time_t)-1) {
-                       index_mail_cache_add(mail, MAIL_CACHE_SENT_DATE,
-                                            &data->sent_date,
-                                            sizeof(data->sent_date));
+                        mail_cache_add(mail->trans->cache_trans, data->seq,
+                                      MAIL_CACHE_SENT_DATE, &data->sent_date,
+                                      sizeof(data->sent_date));
                }
 
                cached_headers_mark_fully_saved(mail);
@@ -387,8 +388,11 @@ static void index_mail_parse_header_cb(struct message_part *part,
 
 static int index_mail_can_cache_headers(struct index_mail *mail)
 {
-       if ((mail->data.cached_fields &
-            mail_cache_header_fields[MAIL_CACHE_HEADERS_COUNT-1]) != 0)
+       enum mail_cache_field field;
+
+       field = mail_cache_header_fields[MAIL_CACHE_HEADERS_COUNT-1];
+       if (mail_cache_field_exists(mail->trans->cache_view, mail->data.seq,
+                                   field) != 0)
                return FALSE; /* all headers used */
 
        /* FIXME: add some smart checks here. we don't necessarily want to
@@ -493,9 +497,6 @@ int index_mail_parse_headers(struct index_mail *mail)
        if (mail->data.header_data == NULL)
                mail->data.header_data = str_new(mail->pool, 4096);
 
-       /* can_cache_headers() locks the cache file. it must be done before
-          we can expect cached headers to stay the same. it's not a good idea
-          to cache some headers twice because of race conditions.. */
        if (!data->header_fully_parsed && index_mail_can_cache_headers(mail)) {
                if (data->header_data_cached_partial) {
                        /* too difficult to handle efficiently, trash it */
@@ -722,8 +723,10 @@ void index_mail_headers_init_next(struct index_mail *mail)
        if (idx != -2) {
                if (idx >= 0) {
                        for (; idx < MAIL_CACHE_HEADERS_COUNT; idx++) {
-                               if ((data->cached_fields &
-                                    mail_cache_header_fields[idx]) != 0)
+                               if (mail_cache_field_exists(
+                                       mail->trans->cache_view,
+                                       data->seq,
+                                       mail_cache_header_fields[idx]) > 0)
                                        break;
                        }
                }
index 0e4af853d4cc57fa1a5eb652bde716ee10e6f2ed..216bd36ed1d4eb42b6b2cce2ccd7993ea2273814 100644 (file)
@@ -13,7 +13,7 @@
 #include "index-storage.h"
 #include "index-mail.h"
 
-static void index_mail_parse_body(struct index_mail *mail);
+static void index_mail_parse_body(struct index_mail *mail, int need_parts);
 
 static struct message_part *get_cached_parts(struct index_mail *mail)
 {
@@ -21,17 +21,13 @@ static struct message_part *get_cached_parts(struct index_mail *mail)
        buffer_t *part_buf;
        const char *error;
 
-       if ((mail->data.cached_fields & MAIL_CACHE_MESSAGEPART) == 0) {
-               mail_cache_mark_missing(mail->trans->cache_view, mail->data.seq,
-                                       MAIL_CACHE_MESSAGEPART);
-               return NULL;
-       }
-
+       t_push();
        part_buf = buffer_create_dynamic(pool_datastack_create(),
                                         128, (size_t)-1);
-       if (!mail_cache_lookup_field(mail->trans->cache_view, part_buf,
-                                    mail->data.seq, MAIL_CACHE_MESSAGEPART)) {
-               /* unexpected - must be an error */
+       if (mail_cache_lookup_field(mail->trans->cache_view, part_buf,
+                                   mail->data.seq,
+                                   MAIL_CACHE_MESSAGEPART) <= 0) {
+               t_pop();
                return NULL;
        }
 
@@ -39,6 +35,8 @@ static struct message_part *get_cached_parts(struct index_mail *mail)
                                        buffer_get_data(part_buf, NULL),
                                        buffer_get_used_size(part_buf),
                                        &error);
+       t_pop();
+
        if (part == NULL) {
                mail_cache_set_corrupted(mail->ibox->cache,
                        "Corrupted cached message_part data (%s)", error);
@@ -62,16 +60,12 @@ const char *index_mail_get_cached_string(struct index_mail *mail,
 {
        string_t *str;
 
-       if ((mail->data.cached_fields & field) == 0) {
-               mail_cache_mark_missing(mail->trans->cache_view,
-                                       mail->data.seq, field);
-               return NULL;
-       }
-
        str = str_new(mail->pool, 32);
-       if (!mail_cache_lookup_string_field(mail->trans->cache_view, str,
-                                           mail->data.seq, field))
+       if (mail_cache_lookup_string_field(mail->trans->cache_view, str,
+                                          mail->data.seq, field) <= 0) {
+               p_free(mail->pool, str);
                return NULL;
+       }
 
        return str_c(str);
 }
@@ -85,10 +79,8 @@ static int index_mail_get_fixed_field(struct index_mail *mail,
 
        t_push();
        buf = buffer_create_data(pool_datastack_create(), data, data_size);
-       if (!mail_cache_lookup_field(mail->trans->cache_view, buf,
-                                    mail->data.seq, field)) {
-               mail_cache_mark_missing(mail->trans->cache_view,
-                                       mail->data.seq, field);
+       if (mail_cache_lookup_field(mail->trans->cache_view, buf,
+                                   mail->data.seq, field) <= 0) {
                ret = FALSE;
        } else {
                i_assert(buffer_get_used_size(buf) == data_size);
@@ -144,35 +136,6 @@ void index_mail_cache_transaction_begin(struct index_mail *mail)
        }
 }
 
-static int index_mail_cache_can_add(struct index_mail *mail,
-                                   enum mail_cache_field field)
-{
-       if ((mail->data.cached_fields & field) != 0)
-               return FALSE;
-
-       // FIXME: check if we really want to cache this
-
-       index_mail_cache_transaction_begin(mail);
-
-       /* cached_fields may have changed, recheck */
-       if ((mail->data.cached_fields & field) != 0)
-               return FALSE;
-
-       return TRUE;
-}
-
-void index_mail_cache_add(struct index_mail *mail, enum mail_cache_field field,
-                         const void *data, size_t size)
-{
-        if (!index_mail_cache_can_add(mail, field))
-               return;
-
-       mail_cache_add(mail->trans->cache_trans, mail->data.seq,
-                      field, data, size);
-
-       mail->data.cached_fields |= field;
-}
-
 const struct mail_full_flags *index_mail_get_flags(struct mail *_mail)
 {
        struct index_mail *mail = (struct index_mail *) _mail;
@@ -194,17 +157,15 @@ const struct message_part *index_mail_get_parts(struct mail *_mail)
        if (data->parts != NULL)
                return data->parts;
 
-       if ((mail->wanted_fields & MAIL_FETCH_MESSAGE_PARTS) == 0) {
-               data->parts = get_cached_parts(mail);
-               if (data->parts != NULL)
-                       return data->parts;
-       }
+       data->parts = get_cached_parts(mail);
+       if (data->parts != NULL)
+               return data->parts;
 
        if (data->parser_ctx == NULL) {
                if (!index_mail_parse_headers(mail))
                        return NULL;
        }
-       index_mail_parse_body(mail);
+       index_mail_parse_body(mail, TRUE);
 
        return data->parts;
 }
@@ -251,9 +212,9 @@ time_t index_mail_get_date(struct mail *_mail, int *timezone)
                                tz = 0;
                        }
                         data->sent_date.timezone = tz;
-                       index_mail_cache_add(mail, MAIL_CACHE_SENT_DATE,
-                                            &data->sent_date,
-                                            sizeof(data->sent_date));
+                       mail_cache_add(mail->trans->cache_trans, mail->data.seq,
+                                      MAIL_CACHE_SENT_DATE, &data->sent_date,
+                                      sizeof(data->sent_date));
                }
        }
 
@@ -266,12 +227,8 @@ static int get_msgpart_sizes(struct index_mail *mail)
 {
        struct index_mail_data *data = &mail->data;
 
-       if (data->parts == NULL) {
-               if ((mail->wanted_fields & MAIL_FETCH_MESSAGE_PARTS) != 0)
-                       (void)index_mail_get_parts(&mail->mail);
-               else
-                       data->parts = get_cached_parts(mail);
-       }
+       if (data->parts == NULL)
+               (void)index_mail_get_parts(&mail->mail);
 
        if (data->parts != NULL) {
                data->hdr_size = data->parts->header_size;
@@ -294,11 +251,9 @@ uoff_t index_mail_get_size(struct mail *_mail)
        if (data->size != (uoff_t)-1)
                return data->size;
 
-       if ((mail->wanted_fields & MAIL_FETCH_SIZE) == 0) {
-               data->size = index_mail_get_cached_virtual_size(mail);
-               if (data->size != (uoff_t)-1)
-                       return data->size;
-       }
+       data->size = index_mail_get_cached_virtual_size(mail);
+       if (data->size != (uoff_t)-1)
+               return data->size;
 
        if (get_msgpart_sizes(mail))
                return data->size;
@@ -318,10 +273,11 @@ static void parse_bodystructure_header(struct message_part *part,
        imap_bodystructure_parse_header(pool, part, hdr);
 }
 
-static void index_mail_parse_body(struct index_mail *mail)
+static void index_mail_parse_body(struct index_mail *mail, int need_parts)
 {
        struct index_mail_data *data = &mail->data;
         enum mail_cache_record_flag cache_flags;
+       enum mail_cache_decision_type decision;
        buffer_t *buffer;
        const void *buf_data;
        size_t buf_size;
@@ -332,6 +288,8 @@ static void index_mail_parse_body(struct index_mail *mail)
        i_stream_seek(data->stream, data->hdr_size.physical_size);
 
        if (data->bodystructure_header_parsed) {
+               /* bodystructure header is parsed, we want the body's mime
+                  headers too */
                message_parser_parse_body(data->parser_ctx,
                                          parse_bodystructure_header,
                                          NULL, mail->pool);
@@ -344,41 +302,50 @@ static void index_mail_parse_body(struct index_mail *mail)
        data->body_size = data->parts->body_size;
        data->body_size_set = TRUE;
 
-       if (mail->mail.has_nuls || mail->mail.has_no_nuls)
-               return;
+       index_mail_cache_transaction_begin(mail);
 
-       /* we know the NULs now, update them */
-       if ((data->parts->flags & MESSAGE_PART_FLAG_HAS_NULS) != 0) {
-               mail->mail.has_nuls = TRUE;
-               mail->mail.has_no_nuls = FALSE;
-       } else {
-               mail->mail.has_nuls = FALSE;
-               mail->mail.has_no_nuls = TRUE;
-       }
+       if (!mail->mail.has_nuls && !mail->mail.has_no_nuls) {
+               /* we know the NULs now, update them */
+               if ((data->parts->flags & MESSAGE_PART_FLAG_HAS_NULS) != 0) {
+                       mail->mail.has_nuls = TRUE;
+                       mail->mail.has_no_nuls = FALSE;
+               } else {
+                       mail->mail.has_nuls = FALSE;
+                       mail->mail.has_no_nuls = TRUE;
+               }
 
-       index_mail_cache_transaction_begin(mail);
+               /* update cache_flags */
+               cache_flags =
+                       mail_cache_get_record_flags(mail->trans->cache_view,
+                                                   mail->data.seq);
+               if (mail->mail.has_nuls)
+                       cache_flags |= MAIL_INDEX_FLAG_HAS_NULS;
+               else
+                       cache_flags |= MAIL_INDEX_FLAG_HAS_NO_NULS;
 
-       /* update cache_flags */
-       cache_flags = mail_cache_get_record_flags(mail->trans->cache_view,
-                                                 mail->data.seq);
-       if (mail->mail.has_nuls)
-               cache_flags |= MAIL_INDEX_FLAG_HAS_NULS;
-       else
-               cache_flags |= MAIL_INDEX_FLAG_HAS_NO_NULS;
+               (void)mail_cache_update_record_flags(mail->trans->cache_view,
+                                                    mail->data.seq,
+                                                    cache_flags);
+       }
 
-       if (!mail_cache_update_record_flags(mail->trans->cache_view,
-                                           mail->data.seq, cache_flags))
+       /* see if we want to cache the message part */
+       if (mail_cache_field_exists(mail->trans->cache_view, mail->data.seq,
+                                   MAIL_CACHE_MESSAGEPART) != 0)
                return;
 
-       if (index_mail_cache_can_add(mail, MAIL_CACHE_MESSAGEPART)) {
+       decision = mail_cache_field_get_decision(mail->ibox->cache,
+                                                MAIL_CACHE_MESSAGEPART);
+       if (decision != (MAIL_CACHE_DECISION_NO | MAIL_CACHE_DECISION_FORCED) &&
+           (decision != MAIL_CACHE_DECISION_NO || need_parts ||
+            (mail->wanted_fields & MAIL_FETCH_MESSAGE_PARTS) != 0)) {
                t_push();
                buffer = buffer_create_dynamic(pool_datastack_create(),
                                               1024, (size_t)-1);
                message_part_serialize(mail->data.parts, buffer);
 
                buf_data = buffer_get_data(buffer, &buf_size);
-               index_mail_cache_add(mail, MAIL_CACHE_MESSAGEPART,
-                                    buf_data, buf_size);
+               mail_cache_add(mail->trans->cache_trans, mail->data.seq,
+                              MAIL_CACHE_MESSAGEPART, buf_data, buf_size);
                t_pop();
        }
 }
@@ -404,7 +371,7 @@ struct istream *index_mail_init_stream(struct index_mail *_mail,
 
        if (body_size != NULL) {
                if (!data->body_size_set)
-                       index_mail_parse_body(mail);
+                       index_mail_parse_body(mail, FALSE);
 
                *body_size = data->body_size;
        }
@@ -418,83 +385,127 @@ struct istream *index_mail_init_stream(struct index_mail *_mail,
        return data->stream;
 }
 
+static void index_mail_parse_bodystructure(struct index_mail *mail,
+                                          enum mail_cache_field field)
+{
+       struct index_mail_data *data = &mail->data;
+       enum mail_cache_decision_type dec;
+       string_t *str;
+       int bodystructure_cached = FALSE;
+
+       if (!data->bodystructure_header_parsed) {
+               data->bodystructure_header_want = TRUE;
+               if (!index_mail_parse_headers(mail))
+                       return;
+       }
+
+       if (data->parts != NULL) {
+               i_assert(data->parts->next == NULL);
+               message_parse_from_parts(data->parts->children, data->stream,
+                                        parse_bodystructure_header,
+                                        mail->pool);
+       } else {
+               index_mail_parse_body(mail, FALSE);
+       }
+
+       dec = mail_cache_field_get_decision(mail->ibox->cache,
+                                           MAIL_CACHE_BODYSTRUCTURE);
+       if (field == MAIL_CACHE_BODYSTRUCTURE ||
+           ((dec & ~MAIL_CACHE_DECISION_FORCED) != MAIL_CACHE_DECISION_NO &&
+            mail_cache_field_exists(mail->trans->cache_view, data->seq,
+                                     MAIL_CACHE_BODYSTRUCTURE)) == 0) {
+               str = str_new(mail->pool, 128);
+               imap_bodystructure_write(data->parts, str, TRUE);
+               data->bodystructure = str_c(str);
+
+               if (dec !=
+                   (MAIL_CACHE_DECISION_NO | MAIL_CACHE_DECISION_FORCED)) {
+                       mail_cache_add(mail->trans->cache_trans, data->seq,
+                                      MAIL_CACHE_BODYSTRUCTURE,
+                                      str_c(str), str_len(str)+1);
+                       bodystructure_cached = TRUE;
+               }
+       }
+
+       dec = mail_cache_field_get_decision(mail->ibox->cache, MAIL_CACHE_BODY);
+       if (field == MAIL_CACHE_BODY ||
+           ((dec & ~MAIL_CACHE_DECISION_FORCED) != MAIL_CACHE_DECISION_NO &&
+            mail_cache_field_exists(mail->trans->cache_view, data->seq,
+                                    MAIL_CACHE_BODY)) == 0) {
+               str = str_new(mail->pool, 128);
+               imap_bodystructure_write(data->parts, str, FALSE);
+               data->body = str_c(str);
+
+               if (!bodystructure_cached && dec !=
+                   (MAIL_CACHE_DECISION_NO | MAIL_CACHE_DECISION_FORCED)) {
+                       mail_cache_add(mail->trans->cache_trans, data->seq,
+                                      MAIL_CACHE_BODY,
+                                      str_c(str), str_len(str)+1);
+               }
+       }
+}
+
 const char *index_mail_get_special(struct mail *_mail,
                                   enum mail_fetch_field field)
 {
        struct index_mail *mail = (struct index_mail *) _mail;
        struct index_mail_data *data = &mail->data;
-       struct mail_cache *cache = mail->ibox->cache;
-       enum mail_cache_field cache_field;
-       char *str;
+       string_t *str;
 
        switch (field) {
        case MAIL_FETCH_IMAP_BODY:
-               if ((data->cached_fields & MAIL_CACHE_BODY) &&
-                   data->body == NULL) {
-                       data->body = index_mail_get_cached_string(mail,
-                                       MAIL_CACHE_BODY);
-               }
                if (data->body != NULL)
                        return data->body;
-               /* fall through */
-       case MAIL_FETCH_IMAP_BODYSTRUCTURE:
-               if ((data->cached_fields & MAIL_CACHE_BODYSTRUCTURE) &&
-                   data->bodystructure == NULL) {
-                       data->bodystructure = index_mail_get_cached_string(mail,
-                                               MAIL_CACHE_BODYSTRUCTURE);
-               }
-
-               if (data->bodystructure != NULL) {
-                       if (field == MAIL_FETCH_IMAP_BODYSTRUCTURE)
-                               return data->bodystructure;
 
-                       /* create BODY from cached BODYSTRUCTURE */
-                       t_push();
-                       data->body = p_strdup(mail->pool,
-                               imap_body_parse_from_bodystructure(
-                                                       data->bodystructure));
-                       t_pop();
+               /* 1) get BODY if it exists
+                  2) get it using BODYSTRUCTURE if it exists
+                  3) parse body structure, and save BODY/BODYSTRUCTURE
+                     depending on what we want cached */
 
-                       if (data->body == NULL) {
-                               mail_cache_set_corrupted(cache,
-                                       "Corrupted BODYSTRUCTURE");
-                       }
+               str = str_new(mail->pool, 128);
+               if (mail_cache_lookup_string_field(mail->trans->cache_view,
+                                                  str, mail->data.seq,
+                                                  MAIL_CACHE_BODY) > 0) {
+                       data->body = str_c(str);
                        return data->body;
                }
+               if (mail_cache_lookup_string_field(mail->trans->cache_view,
+                                       str, mail->data.seq,
+                                       MAIL_CACHE_BODYSTRUCTURE) > 0) {
+                       data->bodystructure = str_c(str);
+                       str_truncate(str, 0);
+
+                       if (imap_body_parse_from_bodystructure(
+                                               data->bodystructure, str)) {
+                               data->body = str_c(str);
+                               return data->body;
+                       }
 
-               if (!data->bodystructure_header_parsed) {
-                       data->bodystructure_header_want = TRUE;
-                       if (!index_mail_parse_headers(mail))
-                               return NULL;
+                       /* broken, continue.. */
+                       data->bodystructure = NULL;
+                       mail_cache_set_corrupted(mail->ibox->cache,
+                               "Corrupted BODYSTRUCTURE for mail %u",
+                               mail->mail.uid);
                }
+               p_free(mail->pool, str);
 
-               if (data->parts != NULL) {
-                       i_assert(data->parts->next == NULL);
-                       message_parse_from_parts(data->parts->children,
-                                                data->stream,
-                                                parse_bodystructure_header,
-                                                mail->pool);
-               } else {
-                       index_mail_parse_body(mail);
+               index_mail_parse_bodystructure(mail, MAIL_CACHE_BODY);
+               return data->body;
+       case MAIL_FETCH_IMAP_BODYSTRUCTURE:
+               if (data->bodystructure != NULL)
+                       return data->bodystructure;
+
+               str = str_new(mail->pool, 128);
+               if (mail_cache_lookup_string_field(mail->trans->cache_view,
+                                       str, mail->data.seq,
+                                       MAIL_CACHE_BODYSTRUCTURE) > 0) {
+                       data->bodystructure = str_c(str);
+                       return data->bodystructure;
                }
+               p_free(mail->pool, str);
 
-               t_push();
-                str = p_strdup(mail->pool, imap_bodystructure_parse_finish(
-                       data->parts, field == MAIL_FETCH_IMAP_BODYSTRUCTURE));
-               t_pop();
-
-               /* should never fail */
-               i_assert(str != NULL);
-
-               cache_field = field == MAIL_FETCH_IMAP_BODYSTRUCTURE ?
-                       MAIL_CACHE_BODYSTRUCTURE : MAIL_CACHE_BODY;
-               index_mail_cache_add(mail, cache_field, str, strlen(str)+1);
-
-               if (field == MAIL_FETCH_IMAP_BODYSTRUCTURE)
-                       data->bodystructure = str;
-               else
-                       data->body = str;
-               return str;
+               index_mail_parse_bodystructure(mail, MAIL_CACHE_BODYSTRUCTURE);
+               return data->bodystructure;
        case MAIL_FETCH_IMAP_ENVELOPE:
                if (data->envelope != NULL)
                        return data->envelope;
@@ -550,13 +561,16 @@ static void index_mail_close(struct index_mail *mail)
        index_mail_headers_close(mail);
 }
 
-int index_mail_next(struct index_mail *mail,
-                   const struct mail_index_record *rec,
-                   uint32_t seq, int delay_open)
+int index_mail_next(struct index_mail *mail, uint32_t seq)
 {
        struct index_mail_data *data = &mail->data;
+        const struct mail_index_record *rec;
         enum mail_cache_record_flag cache_flags;
-       int ret, open_mail;
+
+       if (mail_index_lookup(mail->trans->trans_view, seq, &rec) < 0) {
+               mail_storage_set_index_error(mail->ibox);
+               return -1;
+       }
 
        t_push();
 
@@ -564,10 +578,7 @@ int index_mail_next(struct index_mail *mail,
        memset(data, 0, sizeof(*data));
        p_clear(mail->pool);
 
-       data->cached_fields =
-               mail_cache_get_fields(mail->trans->cache_view, seq);
-       cache_flags = (data->cached_fields & MAIL_CACHE_INDEX_FLAGS) == 0 ? 0 :
-               mail_cache_get_record_flags(mail->trans->cache_view, seq);
+       cache_flags = mail_cache_get_record_flags(mail->trans->cache_view, seq);
 
        mail->mail.seq = seq;
        mail->mail.uid = rec->uid;
@@ -599,7 +610,6 @@ int index_mail_next(struct index_mail *mail,
                get_cached_sent_date(mail, &data->sent_date);
 
        /* see if we have to parse the message */
-       open_mail = FALSE;
        if ((mail->wanted_fields & MAIL_FETCH_MESSAGE_PARTS) &&
            data->parts == NULL)
                data->parse_header = TRUE;
@@ -607,36 +617,22 @@ int index_mail_next(struct index_mail *mail,
                 data->bodystructure == NULL) {
                if (data->parts == NULL)
                        data->parts = get_cached_parts(mail);
-               open_mail = TRUE;
+               data->open_mail = TRUE;
                data->parse_header = data->parts == NULL;
-                data->bodystructure_header_want = TRUE;
+               data->bodystructure_header_want = TRUE;
        } else if ((mail->wanted_fields & MAIL_FETCH_IMAP_BODY) &&
                   data->body == NULL && data->bodystructure == NULL) {
                if (data->parts == NULL)
                        data->parts = get_cached_parts(mail);
-               open_mail = TRUE;
+               data->open_mail = TRUE;
                data->parse_header = data->parts == NULL;
                 data->bodystructure_header_want = TRUE;
        } else if (mail->wanted_fields & (MAIL_FETCH_STREAM_HEADER |
                                          MAIL_FETCH_STREAM_BODY))
-               open_mail = TRUE;
+               data->open_mail = TRUE;
 
         index_mail_headers_init_next(mail);
 
-       if ((open_mail || data->parse_header) && !delay_open) {
-               if (mail->mail.get_stream(&mail->mail, NULL, NULL) == NULL)
-                       ret = data->deleted ? 0 : -1;
-               else
-                       ret = 1;
-       } else {
-               if (mail->wanted_fields & MAIL_FETCH_RECEIVED_DATE) {
-                       /* check this only after open_mail() */
-                       data->received_date =
-                               index_mail_get_cached_received_date(mail);
-               }
-               ret = 1;
-       }
-
        if ((mail->wanted_fields & MAIL_FETCH_DATE) &&
            data->sent_date.time == (time_t)-1)
                data->save_sent_date = TRUE;
@@ -645,7 +641,7 @@ int index_mail_next(struct index_mail *mail,
                data->save_envelope = TRUE;
 
        t_pop();
-       return ret;
+       return 0;
 }
 
 void index_mail_deinit(struct index_mail *mail)
index c2e8ac4a62db4754d305b0db288a7e7109d3072d..0b035b3d29cf78d3be9000e56b4a48507f7e40db 100644 (file)
@@ -12,7 +12,6 @@ struct index_mail_data {
        time_t date, received_date;
        uoff_t size;
 
-       enum mail_cache_field cached_fields;
        struct mail_sent_date sent_date;
 
        buffer_t *headers;
@@ -46,6 +45,7 @@ struct index_mail_data {
        unsigned int header_data_cached_partial:1;
        unsigned int header_fully_parsed:1;
        unsigned int header_save:1;
+       unsigned int open_mail:1;
 };
 
 struct index_mail {
@@ -68,9 +68,7 @@ void index_mail_init(struct index_transaction_context *t,
                     struct index_mail *mail,
                     enum mail_fetch_field wanted_fields,
                     const char *const wanted_headers[]);
-int index_mail_next(struct index_mail *mail,
-                   const struct mail_index_record *rec,
-                   uint32_t seq, int delay_open);
+int index_mail_next(struct index_mail *mail, uint32_t seq);
 void index_mail_deinit(struct index_mail *mail);
 
 void index_mail_parse_header_init(struct index_mail *mail,
@@ -80,9 +78,6 @@ int index_mail_parse_header(struct message_part *part,
                            struct index_mail *mail);
 
 void index_mail_cache_transaction_begin(struct index_mail *mail);
-void index_mail_cache_add(struct index_mail *mail, enum mail_cache_field field,
-                         const void *data, size_t size);
-
 int index_mail_parse_headers(struct index_mail *mail);
 
 void index_mail_headers_init(struct index_mail *mail);
index 046a5f1e6ae4dc3edd1aecf94d87966db062a0cb..d7b7b433c616190fe1945606cff92ffd8844a212 100644 (file)
@@ -810,21 +810,15 @@ static int search_match_next(struct index_search_context *ctx)
 struct mail *index_storage_search_next(struct mail_search_context *_ctx)
 {
         struct index_search_context *ctx = (struct index_search_context *)_ctx;
-       const struct mail_index_record *rec;
        int ret;
 
        ret = 0;
        while (ctx->seq1 <= ctx->seq2) {
-               if (mail_index_lookup(ctx->view, ctx->seq1, &rec) < 0) {
+               if (index_mail_next(&ctx->imail, ctx->seq1++) < 0) {
                        ctx->failed = TRUE;
-                       mail_storage_set_index_error(ctx->ibox);
                        return NULL;
                }
 
-               ret = index_mail_next(&ctx->imail, rec, ctx->seq1++, TRUE);
-               if (ret < 0)
-                       break;
-
                t_push();
                ret = search_match_next(ctx);
                t_pop();
index 6fb5429d079c8749565e356b8742b5bbe08c7c34..9060c4943378bb692e5db931aa463faa4492e9e5 100644 (file)
@@ -1,6 +1,7 @@
 /* Copyright (C) 2002-2003 Timo Sirainen */
 
 #include "lib.h"
+#include "buffer.h"
 #include "ioloop.h"
 #include "mail-index.h"
 #include "index-storage.h"
@@ -172,15 +173,17 @@ void index_storage_destroy_unrefed(void)
        destroy_unrefed(TRUE);
 }
 
-static enum mail_cache_field get_cache_fields(const char *fields)
+static void set_cache_fields(const char *fields,
+                            enum mail_cache_decision_type dest[32],
+                            enum mail_cache_decision_type dec)
 {
-       static enum mail_cache_field field_masks[] = {
+       static enum mail_cache_field field_enums[] = {
                MAIL_CACHE_SENT_DATE,
                MAIL_CACHE_RECEIVED_DATE,
                MAIL_CACHE_VIRTUAL_FULL_SIZE,
                MAIL_CACHE_BODY,
                MAIL_CACHE_BODYSTRUCTURE,
-               MAIL_CACHE_MESSAGEPART,
+               MAIL_CACHE_MESSAGEPART
        };
        static const char *field_names[] = {
                "sent_date",
@@ -193,17 +196,15 @@ static enum mail_cache_field get_cache_fields(const char *fields)
        };
 
        const char *const *arr;
-       enum mail_cache_field ret;
        int i;
 
        if (fields == NULL || *fields == '\0')
-               return 0;
+               return;
 
-       ret = 0;
        for (arr = t_strsplit_spaces(fields, " ,"); *arr != NULL; arr++) {
                for (i = 0; field_names[i] != NULL; i++) {
                        if (strcasecmp(field_names[i], *arr) == 0) {
-                               ret |= field_masks[i];
+                               dest[field_enums[i]] = dec;
                                break;
                        }
                }
@@ -212,34 +213,22 @@ static enum mail_cache_field get_cache_fields(const char *fields)
                                *arr);
                }
        }
-
-       return ret;
-}
-
-static enum mail_cache_field get_default_cache_fields(void)
-{
-       static enum mail_cache_field ret = 0;
-       static int ret_set = FALSE;
-
-       if (ret_set)
-               return ret;
-
-       ret = get_cache_fields(getenv("MAIL_CACHE_FIELDS"));
-       ret_set = TRUE;
-       return ret;
 }
 
-static enum mail_cache_field get_never_cache_fields(void)
+static const enum mail_cache_decision_type *get_default_cache_decisions(void)
 {
-       static enum mail_cache_field ret = 0;
-       static int ret_set = FALSE;
-
-       if (ret_set)
-               return ret;
-
-       ret = get_cache_fields(getenv("MAIL_NEVER_CACHE_FIELDS"));
-       ret_set = TRUE;
-       return ret;
+       static enum mail_cache_decision_type dec[32];
+       static int dec_set = FALSE;
+
+       if (dec_set)
+               return dec;
+
+       memset(dec, 0, sizeof(dec));
+       set_cache_fields(getenv("MAIL_CACHE_FIELDS"), dec,
+                        MAIL_CACHE_DECISION_TEMP);
+       set_cache_fields(getenv("MAIL_NEVER_CACHE_FIELDS"), dec,
+                        MAIL_CACHE_DECISION_NO | MAIL_CACHE_DECISION_FORCED);
+       return dec;
 }
 
 void index_storage_lock_notify(struct index_mailbox *ibox,
@@ -339,9 +328,7 @@ index_storage_mailbox_init(struct index_storage *storage, struct mailbox *box,
 
                ibox->cache = mail_index_get_cache(index);
                mail_cache_set_defaults(ibox->cache,
-                                       get_default_cache_fields(),
-                                       get_never_cache_fields());
-
+                                       get_default_cache_decisions());
                ibox->view = mail_index_view_open(index);
                return ibox;
        } while (0);
index 0ba732348b2ed0c38bca3ed355e54983d59ced92..a33252699ae5c120aebb04ea475c918a86f8db97 100644 (file)
@@ -87,6 +87,11 @@ static time_t maildir_mail_get_received_date(struct mail *_mail)
        if (data->received_date != (time_t)-1)
                return data->received_date;
 
+       if (data->open_mail && data->stream == NULL) {
+               /* we're going to open the mail anyway */
+               (void)_mail->get_stream(_mail, NULL, NULL);
+       }
+
        if (data->stream != NULL) {
                fd = i_stream_get_fd(data->stream);
                i_assert(fd != -1);
@@ -103,8 +108,9 @@ static time_t maildir_mail_get_received_date(struct mail *_mail)
        }
 
        data->received_date = st.st_mtime;
-       index_mail_cache_add(mail, MAIL_CACHE_RECEIVED_DATE,
-                            &data->received_date, sizeof(data->received_date));
+       mail_cache_add(mail->trans->cache_trans, mail->data.seq,
+                      MAIL_CACHE_RECEIVED_DATE,
+                      &data->received_date, sizeof(data->received_date));
        return data->received_date;
 }
 
@@ -141,9 +147,9 @@ static uoff_t maildir_mail_get_size(struct mail *_mail)
                }
 
                if (*p == ':' || *p == ',' || *p == '\0') {
-                       index_mail_cache_add(mail, MAIL_CACHE_VIRTUAL_FULL_SIZE,
-                                            &virtual_size,
-                                            sizeof(virtual_size));
+                       mail_cache_add(mail->trans->cache_trans, mail->data.seq,
+                                      MAIL_CACHE_VIRTUAL_FULL_SIZE,
+                                      &virtual_size, sizeof(virtual_size));
                        return virtual_size;
                }
        }
@@ -162,8 +168,10 @@ static struct istream *maildir_mail_get_stream(struct mail *_mail,
        if (data->stream == NULL) {
                data->stream = maildir_open_mail(mail->ibox, mail->mail.uid,
                                                 &deleted);
-               if (data->stream == NULL)
+               if (data->stream == NULL) {
+                       data->deleted = deleted;
                        return NULL;
+               }
        }
 
        return index_mail_init_stream(mail, hdr_size, body_size);
index b3d204233ba8a50581a9ff7c002e902b97f3f0a6..bff3179fc4f780d07148a83ce68b8328f67f122e 100644 (file)
@@ -201,11 +201,7 @@ int maildir_save(struct mailbox_transaction_context *_t,
        t_pop();
 
        if (mail_r != NULL) {
-               const struct mail_index_record *rec;
-
-               if (mail_index_lookup(t->ictx.trans_view, seq, &rec) < 0)
-                       return -1;
-               if (index_mail_next(&ctx->mail, rec, seq, FALSE) <= 0)
+               if (index_mail_next(&ctx->mail, seq) < 0)
                        return -1;
                *mail_r = &ctx->mail.mail;
        }
index b2156180131415168bdc9c2a288ac38fee547ba0..243eea3b8799bc03b13807adc028caffa0a1761e 100644 (file)
@@ -20,6 +20,9 @@ static int mbox_mail_seek(struct index_mail *mail)
        uint64_t offset;
        int ret;
 
+       if (mail->data.deleted)
+               return 0;
+
        if (ibox->mbox_lock_type == F_UNLCK) {
                if (mbox_sync(ibox, FALSE, FALSE, TRUE) < 0)
                        return -1;
@@ -36,7 +39,9 @@ static int mbox_mail_seek(struct index_mail *mail)
        if (ret <= 0) {
                if (ret < 0)
                        mail_storage_set_index_error(ibox);
-               return -1;
+               else
+                       mail->data.deleted = TRUE;
+               return ret;
        }
 
        offset = *((const uint64_t *)data);
@@ -47,7 +52,7 @@ static int mbox_mail_seek(struct index_mail *mail)
                mail_index_mark_corrupted(ibox->index);
                return -1;
        }
-       return 0;
+       return 1;
 }
 
 static const struct mail_full_flags *mbox_mail_get_flags(struct mail *_mail)
@@ -74,7 +79,7 @@ static time_t mbox_mail_get_received_date(struct mail *_mail)
        if (data->received_date != (time_t)-1)
                return data->received_date;
 
-       if (mbox_mail_seek(mail) < 0)
+       if (mbox_mail_seek(mail) <= 0)
                return (time_t)-1;
        data->received_date =
                istream_raw_mbox_get_received_time(mail->ibox->mbox_stream);
@@ -84,9 +89,9 @@ static time_t mbox_mail_get_received_date(struct mail *_mail)
                data->received_date = 0;
        }
 
-       index_mail_cache_add(mail, MAIL_CACHE_RECEIVED_DATE,
-                            &data->received_date,
-                            sizeof(data->received_date));
+       mail_cache_add(mail->trans->cache_trans, mail->data.seq,
+                      MAIL_CACHE_RECEIVED_DATE,
+                      &data->received_date, sizeof(data->received_date));
        return data->received_date;
 }
 
@@ -96,7 +101,7 @@ mbox_mail_get_special(struct mail *_mail, enum mail_fetch_field field)
        struct index_mail *mail = (struct index_mail *)_mail;
 
        if (field == MAIL_FETCH_FROM_ENVELOPE) {
-               if (mbox_mail_seek(mail) < 0)
+               if (mbox_mail_seek(mail) <= 0)
                        return NULL;
 
                return istream_raw_mbox_get_sender(mail->ibox->mbox_stream);
@@ -116,10 +121,9 @@ static struct istream *mbox_mail_get_stream(struct mail *_mail,
        uoff_t offset;
 
        if (data->stream == NULL) {
-               if (mbox_mail_seek(mail) < 0)
+               if (mbox_mail_seek(mail) <= 0)
                        return NULL;
 
-               // FIXME: need to hide the headers
                raw_stream = mail->ibox->mbox_stream;
                offset = istream_raw_mbox_get_header_offset(raw_stream);
                raw_stream = i_stream_create_limit(default_pool, raw_stream,
index d9269caa7a6dfeb877d31ebee42921a3a09af56c..3785b96bb91b32a0afe532710338cc288a30742f 100644 (file)
@@ -344,11 +344,7 @@ int mbox_save(struct mailbox_transaction_context *_t,
        t_pop();
 
        if (mail_r != NULL) {
-               const struct mail_index_record *rec;
-
-               if (mail_index_lookup(t->ictx.trans_view, seq, &rec) < 0)
-                       return -1;
-               if (index_mail_next(&ctx->mail, rec, seq, FALSE) <= 0)
+               if (index_mail_next(&ctx->mail, seq) < 0)
                        return -1;
                *mail_r = &ctx->mail.mail;
        }