mail-index-alloc-cache.c revision 04dff721d2a63566a4dbe1c856f8218b6550aa3e
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "lib.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "ioloop.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "module-context.h"
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen#include "eacces-error.h"
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen#include "mail-index-private.h"
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen#include "mail-index-alloc-cache.h"
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen#define MAIL_INDEX_ALLOC_CACHE_CONTEXT(obj) \
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen MODULE_CONTEXT(obj, mail_index_alloc_cache_index_module)
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen/* How many seconds to keep index opened for reuse after it's been closed */
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen#define INDEX_CACHE_TIMEOUT 10
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen/* How many closed indexes to keep */
dff32d11a411a24f3b76003c1ae22c5a960f180eTimo Sirainen#define INDEX_CACHE_MAX 3
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainenstruct mail_index_alloc_cache_list {
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen union mail_index_module_context module_ctx;
eb209d12e3b1cfed564c35cf19fdb1bf7fcc6811Timo Sirainen struct mail_index_alloc_cache_list *next;
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen
09060303d565e15d54e42b4ef722f9d3c26f5336Timo Sirainen struct mail_index *index;
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen char *mailbox_path;
a5ddfd7a8b473f73135b93d5e081e470a87f0f7eTimo Sirainen int refcount;
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen
ae32667c54480d329eed994b3defab89cd76c077Timo Sirainen dev_t index_dir_dev;
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen ino_t index_dir_ino;
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen time_t destroy_time;
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen};
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(mail_index_alloc_cache_index_module,
8c2b4a45f17a5cb13bb01058ca37798cf48d91baTimo Sirainen &mail_index_module_register);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic struct mail_index_alloc_cache_list *indexes = NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic struct timeout *to_index = NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomistatic struct mail_index_alloc_cache_list *
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenmail_index_alloc_cache_add(struct mail_index *index,
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen const char *mailbox_path, struct stat *st)
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen{
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen struct mail_index_alloc_cache_list *list;
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen list = i_new(struct mail_index_alloc_cache_list, 1);
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen list->refcount = 1;
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen list->index = index;
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen list->mailbox_path = i_strdup(mailbox_path);
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen list->index_dir_dev = st->st_dev;
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen list->index_dir_ino = st->st_ino;
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen list->next = indexes;
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen indexes = list;
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen MODULE_CONTEXT_SET(index, mail_index_alloc_cache_index_module, list);
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen return list;
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen}
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainenstatic void
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainenmail_index_alloc_cache_list_free(struct mail_index_alloc_cache_list *list)
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen{
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen mail_index_free(&list->index);
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen i_free(list->mailbox_path);
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen i_free(list);
c13fce16374a6fa8d127742c527498d38e777789Timo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstruct mail_index *
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainenmail_index_alloc_cache_get(const char *mailbox_path,
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen const char *index_dir, const char *prefix)
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen{
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen struct mail_index_alloc_cache_list **indexp, *rec, *match;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen struct stat st, st2;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen unsigned int destroy_count;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen /* compare index_dir inodes so we don't break even with symlinks.
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen if index_dir doesn't exist yet or if using in-memory indexes, just
b44033e45e9f48f8a6e1ac5905234fec5de6d6ccAki Tuomi compare mailbox paths */
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen memset(&st, 0, sizeof(st));
b93ec4e5b569e1216d0c7a6f28cbdccfe4fb32caTimo Sirainen if (index_dir == NULL) {
cdc7ca129c3433d3e4b9d5e90f4c209e4546dfe9Timo Sirainen /* in-memory indexes */
cdc7ca129c3433d3e4b9d5e90f4c209e4546dfe9Timo Sirainen } else if (stat(index_dir, &st) < 0) {
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen if (errno == ENOENT) {
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen /* it'll be created later */
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen } else if (errno == EACCES) {
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen i_error("%s", eacces_error_get("stat", index_dir));
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen } else {
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen i_error("stat(%s) failed: %m", index_dir);
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen }
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen }
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen destroy_count = 0; match = NULL;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen for (indexp = &indexes; *indexp != NULL;) {
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen rec = *indexp;
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen if (match != NULL) {
1b7cd57585d8c2f133dd612d2d5d9c775595659fTimo Sirainen /* already found the index. we're just going through
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen the rest of them to drop 0 refcounts */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } else if (rec->refcount == 0 && rec->index->open_count == 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* index is already closed. don't even try to
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen reuse it. */
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } else if (index_dir != NULL && rec->index_dir_ino != 0) {
009217abb57a24a4076092e8e4e165545747839eStephan Bosch if (st.st_ino == rec->index_dir_ino &&
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen CMP_DEV_T(st.st_dev, rec->index_dir_dev)) {
009217abb57a24a4076092e8e4e165545747839eStephan Bosch /* make sure the directory still exists.
00e7c3010f7da4a49881a7feb05e413af353af0aTimo Sirainen it might have been renamed and we're trying
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen to access it via its new path now. */
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen if (stat(rec->index->dir, &st2) < 0 ||
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen st2.st_ino != st.st_ino ||
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen !CMP_DEV_T(st2.st_dev, st.st_dev))
5f5713d6468dca1acf3d350dd8a33057331f78c5Timo Sirainen rec->destroy_time = 0;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen else
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen match = rec;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen } else {
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen if (strcmp(mailbox_path, rec->mailbox_path) == 0)
3ee8a7ee6912c7caa4e83d3ce5a5db1590a7ffcdTimo Sirainen match = rec;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen
cf9d67e4a9bfee31cf3be05244555d51a3d1b9feTimo Sirainen if (rec->refcount == 0 && rec != match) {
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen if (rec->destroy_time <= ioloop_time ||
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen destroy_count >= INDEX_CACHE_MAX) {
edd318d5866ac3fbc6e8df28fb24a4dfef93c884Timo Sirainen *indexp = rec->next;
d3bae1f9d2448e5c398145ea250849ec12583845Timo Sirainen mail_index_alloc_cache_list_free(rec);
d3bae1f9d2448e5c398145ea250849ec12583845Timo Sirainen continue;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } else {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen destroy_count++;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen indexp = &(*indexp)->next;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (match == NULL) {
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen struct mail_index *index = mail_index_alloc(index_dir, prefix);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen match = mail_index_alloc_cache_add(index, mailbox_path, &st);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen } else {
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen match->refcount++;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
58b8a301b7b36047f10a592751094fbed86d6f0cTimo Sirainen i_assert(match->index != NULL);
58b8a301b7b36047f10a592751094fbed86d6f0cTimo Sirainen return match->index;
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen}
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainenstatic void destroy_unrefed(bool all)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen struct mail_index_alloc_cache_list **list, *rec;
89d6cd658eabf46e07e40037b0e641ed9be1a2a3Timo Sirainen
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen for (list = &indexes; *list != NULL;) {
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen rec = *list;
ece0a20249ce26208db3415ba2e79423678856f8Timo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen if (rec->refcount == 0 &&
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen (all || rec->destroy_time <= ioloop_time)) {
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen *list = rec->next;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen mail_index_alloc_cache_list_free(rec);
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen } else {
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen list = &(*list)->next;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen }
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen if (indexes == NULL && to_index != NULL)
1df39b899804fd1dbc560f75382364822935c857Timo Sirainen timeout_remove(&to_index);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenstatic void index_removal_timeout(void *context ATTR_UNUSED)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen destroy_unrefed(FALSE);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen}
009217abb57a24a4076092e8e4e165545747839eStephan Bosch
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainenvoid mail_index_alloc_cache_unref(struct mail_index **_index)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
c4900d31385344bfadaee53a897daeafdb3063d8Timo Sirainen struct mail_index *index = *_index;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen struct mail_index_alloc_cache_list *list, **listp;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen *_index = NULL;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen list = NULL;
4aab01f4eade3d278b61471516c062ce30a84b5fTimo Sirainen for (listp = &indexes; *listp != NULL; listp = &(*listp)->next) {
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen if ((*listp)->index == index) {
152db3f90f298b7fb2dbbd4276f0fc30a9bc30f6Timo Sirainen list = *listp;
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen break;
aa797403d51ff047727b77d64532001d6b6cc21aTimo Sirainen }
468c28dfb03613ab8d487b5aebc985a969193aceTimo Sirainen }
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen
433f5c9cc560a8cbff47257513d0bacb1cf250f4Timo Sirainen i_assert(list != NULL);
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen i_assert(list->refcount > 0);
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
027f58ea63a1822bbf13d99ee5572e5f8b9e8d8bTimo Sirainen list->refcount--;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen list->destroy_time = ioloop_time + INDEX_CACHE_TIMEOUT;
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen
e4194f4703eeec32b432371ae30fc8f25ab720d8Timo Sirainen if (list->refcount == 0 && index->open_count == 0) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen /* index was already closed. don't even try to cache it. */
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen *listp = list->next;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen mail_index_alloc_cache_list_free(list);
abe29107f5dce932d28a00912d2d75a01021bef1Timo Sirainen } else if (to_index == NULL) {
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen to_index = timeout_add(INDEX_CACHE_TIMEOUT*1000/2,
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen index_removal_timeout, NULL);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen }
5e9bb72de1209cd39fdf3e95bdb26e047cc5594eTimo Sirainen}
0a53eb0283d7ec28c6105f61e118b96fce8ecb95Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenvoid mail_index_alloc_cache_destroy_unrefed(void)
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen{
2670cd577aa57eb9f915a4f4220ae48c9b4fc5fbTimo Sirainen destroy_unrefed(TRUE);
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainen}
ab779efe68458cf6fdcaa4f99527685d5563df0aTimo Sirainen
b6b9c99fefbbc662bd9a0006566133c4480bf0e8Timo Sirainenvoid mail_index_alloc_cache_index_opened(struct mail_index *index)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen{
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen struct mail_index_alloc_cache_list *list =
15ab2452b0220a115f4351ad9d7fd5ec70ae7966Timo Sirainen MAIL_INDEX_ALLOC_CACHE_CONTEXT(index);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen struct stat st;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen if (list != NULL && list->index_dir_ino == 0 &&
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen !MAIL_INDEX_IS_IN_MEMORY(index)) {
550d2fe097e95f12e8fa60ef52753ea7fe53d4eaTimo Sirainen /* newly created index directory. update its stat. */
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen if (stat(index->dir, &st) == 0) {
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen list->index_dir_ino = st.st_ino;
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen list->index_dir_dev = st.st_dev;
bfef6891565ff9018ac92add6eae401e9352c657Timo Sirainen }
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen }
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen}
36e091dc733c6cd690c5aae6e411e41adb1eca73Timo Sirainen