]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Cache fixes. Lookups now look into transactions too.
authorTimo Sirainen <tss@iki.fi>
Sat, 10 Jul 2004 11:16:05 +0000 (14:16 +0300)
committerTimo Sirainen <tss@iki.fi>
Sat, 10 Jul 2004 11:16:05 +0000 (14:16 +0300)
--HG--
branch : HEAD

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-index-private.h
src/lib-index/mail-index-transaction.c

index f9a9ecf00411369523f253f4959c11159fe0bd63..df7dae76de78340190a46f8175c01750cd4ceb04 100644 (file)
@@ -139,6 +139,7 @@ mail_cache_get_record(struct mail_cache *cache, uint32_t offset)
        if (cache_rec->size > CACHE_PREFETCH) {
                if (mail_cache_map(cache, offset, cache_rec->size) < 0)
                        return NULL;
+               cache_rec = CACHE_RECORD(cache, offset);
        }
 
        if (offset + cache_rec->size > cache->mmap_length) {
@@ -171,15 +172,56 @@ static int mail_cache_lookup_offset(struct mail_cache_view *view, uint32_t seq,
        return 0;
 }
 
+static int
+mail_cache_foreach_rec(struct mail_cache_view *view,
+                      const struct mail_cache_record *cache_rec,
+                      mail_cache_foreach_callback_t *callback, void *context)
+{
+       size_t pos, next_pos, max_size, data_size;
+       uint32_t field;
+       int ret;
+
+       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);
+               }
+
+               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;
+               }
+
+               ret = callback(view, field, CONST_PTR_OFFSET(cache_rec, pos),
+                              data_size, context);
+               if (ret <= 0)
+                       return ret;
+
+               pos = next_pos;
+       }
+       return 1;
+}
+
 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)
+                       mail_cache_foreach_callback_t *callback, void *context)
 {
        const struct mail_cache_record *cache_rec;
-       size_t pos, next_pos, max_size, data_size;
-       uint32_t offset, field;
+       uint32_t offset;
        int ret;
 
         if (MAIL_CACHE_IS_UNUSABLE(view->cache))
@@ -190,48 +232,21 @@ int mail_cache_foreach(struct mail_cache_view *view, uint32_t seq,
 
        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);
-                       }
-
-                       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;
-                       }
-
-                       ret = callback(view, field,
-                                      CONST_PTR_OFFSET(cache_rec, pos),
-                                      data_size, context);
-                       if (ret <= 0)
-                               return ret;
-
-                       pos = next_pos;
-               }
+               ret = mail_cache_foreach_rec(view, cache_rec,
+                                            callback, context);
+               if (ret <= 0)
+                       return ret;
                cache_rec = mail_cache_get_record(view->cache,
                                                  cache_rec->prev_offset);
        }
 
-       if (view->transaction != NULL) {
-               // FIXME: update
+       if (view->trans_seq1 <= seq && view->trans_seq2 >= seq &&
+           mail_cache_transaction_lookup(view->transaction, seq, &offset)) {
+               cache_rec = mail_cache_get_record(view->cache, offset);
+               if (cache_rec != NULL) {
+                       return mail_cache_foreach_rec(view, cache_rec,
+                                                     callback, context);
+               }
        }
        return 1;
 }
index 3481f43c7941274c62fee91883a5b542f86cc7f2..b89e0414af157a33dd2840230e7d5dc402067150 100644 (file)
@@ -102,10 +102,17 @@ struct mail_cache_view {
        struct mail_index_view *view;
 
        struct mail_cache_transaction_ctx *transaction;
+       uint32_t trans_seq1, trans_seq2;
+
        char cached_exists[32];
        uint32_t cached_exists_seq;
 };
 
+typedef int mail_cache_foreach_callback_t(struct mail_cache_view *view,
+                                         enum mail_cache_field field,
+                                         const void *data, size_t data_size,
+                                         void *context);
+
 extern unsigned int mail_cache_field_sizes[32];
 extern enum mail_cache_field mail_cache_header_fields[MAIL_CACHE_HEADERS_COUNT];
 
@@ -126,14 +133,14 @@ struct mail_cache_record *
 mail_cache_get_record(struct mail_cache *cache, uint32_t offset);
 
 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);
+                      mail_cache_foreach_callback_t *callback, void *context);
 
 int mail_cache_transaction_commit(struct mail_cache_transaction_ctx *ctx);
 void mail_cache_transaction_rollback(struct mail_cache_transaction_ctx *ctx);
 
