mail-cache.c revision 58febed28f2af78b2d8a281c851d9b67160c4bd3
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "lib.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "buffer.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "hash.h"
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen#include "file-lock.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "mmap-util.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "write-full.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include "mail-cache-private.h"
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen#include <unistd.h>
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenvoid mail_cache_set_syscall_error(struct mail_cache *cache,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen const char *function)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen i_assert(function != NULL);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (ENOSPACE(errno)) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen cache->index->nodiskspace = TRUE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mail_index_set_error(cache->index,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen "%s failed with index cache file %s: %m",
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen function, cache->filepath);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenvoid mail_cache_set_corrupted(struct mail_cache *cache, const char *fmt, ...)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen va_list va;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen (void)unlink(cache->filepath);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mail_cache_file_close(cache);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen va_start(va, fmt);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen t_push();
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mail_index_set_error(cache->index, "Corrupted index cache file %s: %s",
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen cache->filepath, t_strdup_vprintf(fmt, va));
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen t_pop();
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen va_end(va);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
063254ba79239f1c0a78ea08d4aa22f8f11d984cTimo Sirainenvoid mail_cache_file_close(struct mail_cache *cache)
063254ba79239f1c0a78ea08d4aa22f8f11d984cTimo Sirainen{
063254ba79239f1c0a78ea08d4aa22f8f11d984cTimo Sirainen if (cache->mmap_base != NULL) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (munmap(cache->mmap_base, cache->mmap_length) < 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mail_cache_set_syscall_error(cache, "munmap()");
e809db9220c804b16d4d74782433a1075da12274Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen cache->mmap_base = NULL;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen cache->hdr = NULL;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen cache->mmap_length = 0;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (cache->fd != -1) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (close(cache->fd) < 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mail_cache_set_syscall_error(cache, "close()");
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen cache->fd = -1;
8ddc45fe2080010715c212ecbb2b12b6734f6d4bTimo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
8ddc45fe2080010715c212ecbb2b12b6734f6d4bTimo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenint mail_cache_reopen(struct mail_cache *cache)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache) && cache->need_compress) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* unusable, we're just waiting for compression */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return 0;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mail_cache_file_close(cache);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen cache->fd = open(cache->filepath, O_RDWR);
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen if (cache->fd == -1) {
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen if (errno == ENOENT)
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen cache->need_compress = TRUE;
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen else
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen mail_cache_set_syscall_error(cache, "open()");
8ddc45fe2080010715c212ecbb2b12b6734f6d4bTimo Sirainen return -1;
8ddc45fe2080010715c212ecbb2b12b6734f6d4bTimo Sirainen }
8ddc45fe2080010715c212ecbb2b12b6734f6d4bTimo Sirainen
8ddc45fe2080010715c212ecbb2b12b6734f6d4bTimo Sirainen if (mail_cache_map(cache, 0, 0) < 0)
8ddc45fe2080010715c212ecbb2b12b6734f6d4bTimo Sirainen return -1;
8ddc45fe2080010715c212ecbb2b12b6734f6d4bTimo Sirainen
8ddc45fe2080010715c212ecbb2b12b6734f6d4bTimo Sirainen if (mail_cache_header_fields_read(cache) < 0)
8ddc45fe2080010715c212ecbb2b12b6734f6d4bTimo Sirainen return -1;
8ddc45fe2080010715c212ecbb2b12b6734f6d4bTimo Sirainen
8ddc45fe2080010715c212ecbb2b12b6734f6d4bTimo Sirainen if (cache->hdr->file_seq != cache->index->hdr->cache_file_seq) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* still different - maybe a race condition or maybe the
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen file_seq really is corrupted. either way, this shouldn't
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen happen often so we'll just mark cache to be compressed
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen later which fixes this. */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen cache->need_compress = TRUE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return 0;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return 1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstatic int mmap_verify_header(struct mail_cache *cache)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen const struct mail_cache_header *hdr;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* check that the header is still ok */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (cache->mmap_length < sizeof(struct mail_cache_header)) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mail_cache_set_corrupted(cache, "File too small");
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return FALSE;
cdf00df4dc5d0ae5acfdf200d2e846dbb92fda7eTimo Sirainen }
cdf00df4dc5d0ae5acfdf200d2e846dbb92fda7eTimo Sirainen cache->hdr = hdr = cache->mmap_base;
cdf00df4dc5d0ae5acfdf200d2e846dbb92fda7eTimo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (cache->hdr->version != MAIL_CACHE_VERSION) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* version changed - upgrade silently */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return FALSE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen if (cache->hdr->indexid != cache->index->indexid) {
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen /* index id changed */
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen mail_cache_set_corrupted(cache, "indexid changed");
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen return FALSE;
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen }
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen /* only check the header if we're locked */
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen if (cache->locked)
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen return TRUE;
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen if (hdr->used_file_size < sizeof(struct mail_cache_header)) {
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen mail_cache_set_corrupted(cache, "used_file_size too small");
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen return FALSE;
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen }
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen if ((hdr->used_file_size % sizeof(uint32_t)) != 0) {
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen mail_cache_set_corrupted(cache, "used_file_size not aligned");
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen return FALSE;
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen }
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen if (hdr->used_file_size > cache->mmap_length) {
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen mail_cache_set_corrupted(cache, "used_file_size too large");
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen return FALSE;
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return TRUE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainenint mail_cache_map(struct mail_cache *cache, size_t offset, size_t size)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (size == 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen size = sizeof(struct mail_cache_header);
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen if (offset < cache->mmap_length &&
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen size <= cache->mmap_length - offset) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* already mapped */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return 0;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (cache->mmap_base != NULL) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (munmap(cache->mmap_base, cache->mmap_length) < 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mail_cache_set_syscall_error(cache, "munmap()");
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen } else {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (cache->fd == -1) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* unusable, waiting for compression */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen i_assert(cache->need_compress);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* map the whole file */
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen cache->hdr = NULL;
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen cache->mmap_length = 0;
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen cache->mmap_base = mmap_ro_file(cache->fd, &cache->mmap_length);
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen if (cache->mmap_base == MAP_FAILED) {
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen cache->mmap_base = NULL;
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen mail_cache_set_syscall_error(cache, "mmap()");
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen return -1;
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen }
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen if (!mmap_verify_header(cache)) {
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen cache->need_compress = TRUE;
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen return -1;
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen }
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen return 0;
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen}
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstatic int mail_cache_open_and_verify(struct mail_cache *cache)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen cache->filepath = i_strconcat(cache->index->filepath,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen MAIL_CACHE_FILE_PREFIX, NULL);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen cache->fd = open(cache->filepath, O_RDWR);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (cache->fd == -1) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (errno == ENOENT) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen cache->need_compress = TRUE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return 0;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mail_cache_set_syscall_error(cache, "open()");
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen return -1;
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen }
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen
9ed77dd00248e88d731ec129116db5dddc0dd3b5Timo Sirainen if (mail_cache_map(cache, 0, sizeof(struct mail_cache_header)) < 0)
951c92a29c36d22a60e56cae4b47d5d0fa5dd6b5Timo Sirainen return -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return mail_cache_header_fields_read(cache);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstruct mail_cache *mail_cache_open_or_create(struct mail_index *index)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen struct mail_cache *cache;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen cache = i_new(struct mail_cache, 1);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen cache->index = index;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen cache->fd = -1;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen cache->field_pool = pool_alloconly_create("Cache fields", 1024);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen cache->field_name_hash =
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen hash_create(default_pool, cache->field_pool, 0,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen strcase_hash, (hash_cmp_callback_t *)strcasecmp);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (!index->mmap_disable && !index->mmap_no_write) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (mail_cache_open_and_verify(cache) < 0) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* failed for some reason - doesn't really matter,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen it's disabled for now. */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mail_cache_file_close(cache);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen }
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen return cache;
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen}
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainenvoid mail_cache_free(struct mail_cache *cache)
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen{
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen mail_cache_file_close(cache);
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen hash_destroy(cache->field_name_hash);
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen pool_unref(cache->field_pool);
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen i_free(cache->field_file_map);
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen i_free(cache->file_field_map);
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen i_free(cache->fields);
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen i_free(cache->filepath);
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen i_free(cache);
00bf64c70c231f647c12c2fd49925ef73cb07f07Timo Sirainen}
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainenint mail_cache_lock(struct mail_cache *cache)
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen{
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen unsigned int lock_id;
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen int i, ret;
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen i_assert(!cache->locked);
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache))
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen return 0;
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen if (mail_index_lock_shared(cache->index, TRUE, &lock_id) < 0)
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen return -1;
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen if (cache->hdr->file_seq != cache->index->hdr->cache_file_seq) {
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen /* we want the latest cache file */
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen if ((ret = mail_cache_reopen(cache)) <= 0) {
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen mail_index_unlock(cache->index, lock_id);
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen return ret;
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen }
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen }
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen for (i = 0; i < 3; i++) {
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen if ((ret = file_wait_lock(cache->fd, F_WRLCK)) <= 0) {
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen mail_cache_set_syscall_error(cache, "file_wait_lock()");
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen break;
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen }
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen cache->locked = TRUE;
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen if (cache->hdr->file_seq == cache->index->hdr->cache_file_seq) {
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen /* got it */
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen break;
7c3f90095b4168d89a268ac1ec820c5925d48fd3Timo Sirainen }
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen /* okay, so it was just compressed. try again. */
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen mail_cache_unlock(cache);
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen if ((ret = mail_cache_reopen(cache)) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen break;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen ret = 0;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (ret > 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen cache->hdr_copy = *cache->hdr;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen mail_index_unlock(cache->index, lock_id);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return ret;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstatic void mail_cache_update_need_compress(struct mail_cache *cache)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen const struct mail_cache_header *hdr = cache->hdr;
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen unsigned int cont_percentage;
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen uoff_t max_del_space;
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen cont_percentage = hdr->continued_record_count * 100 /
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen (cache->index->map->records_count == 0 ? 1 :
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen cache->index->map->records_count);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (cont_percentage >= COMPRESS_CONTINUED_PERCENTAGE &&
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen hdr->used_file_size >= COMPRESS_MIN_SIZE) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* too many continued rows, compress */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen cache->need_compress = TRUE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen /* see if we've reached the max. deleted space in file */
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen max_del_space = hdr->used_file_size / 100 * COMPRESS_PERCENTAGE;
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen if (hdr->deleted_space >= max_del_space &&
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen hdr->used_file_size >= COMPRESS_MIN_SIZE)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen cache->need_compress = TRUE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenvoid mail_cache_unlock(struct mail_cache *cache)
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen i_assert(cache->locked);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (cache->field_header_write_pending)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen (void)mail_cache_header_fields_update(cache);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen cache->locked = FALSE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (cache->hdr_modified) {
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen cache->hdr_modified = FALSE;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (pwrite_full(cache->fd, &cache->hdr_copy,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen sizeof(cache->hdr_copy), 0) < 0)
b1a2d2042e8c7e99983175eb462b82cc7a8cb70bTimo Sirainen mail_cache_set_syscall_error(cache, "pwrite_full()");
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mail_cache_update_need_compress(cache);
530f80fcbfa8be7378ff0d36ec7ecef41f198e2cTimo Sirainen }
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (file_wait_lock(cache->fd, F_UNLCK) <= 0)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen mail_cache_set_syscall_error(cache, "file_wait_lock(F_UNLCK)");
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenstruct mail_cache_view *
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenmail_cache_view_open(struct mail_cache *cache, struct mail_index_view *iview)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen struct mail_cache_view *view;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen view = i_new(struct mail_cache_view, 1);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen view->cache = cache;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen view->view = iview;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen view->offsets_buf =
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen buffer_create_dynamic(default_pool, 128, (size_t)-1);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen view->cached_exists_buf =
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen buffer_create_dynamic(default_pool,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen cache->file_fields_count + 10,
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen (size_t)-1);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen return view;
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainenvoid mail_cache_view_close(struct mail_cache_view *view)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen{
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen if (view->cache->field_header_write_pending)
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen (void)mail_cache_header_fields_update(view->cache);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen buffer_free(view->offsets_buf);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen buffer_free(view->cached_exists_buf);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen i_free(view);
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen}
e15b305e90c9834734ccf35ed78f0ad29d570ee9Timo Sirainen