]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-index: Added MAIL_INDEX_OPEN_FLAG_SAVEONLY to do only minimal reads from cache...
authorTimo Sirainen <tss@iki.fi>
Thu, 18 Oct 2012 02:22:36 +0000 (05:22 +0300)
committerTimo Sirainen <tss@iki.fi>
Thu, 18 Oct 2012 02:22:36 +0000 (05:22 +0300)
src/lib-index/mail-cache-compress.c
src/lib-index/mail-cache-private.h
src/lib-index/mail-cache.c
src/lib-index/mail-index.h

index cc8ec9cb606b08be02ed87f2062f495e9f02a89d..e3bdf7cdac3c4a3f0a262f0e63ac27f83204eff6 100644 (file)
@@ -461,6 +461,9 @@ int mail_cache_compress(struct mail_cache *cache,
        if (MAIL_INDEX_IS_IN_MEMORY(cache->index) || cache->index->readonly)
                return 0;
 
+       /* compression isn't very efficient with small read()s */
+       cache->map_with_read = FALSE;
+
        if (cache->index->lock_method == FILE_LOCK_METHOD_DOTLOCK) {
                /* we're using dotlocking, cache file creation itself creates
                   the dotlock file we need. */
@@ -495,5 +498,6 @@ int mail_cache_compress(struct mail_cache *cache,
 bool mail_cache_need_compress(struct mail_cache *cache)
 {
        return cache->need_compress_file_seq != 0 &&
+               (cache->index->flags & MAIL_INDEX_OPEN_FLAG_SAVEONLY) == 0 &&
                !cache->index->readonly;
 }
index 2b96cb55b80abd0b9900fd955fa92e103158b30d..46feda40424cd6ac787610d4a98f5123d6910bf2 100644 (file)
@@ -130,9 +130,14 @@ struct mail_cache {
        ino_t st_ino;
        dev_t st_dev;
 
-       void *mmap_base;
        size_t mmap_length;
+       /* a) mmaping the whole file */
+       void *mmap_base;
+       /* b) using file cache */
        struct file_cache *file_cache;
+       /* c) using small read() calls with MAIL_INDEX_OPEN_FLAG_SAVEONLY */
+       uoff_t read_offset;
+       buffer_t *read_buf;
        /* mail_cache_map() increases this always. */
        unsigned int remap_counter;
 
@@ -169,6 +174,7 @@ struct mail_cache {
        unsigned int hdr_modified:1;
        unsigned int field_header_write_pending:1;
        unsigned int compressing:1;
+       unsigned int map_with_read:1;
 };
 
 struct mail_cache_loop_track {
index 1ea3d1402f12893d691215749bacd65266466ad6..8505f1225d159840f6deee7e53ae732f6460acc3 100644 (file)
@@ -7,6 +7,7 @@
 #include "nfs-workarounds.h"
 #include "file-cache.h"
 #include "mmap-util.h"
+#include "read-full.h"
 #include "write-full.h"
 #include "mail-cache-private.h"
 
@@ -264,17 +265,87 @@ static bool mail_cache_verify_header(struct mail_cache *cache,
        return TRUE;
 }
 
+static int
+mail_cache_map_finish(struct mail_cache *cache, uoff_t offset, size_t size,
+                     const void *data, bool copy_hdr)
+{
+       if (offset == 0) {
+               const struct mail_cache_header *hdr = data;
+
+               if (!mail_cache_verify_header(cache, hdr)) {
+                       cache->need_compress_file_seq =
+                               !MAIL_CACHE_IS_UNUSABLE(cache) &&
+                               cache->hdr->file_seq != 0 ?
+                               cache->hdr->file_seq : 0;
+                       return -1;
+               }
+               if (!copy_hdr)
+                       cache->hdr = data;
+               else {
+                       memcpy(&cache->hdr_ro_copy, data,
+                              sizeof(cache->hdr_ro_copy));
+                       cache->hdr = &cache->hdr_ro_copy;
+               }
+               mail_cache_update_need_compress(cache);
+       }
+
+       if (offset + size > cache->mmap_length)
+               return 0;
+       return 1;
+}
+
+static int
+mail_cache_map_with_read(struct mail_cache *cache, size_t offset, size_t size,
+                        const void **data_r)
+{
+       void *data;
+       ssize_t ret;
+
+       if (cache->read_buf == NULL) {
+               cache->read_buf =
+                       buffer_create_dynamic(default_pool, size);
+       } else if (cache->read_offset <= offset &&
+                  cache->read_offset + cache->read_buf->used >= offset+size) {
+               /* already mapped */
+               *data_r = CONST_PTR_OFFSET(cache->mmap_base,
+                                          offset - cache->read_offset);
+               return mail_cache_map_finish(cache, offset, size, *data_r, TRUE);
+       } else {
+               buffer_set_used_size(cache->read_buf, 0);
+       }
+       data = buffer_append_space_unsafe(cache->read_buf, size);
+       ret = pread(cache->fd, data, size, offset);
+       if (ret < 0) {
+               if (errno != ESTALE)
+                       mail_cache_set_syscall_error(cache, "read()");
+
+               buffer_set_used_size(cache->read_buf, 0);
+               cache->hdr = NULL;
+               cache->mmap_length = 0;
+               return -1;
+       }
+       buffer_set_used_size(cache->read_buf, ret);
+
+       cache->read_offset = offset;
+       cache->mmap_length = offset + size;
+
+       *data_r = data;
+       return mail_cache_map_finish(cache, offset, size, data, TRUE);
+}
+
 int mail_cache_map(struct mail_cache *cache, size_t offset, size_t size,
                   const void **data_r)
 {
        const void *data;
        ssize_t ret;
 
-       cache->remap_counter++;
-
        if (size == 0)
                size = sizeof(struct mail_cache_header);
 
+       cache->remap_counter++;
+       if (cache->map_with_read)
+               return mail_cache_map_with_read(cache, offset, size, data_r);
+
        if (cache->file_cache != NULL) {
                cache->hdr = NULL;
 
@@ -294,28 +365,9 @@ int mail_cache_map(struct mail_cache *cache, size_t offset, size_t size,
 
                data = file_cache_get_map(cache->file_cache,
                                          &cache->mmap_length);
-
-               if (offset == 0) {
-                       if (!mail_cache_verify_header(cache, data)) {
-                               cache->need_compress_file_seq =
-                                       !MAIL_CACHE_IS_UNUSABLE(cache) &&
-                                       cache->hdr->file_seq != 0 ?
-                                       cache->hdr->file_seq : 0;
-                               return -1;
-                       }
-                       memcpy(&cache->hdr_ro_copy, data,
-                              sizeof(cache->hdr_ro_copy));
-               }
-               cache->hdr = &cache->hdr_ro_copy;
-               if (offset == 0)
-                       mail_cache_update_need_compress(cache);
-
-               if (offset > cache->mmap_length) {
-                       *data_r = NULL;
-                       return 0;
-               }
-               *data_r = CONST_PTR_OFFSET(data, offset);
-               return offset + size > cache->mmap_length ? 0 : 1;
+               *data_r = offset > cache->mmap_length ? NULL :
+                       CONST_PTR_OFFSET(data, offset);
+               return mail_cache_map_finish(cache, offset, size, *data_r, TRUE);
        }
 
        if (offset < cache->mmap_length &&
@@ -348,24 +400,9 @@ int mail_cache_map(struct mail_cache *cache, size_t offset, size_t size,
                mail_cache_set_syscall_error(cache, "mmap()");
                return -1;
        }
-
-       if (!mail_cache_verify_header(cache, cache->mmap_base)) {
-               cache->need_compress_file_seq =
-                       !MAIL_CACHE_IS_UNUSABLE(cache) &&
-                       cache->hdr->file_seq != 0 ?
-                       cache->hdr->file_seq : 0;
-               return -1;
-       }
-
-       cache->hdr = cache->mmap_base;
-       if (offset == 0)
-               mail_cache_update_need_compress(cache);
-       if (offset > cache->mmap_length) {
-               *data_r = NULL;
-               return 0;
-       }
-       *data_r = CONST_PTR_OFFSET(cache->mmap_base, offset);
-       return offset + size > cache->mmap_length ? 0 : 1;
+       *data_r = offset > cache->mmap_length ? NULL :
+               CONST_PTR_OFFSET(cache->mmap_base, offset);
+       return mail_cache_map_finish(cache, offset, size, *data_r, FALSE);
 }
 
 static int mail_cache_try_open(struct mail_cache *cache)
@@ -437,6 +474,8 @@ static struct mail_cache *mail_cache_alloc(struct mail_index *index)
        if (!MAIL_INDEX_IS_IN_MEMORY(index) &&
            (index->flags & MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE) != 0)
                cache->file_cache = file_cache_new(-1);
+       cache->map_with_read =
+               (cache->index->flags & MAIL_INDEX_OPEN_FLAG_SAVEONLY) != 0;
 
        cache->ext_id =
                mail_index_ext_register(index, "cache", 0,
index 89723cef89a1d9061fd82ced68d71bc276eae393..1082bb7fbe160729cc54a093172e2b464a81c596 100644 (file)
@@ -27,7 +27,10 @@ enum mail_index_open_flags {
        MAIL_INDEX_OPEN_FLAG_KEEP_BACKUPS       = 0x100,
        /* If we run out of disk space, fail modifications instead of moving
           indexes to memory. */
-       MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY    = 0x200
+       MAIL_INDEX_OPEN_FLAG_NEVER_IN_MEMORY    = 0x200,
+       /* We're only going to save new messages to the index.
+          Avoid unnecessary reads. */
+       MAIL_INDEX_OPEN_FLAG_SAVEONLY           = 0x400
 };
 
 enum mail_index_header_compat_flags {