]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
Beginnings of getting cache file working again. Easy to break currently, but
authorTimo Sirainen <tss@iki.fi>
Sun, 20 Jun 2004 08:05:41 +0000 (11:05 +0300)
committerTimo Sirainen <tss@iki.fi>
Sun, 20 Jun 2004 08:05:41 +0000 (11:05 +0300)
basics seem to work.

--HG--
branch : HEAD

src/lib-index/mail-cache-compress.c
src/lib-index/mail-cache-lookup.c
src/lib-index/mail-cache-old.c [deleted file]
src/lib-index/mail-cache-private.h
src/lib-index/mail-cache-transaction.c
src/lib-index/mail-cache.c
src/lib-index/mail-cache.h
src/lib-index/mail-index.c
src/lib-storage/index/index-mail.c
src/lib-storage/index/index-storage.c
src/lib-storage/index/index-transaction.c

index 419c5c809144549df59c61ff87a6b6d962f6ba15..41c4bce54af5960e0957af9845a2ae60ec72cc8c 100644 (file)
@@ -241,7 +241,7 @@ int mail_cache_compress(struct mail_cache *cache)
                          MAIL_INDEX_HDR_FLAG_COMPRESS_CACHE);
        }
 
-       if (!mail_cache_unlock(cache))
+       if (mail_cache_unlock(cache) < 0)
                ret = FALSE;
 
        return ret;
index 324b9f2c254cc524dbe8e3ffee0d31f9f3ae870a..a66f281a635b5242c7a5ac811170ac1172af9510 100644 (file)
@@ -5,7 +5,6 @@
 #include "byteorder.h"
 #include "mail-cache-private.h"
 
