mail-index-alloc-cache.c revision e10d8b1291090c26b9ef499637e6e632485ca5be
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen#include "lib.h"
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen#include "ioloop.h"
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen#include "module-context.h"
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen#include "eacces-error.h"
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen#include "mail-index-private.h"
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen#include "mail-index-alloc-cache.h"
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen#define MAIL_INDEX_ALLOC_CACHE_CONTEXT(obj) \
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen MODULE_CONTEXT(obj, mail_index_alloc_cache_index_module)
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen/* How many seconds to keep index opened for reuse after it's been closed */
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen#define INDEX_CACHE_TIMEOUT 10
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen/* How many closed indexes to keep */
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen#define INDEX_CACHE_MAX 3
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainenstruct mail_index_alloc_cache_list {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen union mail_index_module_context module_ctx;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen struct mail_index_alloc_cache_list *next;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen struct mail_index *index;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen char *mailbox_path;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen int refcount;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen dev_t index_dir_dev;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen ino_t index_dir_ino;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen time_t destroy_time;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen};
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(mail_index_alloc_cache_index_module,
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen &mail_index_module_register);
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainenstatic struct mail_index_alloc_cache_list *indexes = NULL;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainenstatic struct timeout *to_index = NULL;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainenstatic struct mail_index_alloc_cache_list *
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainenmail_index_alloc_cache_add(struct mail_index *index,
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen const char *mailbox_path, struct stat *st)
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen{
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen struct mail_index_alloc_cache_list *list;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen list = i_new(struct mail_index_alloc_cache_list, 1);
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen list->refcount = 1;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen list->index = index;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen list->mailbox_path = i_strdup(mailbox_path);
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen list->index_dir_dev = st->st_dev;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen list->index_dir_ino = st->st_ino;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen list->next = indexes;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen indexes = list;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen MODULE_CONTEXT_SET(index, mail_index_alloc_cache_index_module, list);
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen return list;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen}
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainenstatic void
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainenmail_index_alloc_cache_list_free(struct mail_index_alloc_cache_list *list)
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen{
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen mail_index_free(&list->index);
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen i_free(list->mailbox_path);
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen i_free(list);
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen}
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainenstruct mail_index *
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainenmail_index_alloc_cache_get(const char *mailbox_path,
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen const char *index_dir, const char *prefix)
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen{
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen struct mail_index_alloc_cache_list **indexp, *rec, *match;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen struct stat st, st2;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen unsigned int destroy_count;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen /* compare index_dir inodes so we don't break even with symlinks.
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen if index_dir doesn't exist yet or if using in-memory indexes, just
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen compare mailbox paths */
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen memset(&st, 0, sizeof(st));
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen if (index_dir == NULL) {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen /* in-memory indexes */
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen } else if (stat(index_dir, &st) < 0) {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen if (errno == ENOENT) {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen /* it'll be created later */
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen } else if (errno == EACCES) {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen i_error("%s", eacces_error_get("stat", index_dir));
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen } else {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen i_error("stat(%s) failed: %m", index_dir);
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen }
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen }
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen destroy_count = 0; match = NULL;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen for (indexp = &indexes; *indexp != NULL;) {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen rec = *indexp;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen if (match != NULL) {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen /* already found the index. we're just going through
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen the rest of them to drop 0 refcounts */
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen } else if (index_dir != NULL && rec->index_dir_ino != 0) {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen if (st.st_ino == rec->index_dir_ino &&
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen CMP_DEV_T(st.st_dev, rec->index_dir_dev)) {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen /* make sure the directory still exists.
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen it might have been renamed and we're trying
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen to access it via its new path now. */
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen if (stat(rec->index->dir, &st2) < 0 ||
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen st2.st_ino != st.st_ino ||
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen !CMP_DEV_T(st2.st_dev, st.st_dev))
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen rec->destroy_time = 0;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen else
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen match = rec;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen }
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen } else {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen if (strcmp(mailbox_path, rec->mailbox_path) == 0)
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen match = rec;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen }
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen if (rec->refcount == 0 && rec != match) {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen if (rec->destroy_time <= ioloop_time ||
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen destroy_count >= INDEX_CACHE_MAX) {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen *indexp = rec->next;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen mail_index_alloc_cache_list_free(rec);
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen continue;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen } else {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen destroy_count++;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen }
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen }
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen indexp = &(*indexp)->next;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen }
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen if (match == NULL) {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen struct mail_index *index = mail_index_alloc(index_dir, prefix);
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen match = mail_index_alloc_cache_add(index, mailbox_path, &st);
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen } else {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen match->refcount++;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen }
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen i_assert(match->index != NULL);
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen return match->index;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen}
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainenstatic void destroy_unrefed(bool all)
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen{
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen struct mail_index_alloc_cache_list **list, *rec;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen for (list = &indexes; *list != NULL;) {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen rec = *list;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen if (rec->refcount == 0 &&
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen (all || rec->destroy_time <= ioloop_time)) {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen *list = rec->next;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen mail_index_alloc_cache_list_free(rec);
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen } else {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen list = &(*list)->next;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen }
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen }
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen if (indexes == NULL && to_index != NULL)
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen timeout_remove(&to_index);
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen}
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainenstatic void index_removal_timeout(void *context ATTR_UNUSED)
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen{
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen destroy_unrefed(FALSE);
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen}
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainenvoid mail_index_alloc_cache_unref(struct mail_index **_index)
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen{
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen struct mail_index *index = *_index;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen struct mail_index_alloc_cache_list *list;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
e10d8b1291090c26b9ef499637e6e632485ca5beTimo Sirainen *_index = NULL;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen for (list = indexes; list != NULL; list = list->next) {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen if (list->index == index)
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen break;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen }
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen i_assert(list != NULL);
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen i_assert(list->refcount > 0);
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen list->refcount--;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen list->destroy_time = ioloop_time + INDEX_CACHE_TIMEOUT;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen if (to_index == NULL) {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen to_index = timeout_add(INDEX_CACHE_TIMEOUT*1000/2,
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen index_removal_timeout, NULL);
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen }
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen}
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainenvoid mail_index_alloc_cache_destroy_unrefed(void)
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen{
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen destroy_unrefed(TRUE);
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen}
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainenvoid mail_index_alloc_cache_index_opened(struct mail_index *index)
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen{
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen struct mail_index_alloc_cache_list *list =
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen MAIL_INDEX_ALLOC_CACHE_CONTEXT(index);
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen struct stat st;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen if (list != NULL && list->index_dir_ino == 0 &&
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen !MAIL_INDEX_IS_IN_MEMORY(index)) {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen /* newly created index directory. update its stat. */
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen if (stat(index->dir, &st) == 0) {
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen list->index_dir_ino = st.st_ino;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen list->index_dir_dev = st.st_dev;
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen }
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen }
ac26a4607cb12b156f6a42f1ead2881bedd43d94Timo Sirainen}