+int mail_cache_transaction_lookup(struct mail_cache_transaction_ctx *ctx,
+                                 uint32_t seq, uint32_t *offset_r);
+
 int mail_cache_map(struct mail_cache *cache, size_t offset, size_t size);
 void mail_cache_file_close(struct mail_cache *cache);
 int mail_cache_reopen(struct mail_cache *cache);
index 40265e10200e04f03a039af067e68c2c5904d561..a9629dcaa63cda32f377c349762ed7c1345dd475 100644 (file)
@@ -27,9 +27,6 @@ struct mail_cache_transaction_ctx {
        uint32_t reserved_space_offset, reserved_space;
        uint32_t last_grow_size;
 
-       uint32_t first_seq, last_seq;
-       enum mail_cache_field fields[32];
-
        unsigned int changes:1;
 };
 
@@ -65,6 +62,7 @@ mail_cache_get_transaction(struct mail_cache_view *view,
 static void mail_cache_transaction_free(struct mail_cache_transaction_ctx *ctx)
 {
        ctx->view->transaction = NULL;
+       ctx->view->trans_seq1 = ctx->view->trans_seq2 = 0;
 
        buffer_free(ctx->cache_data);
        buffer_free(ctx->cache_data_seq);
@@ -489,21 +487,24 @@ void mail_cache_transaction_rollback(struct mail_cache_transaction_ctx *ctx)
        size_t size;
        unsigned int i;
 
-       mail_cache_transaction_free_space(ctx);
-
-       buf = buffer_get_data(ctx->reservations, &size);
-       i_assert(size % sizeof(uint32_t)*2 == 0);
-       size /= sizeof(*buf);
+       if (mail_cache_lock(cache) > 0) {
+               mail_cache_transaction_free_space(ctx);
 
-       if (size > 0) {
-               /* free flushed data as well. do it from end to beginning so
-                  we have a better chance of updating used_file_size instead
-                  of adding holes */
-               do {
-                       size -= 2;
-                       mail_cache_free_space(ctx->cache, buf[size],
-                                             buf[size+1]);
-               } while (size > 0);
+               buf = buffer_get_data(ctx->reservations, &size);
+               i_assert(size % sizeof(uint32_t)*2 == 0);
+               size /= sizeof(*buf);
+
+               if (size > 0) {
+                       /* free flushed data as well. do it from end to
+                          beginning so we have a better chance of updating
+                          used_file_size instead of adding holes */
+                       do {
+                               size -= 2;
+                               mail_cache_free_space(ctx->cache, buf[size],
+                                                     buf[size+1]);
+                       } while (size > 0);
+               }
+               mail_cache_unlock(cache);
        }
 
        /* make sure we don't cache the headers */
@@ -622,12 +623,10 @@ void mail_cache_add(struct mail_cache_transaction_ctx *ctx, uint32_t seq,
 
                /* remember roughly what we have modified, so cache lookups can
                   look into transactions to see changes. */
-               if (seq < ctx->first_seq || ctx->first_seq == 0)
-                       ctx->first_seq = seq;
-               if (seq > ctx->last_seq)
-                       ctx->last_seq = seq;
-               ctx->view->cached_exists[field] = TRUE;
-               ctx->fields[field] = TRUE;
+               if (seq < ctx->view->trans_seq1 || ctx->view->trans_seq1 == 0)
+                       ctx->view->trans_seq1 = seq;
+               if (seq > ctx->view->trans_seq2)
+                       ctx->view->trans_seq2 = seq;
        }
 
        full_size = (data_size + 3) & ~3;
@@ -658,6 +657,13 @@ int mail_cache_update_record_flags(struct mail_cache_view *view, uint32_t seq,
        return -1;
 }
 
+int mail_cache_transaction_lookup(struct mail_cache_transaction_ctx *ctx,
+                                 uint32_t seq, uint32_t *offset_r)
+{
+       return mail_index_update_cache_lookup(ctx->trans, seq, offset_r);
+}
+
+
 int mail_cache_link(struct mail_cache *cache, uint32_t old_offset,
                    uint32_t new_offset)
 {
index cbdb340d02187f30cfe9a8f9d538bf224ebda59a..83f32301d38562b1821d989e07d1d9c95da10f8f 100644 (file)
@@ -136,6 +136,8 @@ void mail_index_reset_cache(struct mail_index_transaction *t,
 void mail_index_update_cache(struct mail_index_transaction *t, uint32_t seq,
                             uint32_t file_seq, uint32_t offset,
                             uint32_t *old_offset_r);
+int mail_index_update_cache_lookup(struct mail_index_transaction *t,
+                                  uint32_t seq, uint32_t *offset_r);
 
 int mail_index_fix_header(struct mail_index *index, struct mail_index_map *map,
                          struct mail_index_header *hdr, const char **error_r);
index 05cc08e381d230498308fd56cf7bf08f29e02eb2..a3ce01ba41c70321738b397afb93f2155aed67d3 100644 (file)
@@ -509,20 +509,18 @@ static void mail_index_transaction_add_last(struct mail_index_transaction *t)
                      &update, sizeof(update));
 }
 
-static int mail_index_update_seq_buffer(buffer_t **buffer, uint32_t seq,
-                                       const void *record, size_t record_size,
-                                       void *old_record)
+static int
+mail_index_seq_buffer_lookup(buffer_t *buffer, uint32_t seq,
+                            size_t record_size, size_t *pos_r)
 {
        unsigned int idx, left_idx, right_idx;
        void *data;
        uint32_t full_record_size, *seq_p;
        size_t size;
 
-       full_record_size = record_size + sizeof(uint32_t);
+       full_record_size = record_size + sizeof(seq);
 
-       if (*buffer == NULL)
-               *buffer = buffer_create_dynamic(default_pool, 1024, (size_t)-1);
-       data = buffer_get_modifyable_data(*buffer, &size);
+       data = buffer_get_modifyable_data(buffer, &size);
 
        /* we're probably appending it, check */
        if (size == 0)
@@ -540,29 +538,48 @@ static int mail_index_update_seq_buffer(buffer_t **buffer, uint32_t seq,
                        else if (*seq_p > seq)
                                right_idx = idx;
                        else {
-                               /* already there, update */
-                               if (old_record != NULL) {
-                                       memcpy(old_record, seq_p+1,
-                                              record_size);
-                               }
-                               memcpy(seq_p+1, record, record_size);
+                               *pos_r = idx * full_record_size;
                                return TRUE;
                        }
                }
        }
 
-       idx *= full_record_size;
-       if (idx != size) {
-               buffer_copy(*buffer, idx + full_record_size,
-                           *buffer, idx, (size_t)-1);
-       }
-       seq_p = buffer_get_space_unsafe(*buffer, idx, full_record_size);
-
-       *seq_p = seq;
-       memcpy(seq_p+1, record, record_size);
+       *pos_r = idx * full_record_size;
        return FALSE;
 }
 
+static int mail_index_update_seq_buffer(buffer_t **buffer, uint32_t seq,
+                                       const void *record, size_t record_size,
+                                       void *old_record)
+{
+       void *p;
+       size_t pos;
+
+       if (*buffer == NULL) {
+               *buffer = buffer_create_dynamic(default_pool, 1024, (size_t)-1);
+               buffer_append(*buffer, &seq, sizeof(seq));
+               buffer_append(*buffer, record, record_size);
+               return FALSE;
+       }
+
+       if (mail_index_seq_buffer_lookup(*buffer, seq, record_size, &pos)) {
+               /* already there, update */
+               p = buffer_get_space_unsafe(*buffer, pos + sizeof(seq),
+                                           record_size);
+               if (old_record != NULL)
+                       memcpy(old_record, p, record_size);
+               memcpy(p, record, record_size);
+               return TRUE;
+       } else {
+               /* insert */
+               buffer_copy(*buffer, pos + sizeof(seq) + record_size,
+                           *buffer, pos, (size_t)-1);
+               buffer_write(*buffer, pos, &seq, sizeof(seq));
+               buffer_write(*buffer, pos + sizeof(seq), record, record_size);
+               return FALSE;
+       }
+}
+
 static void
 mail_index_transaction_reset_cache_updates(struct mail_index_transaction *t)
 {
@@ -614,6 +631,25 @@ void mail_index_update_cache(struct mail_index_transaction *t, uint32_t seq,
        }
 }
 
+int mail_index_update_cache_lookup(struct mail_index_transaction *t,
+                                  uint32_t seq, uint32_t *offset_r)
+{
+       const void *p;
+       size_t pos;
+
+       if (t->cache_updates == NULL)
+               return FALSE;
+
+       if (!mail_index_seq_buffer_lookup(t->cache_updates, seq,
+                                         sizeof(*offset_r), &pos))
+               return FALSE;
+
+       p = buffer_get_data(t->cache_updates, NULL);
+       memcpy(offset_r, CONST_PTR_OFFSET(p, pos + sizeof(*offset_r)),
+              sizeof(*offset_r));
+       return TRUE;
+}
+
 void mail_index_update_extra_rec(struct mail_index_transaction *t,
                                 uint32_t seq, uint32_t data_id,
                                 const void *data)