-#if 0
 const char *
 mail_cache_get_header_fields_str(struct mail_cache *cache, unsigned int idx)
 {
@@ -17,7 +16,7 @@ mail_cache_get_header_fields_str(struct mail_cache *cache, unsigned int idx)
        if (offset == 0)
                return NULL;
 
-       if (!mmap_update(cache, offset, 1024))
+       if (mail_cache_mmap_update(cache, offset, 1024) < 0)
                return NULL;
 
        if (offset + sizeof(data_size) > cache->mmap_length) {
@@ -37,7 +36,7 @@ mail_cache_get_header_fields_str(struct mail_cache *cache, unsigned int idx)
                return NULL;
        }
 
-       if (!mmap_update(cache, offset, data_size))
+       if (mail_cache_mmap_update(cache, offset, data_size) < 0)
                return NULL;
 
        if (offset + data_size > cache->mmap_length) {
@@ -107,17 +106,20 @@ const char *const *mail_cache_get_header_fields(struct mail_cache_view *view,
 }
 
 struct mail_cache_record *
-mail_cache_get_record(struct mail_cache *cache, uint32_t offset)
+mail_cache_get_record(struct mail_cache *cache, uint32_t offset,
+                     int index_offset)
 {
 #define CACHE_PREFETCH 1024
        struct mail_cache_record *cache_rec;
        size_t size;
 
-       offset = mail_cache_offset_to_uint32(offset);
+       if (!index_offset)
+               offset = mail_cache_offset_to_uint32(offset);
        if (offset == 0)
                return NULL;
 
-       if (!mmap_update(cache, offset, sizeof(*cache_rec) + CACHE_PREFETCH))
+       if (mail_cache_mmap_update(cache, offset,
+                                  sizeof(*cache_rec) + CACHE_PREFETCH) < 0)
                return NULL;
 
        if (offset + sizeof(*cache_rec) > cache->mmap_length) {
@@ -132,7 +134,7 @@ mail_cache_get_record(struct mail_cache *cache, uint32_t offset)
                return NULL;
        }
        if (size > CACHE_PREFETCH) {
-               if (!mmap_update(cache, offset, size))
+               if (mail_cache_mmap_update(cache, offset, size) < 0)
                        return NULL;
        }
 
@@ -149,7 +151,7 @@ mail_cache_get_next_record(struct mail_cache *cache,
 {
        struct mail_cache_record *next;
 
-       next = mail_cache_get_record(cache, rec->next_offset);
+       next = mail_cache_get_record(cache, rec->next_offset, FALSE);
        if (next != NULL && next <= rec) {
                mail_cache_set_corrupted(cache, "next_offset points backwards");
                return NULL;
@@ -165,11 +167,13 @@ mail_cache_lookup(struct mail_cache_view *view, uint32_t seq,
 
        if (mail_cache_transaction_autocommit(view, seq, fields) < 0)
                return NULL;
-       // FIXME: check cache_offset in transaction
-       if (mail_index_lookup_latest(view->view, seq, &rec) < 0)
+       /* FIXME: check cache_offset in transaction
+          FIXME: if rec doesn't point to header record, the file seq may
+          be different and the offset wrong */
+       if (mail_index_lookup(view->view, seq, &rec) < 0)
                return NULL;
 
-       return mail_cache_get_record(view->cache, rec->cache_offset);
+       return mail_cache_get_record(view->cache, rec->cache_offset, TRUE);
 }
 
 enum mail_cache_field
@@ -318,5 +322,10 @@ int mail_cache_copy_fixed_field(struct mail_cache_view *view, uint32_t seq,
        memcpy(buffer, data, buffer_size);
        return TRUE;
 }
-#else
-#endif
+
+enum mail_cache_record_flag
+mail_cache_get_record_flags(struct mail_cache_view *view, uint32_t seq)
+{
+       // FIXME:
+       return 0;
+}
diff --git a/src/lib-index/mail-cache-old.c b/src/lib-index/mail-cache-old.c
deleted file mode 100644 (file)
index 1e9fd8f..0000000
+++ /dev/null
@@ -1,935 +0,0 @@
-static const char *
-mail_cache_get_header_fields_str(struct mail_cache *cache, unsigned int idx);
-static int mail_cache_write(struct mail_cache_transaction_ctx *ctx);
-static struct mail_cache_record *
-mail_cache_lookup(struct mail_cache *cache,
-                 const struct mail_index_record *rec,
-                 enum mail_cache_field fields);
-
-static void mail_cache_file_close(struct mail_cache *cache)
-{
-       if (cache->mmap_base != NULL) {
-               if (munmap(cache->mmap_base, cache->mmap_length) < 0)
-                       mail_cache_set_syscall_error(cache, "munmap()");
-       }
-
-       cache->mmap_base = NULL;
-       cache->hdr = NULL;
-       cache->mmap_length = 0;
-
-       if (cache->fd != -1) {
-               if (close(cache->fd) < 0)
-                       mail_cache_set_syscall_error(cache, "close()");
-               cache->fd = -1;
-       }
-}
-
-static int mail_cache_file_reopen(struct mail_cache *cache)
-{
-       int fd;
-
-       fd = open(cache->filepath, O_RDWR);
-       if (fd == -1) {
-               mail_cache_set_syscall_error(cache, "open()");
-               return -1;
-       }
-
-       mail_cache_file_close(cache);
-
-       cache->fd = fd;
-       return 0;
-}
-
-static int mmap_verify_header(struct mail_cache *cache)
-{
-       struct mail_cache_header *hdr;
-
-       /* check that the header is still ok */
-       if (cache->mmap_length < sizeof(struct mail_cache_header)) {
-               mail_cache_set_corrupted(cache, "File too small");
-               return 0;
-       }
-       cache->hdr = hdr = cache->mmap_base;
-
-       if (cache->hdr->indexid != cache->index->indexid) {
-               /* index id changed */
-               if (cache->hdr->indexid != 0)
-                       mail_cache_set_corrupted(cache, "indexid changed");
-               return 0;
-       }
-
-       if (cache->trans_ctx != NULL) {
-               /* we've updated used_file_size, do nothing */
-               return 1;
-       }
-
-       cache->used_file_size = nbo_to_uint32(hdr->used_file_size);
-
-       /* only check the header if we're locked */
-       if (cache->locks == 0)
-               return 1;
-
-       if (cache->used_file_size < sizeof(struct mail_cache_header)) {
-               mail_cache_set_corrupted(cache, "used_file_size too small");
-               return 0;
-       }
-       if ((cache->used_file_size % sizeof(uint32_t)) != 0) {
-               mail_cache_set_corrupted(cache, "used_file_size not aligned");
-               return 0;
-       }
-
-       if (cache->used_file_size > cache->mmap_length) {
-               /* maybe a crash truncated the file - just fix it */
-               hdr->used_file_size = uint32_to_nbo(cache->mmap_length & ~3);
-               if (msync(cache->mmap_base, sizeof(*hdr), MS_SYNC) < 0) {
-                       mail_cache_set_syscall_error(cache, "msync()");
-                       return -1;
-               }
-       }
-       return 1;
-}
-
-static int mmap_update_nocheck(struct mail_cache *cache,
-                              size_t offset, size_t size)
-{
-       struct stat st;
-
-       /* if sequence has changed, the file has to be reopened.
-          note that if main index isn't locked, it may change again */
-       if (cache->hdr->file_seq != cache->index->hdr->cache_file_seq &&
-           cache->mmap_base != NULL) {
-               if (!mail_cache_file_reopen(cache))
-                       return -1;
-       }
-
-       if (offset < cache->mmap_length &&
-           size <= cache->mmap_length - offset &&
-           !cache->mmap_refresh) {
-               /* already mapped */
-               if (size != 0 || cache->anon_mmap)
-                       return 1;
-
-               /* requesting the whole file - see if we need to
-                  re-mmap */
-               if (fstat(cache->fd, &st) < 0) {
-                       mail_cache_set_syscall_error(cache, "fstat()");
-                       return -1;
-               }
-               if ((uoff_t)st.st_size == cache->mmap_length)
-                       return 1;
-       }
-       cache->mmap_refresh = FALSE;
-
-       if (cache->anon_mmap)
-               return 1;
-
-       if (cache->mmap_base != NULL) {
-               if (cache->locks != 0) {
-                       /* in the middle of transaction - write the changes */
-                       if (msync(cache->mmap_base, cache->mmap_length,
-                                 MS_SYNC) < 0) {
-                               mail_cache_set_syscall_error(cache, "msync()");
-                               return -1;
-                       }
-               }
-
-               if (munmap(cache->mmap_base, cache->mmap_length) < 0)
-                       mail_cache_set_syscall_error(cache, "munmap()");
-       }
-
-       i_assert(cache->fd != -1);
-
-       /* map the whole file */
-       cache->hdr = NULL;
-       cache->mmap_length = 0;
-
-       cache->mmap_base = mmap_rw_file(cache->fd, &cache->mmap_length);
-       if (cache->mmap_base == MAP_FAILED) {
-               cache->mmap_base = NULL;
-               mail_cache_set_syscall_error(cache, "mmap()");
-               return -1;
-       }
-
-       /* re-mmaped, check header */
-       return 0;
-}
-
-static int mmap_update(struct mail_cache *cache, size_t offset, size_t size)
-{
-       int synced, ret;
-
-       for (synced = FALSE;; synced = TRUE) {
-               ret = mmap_update_nocheck(cache, offset, size);
-               if (ret > 0)
-                       return TRUE;
-               if (ret < 0)
-                       return FALSE;
-
-               if (!mmap_verify_header(cache))
-                       return FALSE;
-
-               /* see if cache file was rebuilt - do it only once to avoid
-                  infinite looping */
-               if (cache->hdr->sync_id == cache->index->cache_sync_id ||
-                   synced)
-                       break;
-
-               if (!mail_cache_file_reopen(cache))
-                       return FALSE;
-       }
-       return TRUE;
-}
-
-static int mail_cache_open_and_verify(struct mail_cache *cache, int silent)
-{
-       struct stat st;
-
-       mail_cache_file_close(cache);
-
-       cache->fd = open(cache->filepath, O_RDWR);
-       if (cache->fd == -1) {
-               if (errno == ENOENT)
-                       return 0;
-
-               mail_cache_set_syscall_error(cache, "open()");
-               return -1;
-       }
-
-       if (fstat(cache->fd, &st) < 0) {
-               mail_cache_set_syscall_error(cache, "fstat()");
-               return -1;
-       }
-
-       if (st.st_size < sizeof(struct mail_cache_header))
-               return 0;
-
-       cache->mmap_refresh = TRUE;
-       if (mmap_update_nocheck(cache, 0, sizeof(struct mail_cache_header)) < 0)
-               return -1;
-
-       /* verify that this really is the cache for wanted index */
-       cache->silent = silent;
-       if (!mmap_verify_header(cache)) {
-               cache->silent = FALSE;
-               return 0;
-       }
-
-       cache->silent = FALSE;
-       return 1;
-}
-
-static int mail_cache_open_or_create_file(struct mail_cache *cache,
-                                         struct mail_cache_header *hdr)
-{
-       int ret, fd;
-
-       cache->filepath = i_strconcat(cache->index->filepath,
-                                     MAIL_CACHE_FILE_PREFIX, NULL);
-
-       ret = mail_cache_open_and_verify(cache, FALSE);
-       if (ret != 0)
-               return ret > 0;
-
-       /* we'll have to clear cache_offsets which requires exclusive lock */
-       if (!mail_index_set_lock(cache->index, MAIL_LOCK_EXCLUSIVE))
-               return FALSE;
-
-       /* maybe a rebuild.. */
-       fd = file_dotlock_open(cache->filepath, NULL, MAIL_CACHE_LOCK_TIMEOUT,
-                              MAIL_CACHE_LOCK_CHANGE_TIMEOUT,
-                              MAIL_CACHE_LOCK_IMMEDIATE_TIMEOUT, NULL, NULL);
-       if (fd == -1) {
-               mail_cache_set_syscall_error(cache, "file_dotlock_open()");
-               return FALSE;
-       }
-
-       /* see if someone else just created the cache file */
-       ret = mail_cache_open_and_verify(cache, TRUE);
-       if (ret != 0) {
-               (void)file_dotlock_delete(cache->filepath, fd);
-               return ret > 0;
-       }
-
-       /* rebuild then */
-       if (write_full(fd, hdr, sizeof(*hdr)) < 0) {
-               mail_cache_set_syscall_error(cache, "write_full()");
-               (void)file_dotlock_delete(cache->filepath, fd);
-               return FALSE;
-       }
-       if (file_set_size(fd, MAIL_CACHE_INITIAL_SIZE) < 0) {
-               mail_cache_set_syscall_error(cache, "file_set_size()");
-               (void)file_dotlock_delete(cache->filepath, fd);
-               return FALSE;
-       }
-
-       if (cache->index->hdr.cache_file_seq != 0) {
-               // FIXME: recreate index file with cache_offsets cleared
-       }
-
-       mail_cache_file_close(cache);
-       cache->fd = dup(fd);
-
-       if (file_dotlock_replace(cache->filepath, fd, FALSE) < 0) {
-               mail_cache_set_syscall_error(cache, "file_dotlock_replace()");
-               return FALSE;
-       }
-
-       if (!mmap_update(cache, 0, sizeof(struct mail_cache_header)))
-               return FALSE;
-
-       return TRUE;
-}
-
-int mail_cache_open_or_create(struct mail_index *index)
-{
-        struct mail_cache_header hdr;
-       struct mail_cache *cache;
-
-       memset(&hdr, 0, sizeof(hdr));
-       hdr.indexid = index->indexid;
-       hdr.sync_id = index->hdr->cache_file_seq; // FIXME
-       hdr.used_file_size = uint32_to_nbo(sizeof(hdr));
-
-       cache = i_new(struct mail_cache, 1);
-       cache->index = index;
-       cache->fd = -1;
-        cache->split_header_pool = pool_alloconly_create("Headers", 512);
-
-       index->cache = cache;
-
-       /* we'll do anon-mmaping only if initially requested. if we fail
-          because of out of disk space, we'll just let the main index code
-          know it and fail. */
-       if (!mail_cache_open_or_create_file(cache, &hdr)) {
-               mail_cache_free(cache);
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
-void mail_cache_free(struct mail_cache *cache)
-{
-       i_assert(cache->trans_ctx == NULL);
-
-       cache->index->cache = NULL;
-
-       mail_cache_file_close(cache);
-
-       pool_unref(cache->split_header_pool);
-       i_free(cache->filepath);
-       i_free(cache);
-}
-
-void mail_cache_set_defaults(struct mail_cache *cache,
-                            enum mail_cache_field default_cache_fields,
-                            enum mail_cache_field never_cache_fields)
-{
-       cache->default_cache_fields = default_cache_fields;
-       cache->never_cache_fields = never_cache_fields;
-}
-
-int mail_cache_reset(struct mail_cache *cache)
-{
-       struct mail_cache_header hdr;
-       int ret, fd;
-
-       i_assert(cache->index->lock_type == MAIL_LOCK_EXCLUSIVE);
-
-       memset(&hdr, 0, sizeof(hdr));
-       hdr.indexid = cache->index->indexid;
-       hdr.sync_id = cache->sync_id = cache->index->cache_sync_id =
-               ++cache->index->hdr->cache_sync_id;
-       hdr.used_file_size = uint32_to_nbo(sizeof(hdr));
-       cache->used_file_size = sizeof(hdr);
-
-       fd = file_dotlock_open(cache->filepath, NULL, MAIL_CACHE_LOCK_TIMEOUT,
-                              MAIL_CACHE_LOCK_CHANGE_TIMEOUT,
-                              MAIL_CACHE_LOCK_IMMEDIATE_TIMEOUT, NULL, NULL);
-       if (fd == -1) {
-               mail_cache_set_syscall_error(cache, "file_dotlock_open()");
-               return -1;
-       }
-
-       if (write_full(fd, &hdr, sizeof(hdr)) < 0) {
-               mail_cache_set_syscall_error(cache, "write_full()");
-               (void)file_dotlock_delete(cache->filepath, fd);
-               return -1;
-       }
-       if (file_set_size(fd, MAIL_CACHE_INITIAL_SIZE) < 0) {
-               mail_cache_set_syscall_error(cache, "file_set_size()");
-               (void)file_dotlock_delete(cache->filepath, fd);
-               return -1;
-       }
-
-       mail_cache_file_close(cache);
-       cache->fd = dup(fd);
-
-       if (file_dotlock_replace(cache->filepath, fd, FALSE) < 0) {
-               mail_cache_set_syscall_error(cache, "file_dotlock_replace()");
-               return -1;
-       }
-
-       cache->mmap_refresh = TRUE;
-       if (!mmap_update(cache, 0, sizeof(struct mail_cache_header)))
-               return -1;
-
-       return 0;
-}
-
-int mail_cache_lock(struct mail_cache *cache, int nonblock)
-{
-       int ret;
-
-       if (cache->locks++ != 0)
-               return TRUE;
-
-       if (cache->anon_mmap)
-               return TRUE;
-
-       if (nonblock) {
-               ret = file_try_lock(cache->fd, F_WRLCK);
-               if (ret < 0)
-                       mail_cache_set_syscall_error(cache, "file_try_lock()");
-       } else {
-               ret = file_wait_lock(cache->fd, F_WRLCK);
-               if (ret <= 0)
-                       mail_cache_set_syscall_error(cache, "file_wait_lock()");
-       }
-
-       if (ret > 0) {
-               if (!mmap_update(cache, 0, 0)) {
-                       (void)mail_cache_unlock(cache);
-                       return -1;
-               }
-               if (cache->sync_id != cache->index->cache_sync_id) {
-                       /* we have the cache file locked and sync_id still
-                          doesn't match. it means we crashed between updating
-                          cache file and updating sync_id in index header.
-                          just update the sync_ids so they match. */
-                       i_warning("Updating broken sync_id in cache file %s",
-                                 cache->filepath);
-                       cache->sync_id = cache->hdr->sync_id =
-                               cache->index->cache_sync_id;
-               }
-       }
-       return ret;
-}
-
-int mail_cache_unlock(struct mail_cache *cache)
-{
-       if (--cache->locks > 0)
-               return TRUE;
-
-       if (cache->anon_mmap)
-               return TRUE;
-
-       if (file_wait_lock(cache->fd, F_UNLCK) <= 0) {
-               mail_cache_set_syscall_error(cache, "file_wait_lock(F_UNLCK)");
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
-int mail_cache_is_locked(struct mail_cache *cache)
-{
-       return cache->locks > 0;
-}
-
-struct mail_cache_view *
-mail_cache_view_open(struct mail_cache *cache, struct mail_index_view *view)
-{
-       struct mail_cache_view *view;
-
-       view = i_new(struct mail_cache_view, 1);
-       view->cache = cache;
-       view->view = view;
-       return view;
-}
-
-void mail_cache_view_close(struct mail_cache_view *view)
-{
-       i_free(view);
-}
-
-static const char *
-mail_cache_get_header_fields_str(struct mail_cache *cache, unsigned int idx)
-{
-       uint32_t offset, data_size;
-       unsigned char *buf;
-
-       offset = offset_to_uint32(cache->hdr->header_offsets[idx]);
-
-       if (offset == 0)
-               return NULL;
-
-       if (!mmap_update(cache, offset, 1024))
-               return NULL;
-
-       if (offset + sizeof(data_size) > cache->mmap_length) {
-               mail_cache_set_corrupted(cache, "Header %u points outside file",
-                                        idx);
-               return NULL;
-       }
-
-       buf = cache->mmap_base;
-       memcpy(&data_size, buf + offset, sizeof(data_size));
-       data_size = nbo_to_uint32(data_size);
-       offset += sizeof(data_size);
-
-       if (data_size == 0) {
-               mail_cache_set_corrupted(cache,
-                       "Header %u points to empty string", idx);
-               return NULL;
-       }
-
-       if (!mmap_update(cache, offset, data_size))
-               return NULL;
-
-       if (offset + data_size > cache->mmap_length) {
-               mail_cache_set_corrupted(cache, "Header %u points outside file",
-                                        idx);
-               return NULL;
-       }
-
-       buf = cache->mmap_base;
-       if (buf[offset + data_size - 1] != '\0') {
-               mail_cache_set_corrupted(cache,
-                       "Header %u points to invalid string", idx);
-               return NULL;
-       }
-
-       return buf + offset;
-}
-
-static const char *const *
-split_header(struct mail_cache *cache, const char *header)
-{
-       const char *const *arr, *const *tmp;
-       const char *null = NULL;
-       char *str;
-       buffer_t *buf;
-
-       if (header == NULL)
-               return NULL;
-
-       arr = t_strsplit(header, "\n");
-       buf = buffer_create_dynamic(cache->split_header_pool, 32, (size_t)-1);
-       for (tmp = arr; *tmp != NULL; tmp++) {
-               str = p_strdup(cache->split_header_pool, *tmp);
-               buffer_append(buf, &str, sizeof(str));
-       }
-       buffer_append(buf, &null, sizeof(null));
-
-       return buffer_get_data(buf, NULL);
-}
-
-const char *const *mail_cache_get_header_fields(struct mail_cache *cache,
-                                               unsigned int idx)
-{
-       const char *str;
-       int i;
-
-       i_assert(idx < MAIL_CACHE_HEADERS_COUNT);
-
-       /* t_strsplit() is a bit slow, so we cache it */
-       if (cache->hdr->header_offsets[idx] != cache->split_offsets[idx]) {
-               p_clear(cache->split_header_pool);
-
-               t_push();
-               for (i = 0; i < MAIL_CACHE_HEADERS_COUNT; i++) {
-                       cache->split_offsets[i] =
-                               cache->hdr->header_offsets[i];
-
-                       str = mail_cache_get_header_fields_str(cache, i);
-                       cache->split_headers[i] = split_header(cache, str);
-               }
-               t_pop();
-       }
-
-       return cache->split_headers[idx];
-}
-
-static const char *write_header_string(const char *const headers[],
-                                      uint32_t *size_r)
-{
-       buffer_t *buffer;
-       size_t size;
-
-       buffer = buffer_create_dynamic(pool_datastack_create(),
-                                      512, (size_t)-1);
-
-       while (*headers != NULL) {
-               if (buffer_get_used_size(buffer) != 0)
-                       buffer_append(buffer, "\n", 1);
-               buffer_append(buffer, *headers, strlen(*headers));
-               headers++;
-       }
-       buffer_append(buffer, null4, 1);
-
-       size = buffer_get_used_size(buffer);
-       if ((size & 3) != 0) {
-               buffer_append(buffer, null4, 4 - (size & 3));
-               size += 4 - (size & 3);
-       }
-       *size_r = size;
-       return buffer_get_data(buffer, NULL);
-}
-
-int mail_cache_set_header_fields(struct mail_cache_transaction_ctx *ctx,
-                                unsigned int idx, const char *const headers[])
-{
-       struct mail_cache *cache = ctx->cache;
-       uint32_t offset, update_offset, size;
-       const char *header_str, *prev_str;
-
-       i_assert(*headers != NULL);
-       i_assert(idx < MAIL_CACHE_HEADERS_COUNT);
-       i_assert(idx >= ctx->next_unused_header_lowwater);
-       i_assert(offset_to_uint32(cache->hdr->header_offsets[idx]) == 0);
-
-       t_push();
-
-       header_str = write_header_string(headers, &size);
-       if (idx != 0) {
-               prev_str = mail_cache_get_header_fields_str(cache, idx-1);
-               if (prev_str == NULL) {
-                       t_pop();
-                       return FALSE;
-               }
-
-               i_assert(strcmp(header_str, prev_str) != 0);
-       }
-
-       offset = mail_cache_append_space(ctx, size + sizeof(uint32_t));
-       if (offset != 0) {
-               memcpy((char *) cache->mmap_base + offset + sizeof(uint32_t),
-                      header_str, size);
-
-               size = uint32_to_nbo(size);
-               memcpy((char *) cache->mmap_base + offset,
-                      &size, sizeof(uint32_t));
-
-               /* update cached headers */
-               cache->split_offsets[idx] = cache->hdr->header_offsets[idx];
-               cache->split_headers[idx] = split_header(cache, header_str);
-
-               /* mark used-bit to be updated later. not really needed for
-                  read-safety, but if transaction get rolled back we can't let
-                  this point to invalid location. */
-               update_offset = (char *) &cache->hdr->header_offsets[idx] -
-                       (char *) cache->mmap_base;
-               mark_update(&ctx->cache_marks, update_offset,
-                           uint32_to_offset(offset));
-
-               /* make sure get_header_fields() still works for this header
-                  while the transaction isn't yet committed. */
-               ctx->next_unused_header_lowwater = idx + 1;
-       }
-
-       t_pop();
-       return offset > 0;
-}
-
-static struct mail_cache_record *
-cache_get_record(struct mail_cache *cache, uint32_t offset)
-{
-#define CACHE_PREFETCH 1024
-       struct mail_cache_record *cache_rec;
-       size_t size;
-
-       offset = offset_to_uint32(offset);
-       if (offset == 0)
-               return NULL;
-
-       if (!mmap_update(cache, offset, sizeof(*cache_rec) + CACHE_PREFETCH))
-               return NULL;
-
-       if (offset + sizeof(*cache_rec) > cache->mmap_length) {
-               mail_cache_set_corrupted(cache, "record points outside file");
-               return NULL;
-       }
-       cache_rec = CACHE_RECORD(cache, offset);
-
-       size = nbo_to_uint32(cache_rec->size);
-       if (size < sizeof(*cache_rec)) {
-               mail_cache_set_corrupted(cache, "invalid record size");
-               return NULL;
-       }
-       if (size > CACHE_PREFETCH) {
-               if (!mmap_update(cache, offset, size))
-                       return NULL;
-       }
-
-       if (offset + size > cache->mmap_length) {
-               mail_cache_set_corrupted(cache, "record points outside file");
-               return NULL;
-       }
-       return cache_rec;
-}
-
-static struct mail_cache_record *
-cache_get_next_record(struct mail_cache *cache, struct mail_cache_record *rec)
-{
-       struct mail_cache_record *next;
-
-       next = cache_get_record(cache, rec->next_offset);
-       if (next != NULL && next <= rec) {
-               mail_cache_set_corrupted(cache, "next_offset points backwards");
-               return NULL;
-       }
-       return next;
-}
-
-static struct mail_cache_record *
-mail_cache_lookup(struct mail_cache *cache, const struct mail_index_record *rec,
-                 enum mail_cache_field fields)
-{
-       struct mail_cache_record *cache_rec;
-       unsigned int idx;
-
-       if (cache->trans_ctx != NULL &&
-           cache->trans_ctx->first_uid <= rec->uid &&
-           cache->trans_ctx->last_uid >= rec->uid &&
-           (cache->trans_ctx->prev_uid != rec->uid || fields == 0 ||
-            (cache->trans_ctx->prev_fields & fields) != 0)) {
-               /* we have to auto-commit since we're not capable of looking
-                  into uncommitted records. it would be possible by checking
-                  index_marks and cache_marks, but it's just more trouble
-                  than worth. */
-               idx = INDEX_RECORD_INDEX(cache->index, rec);
-               if (cache->trans_ctx->last_idx == idx) {
-                       if (!mail_cache_write(cache->trans_ctx))
-                               return NULL;
-               }
-
-               if (!mail_cache_transaction_commit(cache->trans_ctx))
-                       return NULL;
-       }
-
-       cache_rec = cache_get_record(cache, rec->cache_offset);
-       if (cache_rec == NULL)
-               return NULL;
-
-       return cache_rec;
-}
-
-enum mail_cache_field
-mail_cache_get_fields(struct mail_cache *cache,
-                     const struct mail_index_record *rec)
-{
-       struct mail_cache_record *cache_rec;
-        enum mail_cache_field fields = 0;
-
-       cache_rec = mail_cache_lookup(cache, rec, 0);
-       while (cache_rec != NULL) {
-               fields |= cache_rec->fields;
-               cache_rec = cache_get_next_record(cache, cache_rec);
-       }
-
-       return fields;
-}
-
-static int cache_get_field(struct mail_cache *cache,
-                          struct mail_cache_record *cache_rec,
-                          enum mail_cache_field field,
-                          void **data_r, size_t *size_r)
-{
-       unsigned char *buf;
-       unsigned int mask;
-       uint32_t rec_size, data_size;
-       size_t offset, next_offset;
-       int i;
-
-       rec_size = nbo_to_uint32(cache_rec->size);
-       buf = (unsigned char *) cache_rec;
-       offset = sizeof(*cache_rec);
-
-       for (i = 0, mask = 1; i < 31; i++, mask <<= 1) {
-               if ((cache_rec->fields & mask) == 0)
-                       continue;
-
-               /* all records are at least 32bit. we have to check this
-                  before getting data_size. */
-               if (offset + sizeof(uint32_t) > rec_size) {
-                       mail_cache_set_corrupted(cache,
-                               "Record continues outside it's allocated size");
-                       return FALSE;
-               }
-
-               if ((mask & MAIL_CACHE_FIXED_MASK) != 0)
-                       data_size = mail_cache_field_sizes[i];
-               else {
-                       memcpy(&data_size, buf + offset, sizeof(data_size));
-                       data_size = nbo_to_uint32(data_size);
-                       offset += sizeof(data_size);
-               }
-
-               next_offset = offset + ((data_size + 3) & ~3);
-               if (next_offset > rec_size) {
-                       mail_cache_set_corrupted(cache,
-                               "Record continues outside it's allocated size");
-                       return FALSE;
-               }
-
-               if (field == mask) {
-                       if (data_size == 0) {
-                               mail_cache_set_corrupted(cache,
-                                                        "Field size is 0");
-                               return FALSE;
-                       }
-                       *data_r = buf + offset;
-                       *size_r = data_size;
-                       return TRUE;
-               }
-               offset = next_offset;
-       }
-
-       i_unreached();
-       return FALSE;
-}
-
-static int cache_lookup_field(struct mail_cache *cache,
-                             const struct mail_index_record *rec,
-                             enum mail_cache_field field,
-                             void **data_r, size_t *size_r)
-{
-       struct mail_cache_record *cache_rec;
-
-       cache_rec = mail_cache_lookup(cache, rec, field);
-       while (cache_rec != NULL) {
-               if ((cache_rec->fields & field) != 0) {
-                       return cache_get_field(cache, cache_rec, field,
-                                              data_r, size_r);
-               }
-               cache_rec = cache_get_next_record(cache, cache_rec);
-       }
-
-       return FALSE;
-}
-
-int mail_cache_lookup_field(struct mail_cache *cache,
-                           const struct mail_index_record *rec,
-                           enum mail_cache_field field,
-                           const void **data_r, size_t *size_r)
-{
-       void *data;
-
-       if (!cache_lookup_field(cache, rec, field, &data, size_r))
-               return FALSE;
-
-       *data_r = data;
-       return TRUE;
-}
-
-const char *mail_cache_lookup_string_field(struct mail_cache *cache,
-                                          const struct mail_index_record *rec,
-                                          enum mail_cache_field field)
-{
-       const void *data;
-       size_t size;
-
-       i_assert((field & MAIL_CACHE_STRING_MASK) != 0);
-
-       if (!mail_cache_lookup_field(cache, rec, field, &data, &size))
-               return NULL;
-
-       if (((const char *) data)[size-1] != '\0') {
-               mail_cache_set_corrupted(cache,
-                       "String field %x doesn't end with NUL", field);
-               return NULL;
-       }
-       return data;
-}
-
-int mail_cache_copy_fixed_field(struct mail_cache *cache,
-                               const struct mail_index_record *rec,
-                               enum mail_cache_field field,
-                               void *buffer, size_t buffer_size)
-{
-       const void *data;
-       size_t size;
-
-       i_assert((field & MAIL_CACHE_FIXED_MASK) != 0);
-
-       if (!mail_cache_lookup_field(cache, rec, field, &data, &size))
-               return FALSE;
-
-       if (buffer_size != size) {
-               i_panic("cache: fixed field %x wrong size "
-                       "(%"PRIuSIZE_T" vs %"PRIuSIZE_T")",
-                       field, size, buffer_size);
-       }
-
-       memcpy(buffer, data, buffer_size);
-       return TRUE;
-}
-
-void mail_cache_mark_missing(struct mail_cache *cache,
-                            enum mail_cache_field fields)
-{
-       // FIXME: count these
-}
-
-enum mail_index_record_flag
-mail_cache_get_index_flags(struct mail_cache *cache,
-                          const struct mail_index_record *rec)
-{
-       enum mail_index_record_flag flags;
-
-       if (!mail_cache_copy_fixed_field(cache, rec, MAIL_CACHE_INDEX_FLAGS,
-                                        &flags, sizeof(flags)))
-               return 0;
-
-       return flags;
-}
-
-int mail_cache_update_index_flags(struct mail_cache *cache,
-                                 const struct mail_index_record *rec,
-                                 enum mail_index_record_flag flags)
-{
-       void *data;
-       size_t size;
-
-       i_assert(cache->locks > 0);
-
-       if (!cache_lookup_field(cache, rec, MAIL_CACHE_INDEX_FLAGS,
-                               &data, &size)) {
-               mail_cache_set_corrupted(cache,
-                       "Missing index flags for record %u", rec->uid);
-               return FALSE;
-       }
-
-       memcpy(data, &flags, sizeof(flags));
-       return TRUE;
-}
-
-int mail_cache_update_location_offset(struct mail_cache *cache,
-                                     const struct mail_index_record *rec,
-                                     uoff_t offset)
-{
-       void *data;
-       size_t size;
-
-       i_assert(cache->locks > 0);
-
-       if (!cache_lookup_field(cache, rec, MAIL_CACHE_LOCATION_OFFSET,
-                               &data, &size)) {
-               mail_cache_set_corrupted(cache,
-                       "Missing location offset for record %u", rec->uid);
-               return FALSE;
-       }
-
-       memcpy(data, &offset, sizeof(offset));
-       return TRUE;
-}
-
-void *mail_cache_get_mmaped(struct mail_cache *cache, size_t *size)
-{
-       if (!mmap_update(cache, 0, 0))
-               return NULL;
-
-       *size = cache->mmap_length;
-       return cache->mmap_base;
-}
index baa86f606fb1f47cc93f7dce7242f8415abfb1f6..50e93bbf217403f2d4456b490f2ba2ee91e7d0fc 100644 (file)
@@ -95,7 +95,8 @@ const char *const *
 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);
+mail_cache_get_record(struct mail_cache *cache, uint32_t offset,
+                     int index_offset);
 struct mail_cache_record *
 mail_cache_get_next_record(struct mail_cache *cache,
                           struct mail_cache_record *rec);
@@ -108,6 +109,9 @@ int
 mail_cache_transaction_autocommit(struct mail_cache_view *view,
                                  uint32_t seq, enum mail_cache_field fields);
 
+int mail_cache_mmap_update(struct mail_cache *cache,
+                          size_t offset, size_t size);
+
 void mail_cache_set_syscall_error(struct mail_cache *cache,
                                  const char *function);
 
index e33ff21ede4a8b413e2178b094b68213d38443c5..99fd8a7068d75a1ec784890c3c457644b617173f 100644 (file)
@@ -9,7 +9,6 @@
 
 #include <sys/stat.h>
 
-#if 0
 struct mail_cache_transaction_ctx {
        struct mail_cache *cache;
        struct mail_cache_view *view;
@@ -171,7 +170,7 @@ static int mail_cache_grow(struct mail_cache *cache, uint32_t size)
 
        if (cache->used_file_size + size <= (uoff_t)st.st_size) {
                /* no need to grow, just update mmap */
-               if (mmap_update(cache, 0, 0) < 0)
+               if (mail_cache_mmap_update(cache, 0, 0) < 0)
                        return -1;
 
                i_assert(cache->mmap_length >= (uoff_t)st.st_size);
@@ -183,7 +182,7 @@ static int mail_cache_grow(struct mail_cache *cache, uint32_t size)
                return -1;
        }
 
-       return mmap_update(cache, 0, 0);
+       return mail_cache_mmap_update(cache, 0, 0);
 }
 
 static uint32_t mail_cache_append_space(struct mail_cache_transaction_ctx *ctx,
@@ -219,46 +218,54 @@ static int mail_cache_write(struct mail_cache_transaction_ctx *ctx)
        uint32_t write_offset, update_offset;
        const void *buf;
        size_t size, buf_size;
+       int ret;
 
        buf = buffer_get_data(ctx->cache_data, &buf_size);
 
        size = sizeof(*cache_rec) + buf_size;
        ctx->cache_rec.size = uint32_to_nbo(size);
 
-       write_offset = mail_cache_append_space(ctx, size);
-       if (write_offset == 0)
-               return -1;
-
        // FIXME: check cache_offset in transaction
-       if (mail_index_lookup_latest(ctx->view->view, ctx->prev_seq, &rec) < 0)
+       ret = mail_index_lookup(ctx->view->view, ctx->prev_seq, &rec);
+       if (ret < 0)
                return -1;
 
-       cache_rec = mail_cache_get_record(cache, rec->cache_offset);
-       if (cache_rec == NULL) {
-               /* first cache record - update offset in index file */
-               mail_index_update_cache(ctx->trans, ctx->prev_seq,
-                                       write_offset);
+       if (ret == 0) {
+               /* it's been expunged already, do nothing */
        } else {
-               /* find the last cache record */
-               while ((next = mail_cache_get_next_record(cache,
-                                                         cache_rec)) != NULL)
-                       cache_rec = next;
+               write_offset = mail_cache_append_space(ctx, size);
+               if (write_offset == 0)
+                       return -1;
 
-               /* mark next_offset to be updated later */
-               update_offset = (char *) &cache_rec->next_offset -
-                       (char *) cache->mmap_base;
-               mark_update(&ctx->cache_marks, update_offset,
-                           mail_cache_uint32_to_offset(write_offset));
+               cache_rec = mail_cache_get_record(cache, rec->cache_offset,
+                                                 TRUE);
+               if (cache_rec == NULL) {
+                       /* first cache record - update offset in index file */
+                       mail_index_update_cache(ctx->trans, ctx->prev_seq,
+                                               write_offset);
+               } else {
+                       /* find the last cache record */
+                       while ((next = mail_cache_get_next_record(cache,
+                                                                 cache_rec)) != NULL)
+                               cache_rec = next;
+
+                       /* mark next_offset to be updated later */
+                       update_offset = (char *) &cache_rec->next_offset -
+                               (char *) cache->mmap_base;
+                       mark_update(&ctx->cache_marks, update_offset,
+                                   mail_cache_uint32_to_offset(write_offset));
+               }
+
+               memcpy((char *) cache->mmap_base + write_offset,
+                      &ctx->cache_rec, sizeof(ctx->cache_rec));
+               memcpy((char *) cache->mmap_base + write_offset +
+                      sizeof(ctx->cache_rec), buf, buf_size);
        }
+
+       /* reset the write context */
        ctx->prev_seq = 0;
        ctx->prev_fields = 0;
 
-       memcpy((char *) cache->mmap_base + write_offset,
-              &ctx->cache_rec, sizeof(ctx->cache_rec));
-       memcpy((char *) cache->mmap_base + write_offset +
-              sizeof(ctx->cache_rec), buf, buf_size);
-
-       /* reset the write context */
        memset(&ctx->cache_rec, 0, sizeof(ctx->cache_rec));
        buffer_set_used_size(ctx->cache_data, 0);
        return 0;
@@ -558,5 +565,9 @@ mail_cache_transaction_autocommit(struct mail_cache_view *view,
 
        return 0;
 }
-#else
-#endif
+
+int mail_cache_update_record_flags(struct mail_cache_view *view, uint32_t seq,
+                                  enum mail_cache_record_flag flags)
+{
+       return -1;
+}
index 6874c8575b3d199b848457646c7ec9d858352cc1..58a631ad48e3b0f30494c9a7748c1317ff8e9cf6 100644 (file)
@@ -4,6 +4,7 @@
 #include "buffer.h"
 #include "byteorder.h"
 #include "file-lock.h"
+#include "file-set-size.h"
 #include "mmap-util.h"
 #include "write-full.h"
 #include "mail-cache-private.h"
@@ -38,7 +39,6 @@ enum mail_cache_field mail_cache_header_fields[MAIL_CACHE_HEADERS_COUNT] = {
        MAIL_CACHE_HEADERS4
 };
 
-#if 0
 uint32_t mail_cache_uint32_to_offset(uint32_t offset)
 {
        unsigned char buf[4];
@@ -187,13 +187,15 @@ static int mmap_update_nocheck(struct mail_cache *cache,
 {
        struct stat st;
 
+#if 0 // FIXME
        /* if sequence has changed, the file has to be reopened.
           note that if main index isn't locked, it may change again */
        if (cache->hdr->file_seq != cache->index->hdr->cache_file_seq &&
            cache->mmap_base != NULL) {
-               if (!mail_cache_file_reopen(cache))
+               if (mail_cache_file_reopen(cache) < 0)
                        return -1;
        }
+#endif
 
        if (offset < cache->mmap_length &&
            size <= cache->mmap_length - offset &&
@@ -244,35 +246,38 @@ static int mmap_update_nocheck(struct mail_cache *cache,
        return 0;
 }
 
-static int mmap_update(struct mail_cache *cache, size_t offset, size_t size)
+int mail_cache_mmap_update(struct mail_cache *cache, size_t offset, size_t size)
 {
        int synced, ret;
 
        for (synced = FALSE;; synced = TRUE) {
                ret = mmap_update_nocheck(cache, offset, size);
                if (ret > 0)
-                       return TRUE;
+                       return 0;
                if (ret < 0)
-                       return FALSE;
+                       return -1;
 
-               if (!mmap_verify_header(cache))
-                       return FALSE;
+               if (mmap_verify_header(cache) <= 0)
+                       return -1;
 
+#if 0 // FIXME
                /* see if cache file was rebuilt - do it only once to avoid
                   infinite looping */
-               if (cache->hdr->sync_id == cache->index->cache_sync_id ||
+               if (cache->hdr->file_seq == cache->index->hdr->cache_file_seq ||
                    synced)
                        break;
 
-               if (!mail_cache_file_reopen(cache))
-                       return FALSE;
+               if (mail_cache_file_reopen(cache) < 0)
+                       return -1;
+#endif
        }
-       return TRUE;
+       return 0;
 }
 
 static int mail_cache_open_and_verify(struct mail_cache *cache, int silent)
 {
        struct stat st;
+       int ret;
 
        mail_cache_file_close(cache);
 
@@ -299,9 +304,9 @@ static int mail_cache_open_and_verify(struct mail_cache *cache, int silent)
 
        /* verify that this really is the cache for wanted index */
        cache->silent = silent;
-       if (!mmap_verify_header(cache)) {
+       if ((ret = mmap_verify_header(cache)) <= 0) {
                cache->silent = FALSE;
-               return 0;
+               return ret;
        }
 
        cache->silent = FALSE;
@@ -318,66 +323,64 @@ static int mail_cache_open_or_create_file(struct mail_cache *cache,
 
        ret = mail_cache_open_and_verify(cache, FALSE);
        if (ret != 0)
-               return ret > 0;
-
-       /* we'll have to clear cache_offsets which requires exclusive lock */
-       if (!mail_index_set_lock(cache->index, MAIL_LOCK_EXCLUSIVE))
-               return FALSE;
+               return ret < 0 ? -1 : 0;
 
        /* maybe a rebuild.. */
-       fd = file_dotlock_open(cache->filepath, NULL, MAIL_CACHE_LOCK_TIMEOUT,
+       fd = file_dotlock_open(cache->filepath, NULL, NULL,
+                              MAIL_CACHE_LOCK_TIMEOUT,
                               MAIL_CACHE_LOCK_CHANGE_TIMEOUT,
                               MAIL_CACHE_LOCK_IMMEDIATE_TIMEOUT, NULL, NULL);
        if (fd == -1) {
                mail_cache_set_syscall_error(cache, "file_dotlock_open()");
-               return FALSE;
+               return -1;
        }
 
        /* see if someone else just created the cache file */
        ret = mail_cache_open_and_verify(cache, TRUE);
        if (ret != 0) {
-               (void)file_dotlock_delete(cache->filepath, fd);
-               return ret > 0;
+               (void)file_dotlock_delete(cache->filepath, NULL, fd);
+               return ret < 0 ? -1 : 0;
        }
 
        /* rebuild then */
        if (write_full(fd, hdr, sizeof(*hdr)) < 0) {
                mail_cache_set_syscall_error(cache, "write_full()");
-               (void)file_dotlock_delete(cache->filepath, fd);
-               return FALSE;
+               (void)file_dotlock_delete(cache->filepath, NULL, fd);
+               return -1;
        }
        if (file_set_size(fd, MAIL_CACHE_INITIAL_SIZE) < 0) {
                mail_cache_set_syscall_error(cache, "file_set_size()");
-               (void)file_dotlock_delete(cache->filepath, fd);
-               return FALSE;
+               (void)file_dotlock_delete(cache->filepath, NULL, fd);
+               return -1;
        }
 
-       if (cache->index->hdr.cache_file_seq != 0) {
-               // FIXME: recreate index file with cache_offsets cleared
+       if (cache->index->hdr->cache_file_seq != 0) {
+               // FIXME: clear cache_offsets in index file
        }
 
        mail_cache_file_close(cache);
        cache->fd = dup(fd);
 
-       if (file_dotlock_replace(cache->filepath, fd, FALSE) < 0) {
+       if (file_dotlock_replace(cache->filepath, NULL, fd, FALSE) < 0) {
                mail_cache_set_syscall_error(cache, "file_dotlock_replace()");
-               return FALSE;
+               return -1;
        }
 
-       if (!mmap_update(cache, 0, sizeof(struct mail_cache_header)))
-               return FALSE;
+       if (mail_cache_mmap_update(cache, 0,
+                                  sizeof(struct mail_cache_header)) < 0)
+               return -1;
 
-       return TRUE;
+       return 0;
 }
 
-int mail_cache_open_or_create(struct mail_index *index)
+struct mail_cache *mail_cache_open_or_create(struct mail_index *index)
 {
         struct mail_cache_header hdr;
        struct mail_cache *cache;
 
        memset(&hdr, 0, sizeof(hdr));
        hdr.indexid = index->indexid;
-       hdr.sync_id = index->hdr->cache_file_seq; // FIXME
+       hdr.file_seq = index->hdr->cache_file_seq + 1;
        hdr.used_file_size = uint32_to_nbo(sizeof(hdr));
 
        cache = i_new(struct mail_cache, 1);
@@ -385,25 +388,21 @@ int mail_cache_open_or_create(struct mail_index *index)
        cache->fd = -1;
         cache->split_header_pool = pool_alloconly_create("Headers", 512);
 
-       index->cache = cache;
-
        /* we'll do anon-mmaping only if initially requested. if we fail
           because of out of disk space, we'll just let the main index code
           know it and fail. */
-       if (!mail_cache_open_or_create_file(cache, &hdr)) {
+       if (mail_cache_open_or_create_file(cache, &hdr) < 0) {
                mail_cache_free(cache);
-               return FALSE;
+               return NULL;
        }
 
-       return TRUE;
+       return cache;
 }
 
 void mail_cache_free(struct mail_cache *cache)
 {
        i_assert(cache->trans_ctx == NULL);
 
-       cache->index->cache = NULL;
-
        mail_cache_file_close(cache);
 
        pool_unref(cache->split_header_pool);
@@ -422,18 +421,20 @@ void mail_cache_set_defaults(struct mail_cache *cache,
 int mail_cache_reset(struct mail_cache *cache)
 {
        struct mail_cache_header hdr;
-       int ret, fd;
+       int fd;
 
-       i_assert(cache->index->lock_type == MAIL_LOCK_EXCLUSIVE);
+       i_assert(cache->index->lock_type == F_WRLCK);
 
        memset(&hdr, 0, sizeof(hdr));
        hdr.indexid = cache->index->indexid;
-       hdr.sync_id = cache->sync_id = cache->index->cache_sync_id =
-               ++cache->index->hdr->cache_sync_id;
+       hdr.file_seq = cache->index->hdr->cache_file_seq + 1;
        hdr.used_file_size = uint32_to_nbo(sizeof(hdr));
        cache->used_file_size = sizeof(hdr);
 
-       fd = file_dotlock_open(cache->filepath, NULL, MAIL_CACHE_LOCK_TIMEOUT,
+       // FIXME: update cache_offsets in index
+
+       fd = file_dotlock_open(cache->filepath, NULL, NULL,
+                              MAIL_CACHE_LOCK_TIMEOUT,
                               MAIL_CACHE_LOCK_CHANGE_TIMEOUT,
                               MAIL_CACHE_LOCK_IMMEDIATE_TIMEOUT, NULL, NULL);
        if (fd == -1) {
@@ -443,25 +444,26 @@ int mail_cache_reset(struct mail_cache *cache)
 
        if (write_full(fd, &hdr, sizeof(hdr)) < 0) {
                mail_cache_set_syscall_error(cache, "write_full()");
-               (void)file_dotlock_delete(cache->filepath, fd);
+               (void)file_dotlock_delete(cache->filepath, NULL, fd);
                return -1;
        }
        if (file_set_size(fd, MAIL_CACHE_INITIAL_SIZE) < 0) {
                mail_cache_set_syscall_error(cache, "file_set_size()");
-               (void)file_dotlock_delete(cache->filepath, fd);
+               (void)file_dotlock_delete(cache->filepath, NULL, fd);
                return -1;
        }
 
        mail_cache_file_close(cache);
        cache->fd = dup(fd);
 
-       if (file_dotlock_replace(cache->filepath, fd, FALSE) < 0) {
+       if (file_dotlock_replace(cache->filepath, NULL, fd, FALSE) < 0) {
                mail_cache_set_syscall_error(cache, "file_dotlock_replace()");
                return -1;
        }
 
        cache->mmap_refresh = TRUE;
-       if (!mmap_update(cache, 0, sizeof(struct mail_cache_header)))
+       if (mail_cache_mmap_update(cache, 0,
+                                  sizeof(struct mail_cache_header)) < 0)
                return -1;
 
        return 0;
@@ -472,7 +474,7 @@ int mail_cache_lock(struct mail_cache *cache, int nonblock)
        int ret;
 
        if (cache->locks++ != 0)
-               return TRUE;
+               return 1;
 
        if (nonblock) {
                ret = file_try_lock(cache->fd, F_WRLCK);
@@ -485,20 +487,22 @@ int mail_cache_lock(struct mail_cache *cache, int nonblock)
        }
 
        if (ret > 0) {
-               if (!mmap_update(cache, 0, 0)) {
+               if (mail_cache_mmap_update(cache, 0, 0) < 0) {
                        (void)mail_cache_unlock(cache);
                        return -1;
                }
-               if (cache->sync_id != cache->index->cache_sync_id) {
+#if 0 // FIXME
+               if (cache->hdr->file_seq != cache->index->hdr->cache_file_seq) {
                        /* we have the cache file locked and sync_id still
                           doesn't match. it means we crashed between updating
                           cache file and updating sync_id in index header.
                           just update the sync_ids so they match. */
                        i_warning("Updating broken sync_id in cache file %s",
                                  cache->filepath);
-                       cache->sync_id = cache->hdr->sync_id =
-                               cache->index->cache_sync_id;
+                       cache->hdr->file_seq =
+                               cache->index->hdr->cache_file_seq;
                }
+#endif
        }
        return ret;
 }
@@ -506,14 +510,14 @@ int mail_cache_lock(struct mail_cache *cache, int nonblock)
 int mail_cache_unlock(struct mail_cache *cache)
 {
        if (--cache->locks > 0)
-               return TRUE;
+               return 0;
 
        if (file_wait_lock(cache->fd, F_UNLCK) <= 0) {
                mail_cache_set_syscall_error(cache, "file_wait_lock(F_UNLCK)");
-               return FALSE;
+               return -1;
        }
 
-       return TRUE;
+       return 0;
 }
 
 int mail_cache_is_locked(struct mail_cache *cache)
@@ -536,128 +540,9 @@ void mail_cache_view_close(struct mail_cache_view *view)
 {
        i_free(view);
 }
-#else
-
-int mail_cache_open_or_create(struct mail_index *index)
-{
-       return 0;
-}
-
-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) {}
 
-/* Compress cache file. */
-int mail_cache_compress(struct mail_cache *cache) {return 0;}
-
-/* Reset the cache file, clearing all data. */
-int mail_cache_reset(struct mail_cache *cache) {return 0;}
-
-/* Explicitly lock the cache file. Returns 1 if ok, 0 if nonblock is TRUE and
-   we couldn't immediately get a lock, or -1 if error. */
-int mail_cache_lock(struct mail_cache *cache, int nonblock) {return 0;}
-int mail_cache_unlock(struct mail_cache *cache) {return 0;}
-
-/* Returns TRUE if cache file is locked. */
-int mail_cache_is_locked(struct mail_cache *cache) {return TRUE;}
-
-struct mail_cache_view *
-mail_cache_view_open(struct mail_cache *cache, struct mail_index_view *iview)
-{return i_new(struct mail_cache_view, 1);}
-void mail_cache_view_close(struct mail_cache_view *view) {i_free(view);}
-
-/* Begin transaction. Cache transaction may be committed or rollbacked multiple
-   times. It will finish when index transaction is committed or rollbacked.
-   The transaction might also be partially committed automatically, so this
-   is kind of fake transaction, it's only purpose being optimizing writes.
-   Returns same as mail_cache_lock(). */
-int mail_cache_transaction_begin(struct mail_cache_view *view, int nonblock,
-                                struct mail_index_transaction *t,
-                                struct mail_cache_transaction_ctx **ctx_r)
+void mail_cache_mark_missing(struct mail_cache_view *view,
+                            enum mail_cache_field fields)
 {
-       *ctx_r = NULL;
-       return 1;
+       // FIXME
 }
-int mail_cache_transaction_commit(struct mail_cache_transaction_ctx *ctx)
-{return 0;}
-void mail_cache_transaction_rollback(struct mail_cache_transaction_ctx *ctx) {}
-
-/* Should be called only by mail_transaction_commit/rollback: */
-int mail_cache_transaction_end(struct mail_cache_transaction_ctx *ctx)
-{return 0;}
-
-/* Return NULL-terminated list of headers for given index, or NULL if
-   header index isn't used. */
-const char *const *mail_cache_get_header_fields(struct mail_cache_view *view,
-                                               unsigned int idx)
-{return NULL;}
-/* Set list of headers for given index. */
-int mail_cache_set_header_fields(struct mail_cache_transaction_ctx *ctx,
-                                unsigned int idx, const char *const headers[])
-{return 0;}
-
-/* Add new field to given record. Updates are not allowed. Fixed size fields
-   must be exactly the expected size and they're converted to network byte
-   order in disk. */
-int 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 0;}
-
-/* Mark the given record deleted. */
-int mail_cache_delete(struct mail_cache_transaction_ctx *ctx, uint32_t seq)
-{return 0;}
-
-/* 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) {return 0;}
-
-/* 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,
-   first one found is returned. This is mostly useful for finding headers. */
-int mail_cache_lookup_field(struct mail_cache_view *view, uint32_t seq,
-                           enum mail_cache_field field,
-                           const void **data_r, size_t *size_r) {return 0;}
-
-/* Return string field. */
-const char *
-mail_cache_lookup_string_field(struct mail_cache_view *view, uint32_t seq,
-                              enum mail_cache_field field) {return 0;}
-
-/* Copy fixed size field to given buffer. buffer_size must be exactly the
-   expected size. The result will be converted to host byte order.
-   Returns TRUE if field was found. */
-int mail_cache_copy_fixed_field(struct mail_cache_view *view, uint32_t seq,
-                               enum mail_cache_field field,
-                               void *buffer, size_t buffer_size) {return 0;}
-
-/* Mark given fields as missing, ie. they should be cached when possible. */
-void mail_cache_mark_missing(struct mail_cache_view *view,
-                            enum mail_cache_field fields) {}
-
-/* Return index flags. */
-enum mail_cache_record_flag
-mail_cache_get_record_flags(struct mail_cache_view *view, uint32_t seq)
-{return 0;}
-
-/* Update index flags. The cache file must be locked and the flags must be
-   already inserted to the record. */
-int mail_cache_update_record_flags(struct mail_cache_view *view, uint32_t seq,
-                                  enum mail_cache_record_flag flags)
-{return 0;}
-
-/* Update location offset. External locking is assumed to take care of locking
-   readers out to prevent race conditions. */
-int mail_cache_update_location_offset(struct mail_cache_view *view,
-                                     uint32_t seq, uoff_t offset)
-{return 0;}
-
-/* "Error in index cache file %s: ...". */
-void mail_cache_set_corrupted(struct mail_cache *cache, const char *fmt, ...)
-{}
-
-#endif
index 1162ee28c711e6caa0d840dbe4d7377e829ecda1..aa4823db722dc3d9da1fe672632e3a69d45bec57 100644 (file)
@@ -28,12 +28,9 @@ enum mail_cache_record_flag {
 enum mail_cache_field {
        /* fixed size fields */
        MAIL_CACHE_INDEX_FLAGS          = 0x00000001,
-       MAIL_CACHE_LOCATION_OFFSET      = 0x00000002,
-       MAIL_CACHE_MD5                  = 0x00000004,
        MAIL_CACHE_SENT_DATE            = 0x00000008,
        MAIL_CACHE_RECEIVED_DATE        = 0x00000010,
        MAIL_CACHE_VIRTUAL_FULL_SIZE    = 0x00000020,
-       MAIL_CACHE_PHYSICAL_BODY_SIZE   = 0x00000040,
 
        /* variable sized field */
        MAIL_CACHE_HEADERS1             = 0x40000000,
@@ -47,12 +44,9 @@ enum mail_cache_field {
        MAIL_CACHE_MESSAGEPART          = 0x00400000,
 
        MAIL_CACHE_FIXED_MASK           = MAIL_CACHE_INDEX_FLAGS |
-                                         MAIL_CACHE_LOCATION_OFFSET |
-                                         MAIL_CACHE_MD5 |
                                          MAIL_CACHE_SENT_DATE |
                                          MAIL_CACHE_RECEIVED_DATE |
-                                         MAIL_CACHE_VIRTUAL_FULL_SIZE |
-                                         MAIL_CACHE_PHYSICAL_BODY_SIZE,
+                                         MAIL_CACHE_VIRTUAL_FULL_SIZE,
        MAIL_CACHE_HEADERS_MASK         = MAIL_CACHE_HEADERS1 |
                                          MAIL_CACHE_HEADERS2 |
                                          MAIL_CACHE_HEADERS3 |
@@ -74,7 +68,7 @@ struct mail_sent_date {
 
 extern enum mail_cache_field mail_cache_header_fields[MAIL_CACHE_HEADERS_COUNT];
 
-int mail_cache_open_or_create(struct mail_index *index);
+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,
@@ -167,11 +161,6 @@ mail_cache_get_record_flags(struct mail_cache_view *view, uint32_t seq);
 int mail_cache_update_record_flags(struct mail_cache_view *view, uint32_t seq,
                                   enum mail_cache_record_flag flags);
 
-/* Update location offset. External locking is assumed to take care of locking
-   readers out to prevent race conditions. */
-int mail_cache_update_location_offset(struct mail_cache_view *view,
-                                     uint32_t seq, uoff_t offset);
-
 /* "Error in index cache file %s: ...". */
 void mail_cache_set_corrupted(struct mail_cache *cache, const char *fmt, ...)
        __attr_format__(2, 3);
index 0225aa59d0e438695eeccc9fc00d28dbef585af3..ff0cb25d9e5346b815ec579204ad285feb9167b3 100644 (file)
@@ -8,6 +8,7 @@
 #include "write-full.h"
 #include "mail-index-private.h"
 #include "mail-transaction-log.h"
+#include "mail-cache.h"
 
 #include <stdio.h>
 #include <stddef.h>
@@ -553,7 +554,7 @@ static int mail_index_create(struct mail_index *index,
        ret = mail_index_try_open(index, NULL);
        if (ret != 0) {
                mail_transaction_log_sync_unlock(index->log);
-               return ret;
+               return ret < 0 ? -1 : 0;
        }
 
        /* create it fully in index.tmp first */
@@ -618,6 +619,7 @@ static void mail_index_header_init(struct mail_index *index,
        hdr->next_uid = 1;
 }
 
+/* returns -1 = error, 0 = won't create, 1 = ok */
 static int mail_index_open_files(struct mail_index *index,
                                 enum mail_index_open_flags flags)
 {
@@ -643,9 +645,27 @@ static int mail_index_open_files(struct mail_index *index,
        if (index->log == NULL)
                return -1;
 
-       if (lock_id != 0)
-               mail_index_unlock(index, lock_id);
-       return index->fd != -1 ? 1 : mail_index_create(index, &hdr);
+       if (index->fd == -1) {
+               if (lock_id != 0) {
+                       mail_index_unlock(index, lock_id);
+                       lock_id = 0;
+               }
+               if (mail_index_create(index, &hdr) < 0)
+                       return -1;
+       }
+
+       if (lock_id == 0) {
+               if (mail_index_lock_shared(index, FALSE, &lock_id) < 0)
+                       return -1;
+
+       }
+
+       index->cache = mail_cache_open_or_create(index);
+       if (index->cache == NULL)
+               return -1;
+
+       mail_index_unlock(index, lock_id);
+       return 1;
 }
 
 int mail_index_open(struct mail_index *index, enum mail_index_open_flags flags)
@@ -711,6 +731,11 @@ void mail_index_close(struct mail_index *index)
                index->map = NULL;
        }
 
+       if (index->cache != NULL) {
+               mail_cache_free(index->cache);
+               index->cache = NULL;
+       }
+
        if (index->fd != -1) {
                if (close(index->fd) < 0)
                        mail_index_set_syscall_error(index, "close()");
index 4a7ed28d14dc084dfa548b1a69210cd4f9fdbb61..ff7f6d1449215abdc5fb864f8d96a0754c2448b4 100644 (file)
@@ -157,8 +157,8 @@ void index_mail_cache_add(struct index_mail *mail, enum mail_cache_field field,
         if (!index_mail_cache_can_add(mail, field))
                return;
 
-       if (!mail_cache_add(mail->trans->cache_trans, mail->data.seq,
-                           field, data, size))
+       if (mail_cache_add(mail->trans->cache_trans, mail->data.seq,
+                          field, data, size) < 0)
                mail_cache_transaction_rollback(mail->trans->cache_trans);
 
        mail->data.cached_fields |= field;
index e2dab12929eb3624370538ad72e49a15499e0413..812aa8bad6930658a0f21b1803d69c92409910c5 100644 (file)
@@ -350,6 +350,8 @@ index_storage_mailbox_init(struct index_storage *storage, struct mailbox *box,
                }
 
                ibox->view = mail_index_view_open(index);
+               ibox->cache_view =
+                       mail_cache_view_open(ibox->cache, ibox->view);
                return ibox;
        } while (0);
 
@@ -362,6 +364,8 @@ void index_storage_mailbox_free(struct mailbox *box)
 {
        struct index_mailbox *ibox = (struct index_mailbox *) box;
 
+       if (ibox->cache_view != NULL)
+               mail_cache_view_close(ibox->cache_view);
        if (ibox->view != NULL)
                mail_index_view_close(ibox->view);
 
index e9233f09fee50d7cab960cb65a8ab6972f104991..e32d93075741c35a1ff4436d8855ff4af37089c6 100644 (file)
@@ -20,8 +20,11 @@ int index_transaction_commit(struct mailbox_transaction_context *_t)
        uoff_t offset;
        int ret;
 
-       if (t->cache_trans != NULL) 
+       if (t->cache_trans != NULL)  {
                (void)mail_cache_transaction_commit(t->cache_trans);
+               (void)mail_cache_transaction_end(t->cache_trans);
+               t->cache_trans = NULL;
+       }
 
        ret = mail_index_transaction_commit(t->trans, &seq, &offset);
        if (ret < 0)