mail-cache.c revision 114a0f74e0f825c6bd8aeadfafb248a030762a1f
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes/* Copyright (C) 2003-2004 Timo Sirainen */
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes#include "lib.h"
16b55a35cff91315d261d1baa776138af465c4e4fuankg#include "buffer.h"
16b55a35cff91315d261d1baa776138af465c4e4fuankg#include "hash.h"
16b55a35cff91315d261d1baa776138af465c4e4fuankg#include "file-cache.h"
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes#include "mmap-util.h"
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes#include "write-full.h"
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes#include "mail-cache-private.h"
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes#include <unistd.h>
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesvoid mail_cache_set_syscall_error(struct mail_cache *cache,
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg const char *function)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes{
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes i_assert(function != NULL);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (ENOSPACE(errno)) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache->index->nodiskspace = TRUE;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return;
0662ed52e814f8f08ef0e09956413a792584eddffuankg }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes mail_index_set_error(cache->index,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes "%s failed with index cache file %s: %m",
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes function, cache->filepath);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes}
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesvoid mail_cache_set_corrupted(struct mail_cache *cache, const char *fmt, ...)
16b55a35cff91315d261d1baa776138af465c4e4fuankg{
16b55a35cff91315d261d1baa776138af465c4e4fuankg va_list va;
16b55a35cff91315d261d1baa776138af465c4e4fuankg
16b55a35cff91315d261d1baa776138af465c4e4fuankg (void)unlink(cache->filepath);
16b55a35cff91315d261d1baa776138af465c4e4fuankg mail_cache_file_close(cache);
16b55a35cff91315d261d1baa776138af465c4e4fuankg
16b55a35cff91315d261d1baa776138af465c4e4fuankg va_start(va, fmt);
16b55a35cff91315d261d1baa776138af465c4e4fuankg t_push();
16b55a35cff91315d261d1baa776138af465c4e4fuankg mail_index_set_error(cache->index, "Corrupted index cache file %s: %s",
16b55a35cff91315d261d1baa776138af465c4e4fuankg cache->filepath, t_strdup_vprintf(fmt, va));
16b55a35cff91315d261d1baa776138af465c4e4fuankg t_pop();
16b55a35cff91315d261d1baa776138af465c4e4fuankg va_end(va);
16b55a35cff91315d261d1baa776138af465c4e4fuankg}
16b55a35cff91315d261d1baa776138af465c4e4fuankg
16b55a35cff91315d261d1baa776138af465c4e4fuankgvoid mail_cache_file_close(struct mail_cache *cache)
16b55a35cff91315d261d1baa776138af465c4e4fuankg{
16b55a35cff91315d261d1baa776138af465c4e4fuankg if (cache->mmap_base != NULL) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (munmap(cache->mmap_base, cache->mmap_length) < 0)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes mail_cache_set_syscall_error(cache, "munmap()");
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (cache->file_cache != NULL)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes file_cache_set_fd(cache->file_cache, -1);
16b55a35cff91315d261d1baa776138af465c4e4fuankg
16b55a35cff91315d261d1baa776138af465c4e4fuankg cache->mmap_base = NULL;
16b55a35cff91315d261d1baa776138af465c4e4fuankg cache->data = NULL;
16b55a35cff91315d261d1baa776138af465c4e4fuankg cache->hdr = NULL;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache->mmap_length = 0;
6f99e6278481df33e006c428d3d6de68a1ecd5d5fuankg
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (cache->fd != -1) {
16b55a35cff91315d261d1baa776138af465c4e4fuankg if (close(cache->fd) < 0)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes mail_cache_set_syscall_error(cache, "close()");
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache->fd = -1;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes}
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesint mail_cache_reopen(struct mail_cache *cache)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes{
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct mail_index_view *view;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes const struct mail_index_ext *ext;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (MAIL_CACHE_IS_UNUSABLE(cache) && cache->need_compress) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes /* unusable, we're just waiting for compression */
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return 0;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes mail_cache_file_close(cache);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache->fd = open(cache->filepath, O_RDWR);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (cache->fd == -1) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (errno == ENOENT)
16b55a35cff91315d261d1baa776138af465c4e4fuankg cache->need_compress = TRUE;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes else
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes mail_cache_set_syscall_error(cache, "open()");
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return -1;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (cache->file_cache != NULL)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes file_cache_set_fd(cache->file_cache, cache->fd);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (mail_cache_map(cache, 0, 0) < 0)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return -1;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (mail_cache_header_fields_read(cache) < 0)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return -1;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes view = mail_index_view_open(cache->index);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes ext = mail_index_view_get_ext(view, cache->ext_id);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (ext == NULL || cache->hdr->file_seq != ext->reset_id) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes /* still different - maybe a race condition or maybe the
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes file_seq really is corrupted. either way, this shouldn't
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes happen often so we'll just mark cache to be compressed
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes later which fixes this. */
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache->need_compress = TRUE;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes mail_index_view_close(view);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return 0;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes mail_index_view_close(view);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return 1;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes}
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesstatic int mail_cache_verify_header(struct mail_cache *cache)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes{
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes const struct mail_cache_header *hdr = cache->data;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes /* check that the header is still ok */
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (cache->mmap_length < sizeof(struct mail_cache_header)) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes mail_cache_set_corrupted(cache, "File too small");
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return FALSE;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (cache->hdr->version != MAIL_CACHE_VERSION) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes /* version changed - upgrade silently */
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return FALSE;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (cache->hdr->indexid != cache->index->indexid) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes /* index id changed */
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes mail_cache_set_corrupted(cache, "indexid changed");
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return FALSE;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes /* only check the header if we're locked */
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (!cache->locked)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return TRUE;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (hdr->used_file_size < sizeof(struct mail_cache_header)) {
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg mail_cache_set_corrupted(cache, "used_file_size too small");
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return FALSE;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
16b55a35cff91315d261d1baa776138af465c4e4fuankg if ((hdr->used_file_size % sizeof(uint32_t)) != 0) {
16b55a35cff91315d261d1baa776138af465c4e4fuankg mail_cache_set_corrupted(cache, "used_file_size not aligned");
16b55a35cff91315d261d1baa776138af465c4e4fuankg return FALSE;
b387b9d37fc71c534f4718777454a8f5a1169017fuankg }
16b55a35cff91315d261d1baa776138af465c4e4fuankg
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (cache->mmap_base != NULL &&
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes hdr->used_file_size > cache->mmap_length) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes mail_cache_set_corrupted(cache, "used_file_size too large");
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return FALSE;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
0b2a6b63977ab27352a0b525bdad1e1982a1c0b1bnicholes return TRUE;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes}
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
ac7985784d08a3655291f24f711812b4d8b1cbcffuankgint mail_cache_map(struct mail_cache *cache, size_t offset, size_t size)
0662ed52e814f8f08ef0e09956413a792584eddffuankg{
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes ssize_t ret;
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (size == 0)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes size = sizeof(struct mail_cache_header);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (cache->file_cache != NULL) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache->data = NULL;
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg cache->hdr = NULL;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes ret = file_cache_read(cache->file_cache, offset, size);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (ret < 0) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes // FIXME: ESTALE
0662ed52e814f8f08ef0e09956413a792584eddffuankg mail_cache_set_syscall_error(cache, "read()");
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return -1;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache->data = file_cache_get_map(cache->file_cache,
0662ed52e814f8f08ef0e09956413a792584eddffuankg &cache->mmap_length);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache->hdr = cache->data;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (offset == 0 && !mail_cache_verify_header(cache)) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache->need_compress = TRUE;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return -1;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return 0;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
0662ed52e814f8f08ef0e09956413a792584eddffuankg if (offset < cache->mmap_length &&
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg size <= cache->mmap_length - offset) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes /* already mapped */
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg return 0;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (cache->mmap_base != NULL) {
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg if (munmap(cache->mmap_base, cache->mmap_length) < 0)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes mail_cache_set_syscall_error(cache, "munmap()");
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes } else {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (cache->fd == -1) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes /* unusable, waiting for compression */
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes i_assert(cache->need_compress);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return -1;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
0b2a6b63977ab27352a0b525bdad1e1982a1c0b1bnicholes /* map the whole file */
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache->hdr = NULL;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache->mmap_length = 0;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache->mmap_base = mmap_ro_file(cache->fd, &cache->mmap_length);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (cache->mmap_base == MAP_FAILED) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache->mmap_base = NULL;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache->data = NULL;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes mail_cache_set_syscall_error(cache, "mmap()");
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return -1;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache->data = cache->mmap_base;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache->hdr = cache->mmap_base;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (!mail_cache_verify_header(cache)) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache->need_compress = TRUE;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return -1;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return 0;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes}
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesstatic int mail_cache_open_and_verify(struct mail_cache *cache)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes{
16b55a35cff91315d261d1baa776138af465c4e4fuankg cache->filepath = i_strconcat(cache->index->filepath,
16b55a35cff91315d261d1baa776138af465c4e4fuankg MAIL_CACHE_FILE_PREFIX, NULL);
16b55a35cff91315d261d1baa776138af465c4e4fuankg
16b55a35cff91315d261d1baa776138af465c4e4fuankg if (cache->index->mmap_disable || cache->index->mmap_no_write)
16b55a35cff91315d261d1baa776138af465c4e4fuankg cache->file_cache = file_cache_new(-1);
16b55a35cff91315d261d1baa776138af465c4e4fuankg
16b55a35cff91315d261d1baa776138af465c4e4fuankg cache->fd = open(cache->filepath, O_RDWR);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (cache->fd == -1) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (errno == ENOENT) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache->need_compress = TRUE;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return 0;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes mail_cache_set_syscall_error(cache, "open()");
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return -1;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
16b55a35cff91315d261d1baa776138af465c4e4fuankg
16b55a35cff91315d261d1baa776138af465c4e4fuankg if (cache->file_cache != NULL)
16b55a35cff91315d261d1baa776138af465c4e4fuankg file_cache_set_fd(cache->file_cache, cache->fd);
16b55a35cff91315d261d1baa776138af465c4e4fuankg
16b55a35cff91315d261d1baa776138af465c4e4fuankg if (mail_cache_map(cache, 0, sizeof(struct mail_cache_header)) < 0)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return -1;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return mail_cache_header_fields_read(cache);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes}
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesstruct mail_cache *mail_cache_open_or_create(struct mail_index *index)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes{
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct mail_cache *cache;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache = i_new(struct mail_cache, 1);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache->index = index;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache->fd = -1;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache->field_pool = pool_alloconly_create("Cache fields", 1024);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes cache->field_name_hash =
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes hash_create(default_pool, cache->field_pool, 0,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes strcase_hash, (hash_cmp_callback_t *)strcasecmp);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (mail_cache_open_and_verify(cache) < 0) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes /* failed for some reason - doesn't really matter,
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes it's disabled for now. */
8ffac2c334103c0336602aaede650cb578611151fuankg mail_cache_file_close(cache);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg cache->ext_id =
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes mail_index_ext_register(index, "cache", 0,
16b55a35cff91315d261d1baa776138af465c4e4fuankg sizeof(uint32_t), sizeof(uint32_t));
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes mail_index_register_expunge_handler(index, cache->ext_id,
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg mail_cache_expunge_handler);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes mail_index_register_sync_handler(index, cache->ext_id,
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg mail_cache_sync_handler);
16b55a35cff91315d261d1baa776138af465c4e4fuankg return cache;
16b55a35cff91315d261d1baa776138af465c4e4fuankg}
16b55a35cff91315d261d1baa776138af465c4e4fuankg
16b55a35cff91315d261d1baa776138af465c4e4fuankgvoid mail_cache_free(struct mail_cache *cache)
16b55a35cff91315d261d1baa776138af465c4e4fuankg{
16b55a35cff91315d261d1baa776138af465c4e4fuankg if (cache->file_cache != NULL) {
16b55a35cff91315d261d1baa776138af465c4e4fuankg file_cache_free(cache->file_cache);
16b55a35cff91315d261d1baa776138af465c4e4fuankg cache->file_cache = NULL;
16b55a35cff91315d261d1baa776138af465c4e4fuankg }
16b55a35cff91315d261d1baa776138af465c4e4fuankg
16b55a35cff91315d261d1baa776138af465c4e4fuankg mail_cache_file_close(cache);
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes hash_destroy(cache->field_name_hash);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes pool_unref(cache->field_pool);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes i_free(cache->field_file_map);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes i_free(cache->file_field_map);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes i_free(cache->fields);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes i_free(cache->filepath);
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg i_free(cache);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes}
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholesint mail_cache_lock(struct mail_cache *cache)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes{
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes struct mail_index_view *view;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes const struct mail_index_ext *ext;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes int i, ret;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes i_assert(!cache->locked);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (MAIL_CACHE_IS_UNUSABLE(cache))
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return 0;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (mail_index_view_open_locked(cache->index, &view) < 0)
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return -1;
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg
0662ed52e814f8f08ef0e09956413a792584eddffuankg ext = mail_index_view_get_ext(view, cache->ext_id);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (ext == NULL) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes /* cache not used */
e097a47d2f32eaf74a6130e6fadfa3e24b8cb2effuankg mail_index_view_close(view);
e097a47d2f32eaf74a6130e6fadfa3e24b8cb2effuankg return 0;
e097a47d2f32eaf74a6130e6fadfa3e24b8cb2effuankg }
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (cache->hdr->file_seq != ext->reset_id) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes /* we want the latest cache file */
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if ((ret = mail_cache_reopen(cache)) <= 0) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes mail_index_view_close(view);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes return ret;
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes }
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes for (i = 0; i < 3; i++) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes ret = mail_index_lock_fd(cache->index, cache->fd, F_WRLCK,
0662ed52e814f8f08ef0e09956413a792584eddffuankg MAIL_INDEX_LOCK_SECS);
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes if (ret <= 0) {
e76fdcdfb8994ad70776526f50fa013b3e9a6033bnicholes mail_cache_set_syscall_error(cache,
"mail_index_wait_lock_fd()");
break;
}
cache->locked = TRUE;
if (cache->hdr->file_seq == ext->reset_id) {
/* got it */
break;
}
/* okay, so it was just compressed. try again. */
mail_cache_unlock(cache);
if ((ret = mail_cache_reopen(cache)) <= 0)
break;
ret = 0;
}
if (ret > 0) {
/* make sure our header is up to date */
if (cache->file_cache != NULL) {
file_cache_invalidate(cache->file_cache, 0,
sizeof(struct mail_cache_header));
}
if (mail_cache_map(cache, 0, 0) < 0)
ret = -1;
cache->hdr_copy = *cache->hdr;
}
mail_index_view_close(view);
return ret;
}
static void mail_cache_update_need_compress(struct mail_cache *cache)
{
const struct mail_cache_header *hdr = cache->hdr;
unsigned int cont_percentage;
uoff_t max_del_space;
cont_percentage = hdr->continued_record_count * 100 /
(cache->index->map->records_count == 0 ? 1 :
cache->index->map->records_count);
if (cont_percentage >= COMPRESS_CONTINUED_PERCENTAGE &&
hdr->used_file_size >= COMPRESS_MIN_SIZE) {
/* too many continued rows, compress */
cache->need_compress = TRUE;
}
/* see if we've reached the max. deleted space in file */
max_del_space = hdr->used_file_size / 100 * COMPRESS_PERCENTAGE;
if (hdr->deleted_space >= max_del_space &&
hdr->used_file_size >= COMPRESS_MIN_SIZE)
cache->need_compress = TRUE;
}
void mail_cache_unlock(struct mail_cache *cache)
{
i_assert(cache->locked);
if (cache->field_header_write_pending)
(void)mail_cache_header_fields_update(cache);
cache->locked = FALSE;
if (cache->hdr_modified) {
cache->hdr_modified = FALSE;
if (pwrite_full(cache->fd, &cache->hdr_copy,
sizeof(cache->hdr_copy), 0) < 0)
mail_cache_set_syscall_error(cache, "pwrite_full()");
mail_cache_update_need_compress(cache);
}
if (mail_index_lock_fd(cache->index, cache->fd, F_UNLCK, 0) <= 0) {
mail_cache_set_syscall_error(cache,
"mail_index_wait_lock_fd(F_UNLCK)");
}
}
struct mail_cache_view *
mail_cache_view_open(struct mail_cache *cache, struct mail_index_view *iview)
{
struct mail_cache_view *view;
view = i_new(struct mail_cache_view, 1);
view->cache = cache;
view->view = iview;
view->offsets_buf = buffer_create_dynamic(default_pool, 128);
view->cached_exists_buf =
buffer_create_dynamic(default_pool,
cache->file_fields_count + 10);
return view;
}
void mail_cache_view_close(struct mail_cache_view *view)
{
if (view->cache->field_header_write_pending)
(void)mail_cache_header_fields_update(view->cache);
if (view->trans_view != NULL)
mail_index_view_close(view->trans_view);
buffer_free(view->offsets_buf);
buffer_free(view->cached_exists_buf);
i_free(view);
}