mail-cache.c revision 1098fc409a45e7603701dc94635927a673bee0c1
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_cache_set_syscall_error(struct mail_cache *cache,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "%s failed with index cache file %s: %m",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_cache_set_corrupted(struct mail_cache *cache, const char *fmt, ...)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_set_error(cache->index, "Corrupted index cache file %s: %s",
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainenvoid mail_cache_file_close(struct mail_cache *cache)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (munmap(cache->mmap_base, cache->mmap_length) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_set_syscall_error(cache, "munmap()");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_set_syscall_error(cache, "close()");
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainenint mail_cache_reopen(struct mail_cache *cache)
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen if (MAIL_CACHE_IS_UNUSABLE(cache) && cache->need_compress) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen /* unusable, we're just waiting for compression */
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen mail_cache_set_syscall_error(cache, "open()");
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen file_cache_set_fd(cache->file_cache, cache->fd);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen ext = mail_index_view_get_ext(view, cache->ext_id);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (ext == NULL || cache->hdr->file_seq != ext->reset_id) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen /* still different - maybe a race condition or maybe the
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen file_seq really is corrupted. either way, this shouldn't
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen happen often so we'll just mark cache to be compressed
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen later which fixes this. */
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainenstatic int mail_cache_verify_header(struct mail_cache *cache)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen const struct mail_cache_header *hdr = cache->data;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* check that the header is still ok */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (cache->mmap_length < sizeof(struct mail_cache_header)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_set_corrupted(cache, "File too small");
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen if (cache->hdr->version != MAIL_CACHE_VERSION) {
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen /* version changed - upgrade silently */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (cache->hdr->indexid != cache->index->indexid) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* index id changed */
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen mail_cache_set_corrupted(cache, "indexid changed");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* only check the header if we're locked */
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen if (hdr->used_file_size < sizeof(struct mail_cache_header)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_set_corrupted(cache, "used_file_size too small");
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen if ((hdr->used_file_size % sizeof(uint32_t)) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_set_corrupted(cache, "used_file_size not aligned");
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen mail_cache_set_corrupted(cache, "used_file_size too large");
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainenint mail_cache_map(struct mail_cache *cache, size_t offset, size_t size)
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen ret = file_cache_read(cache->file_cache, offset, size);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen // FIXME: ESTALE
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen mail_cache_set_syscall_error(cache, "read()");
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen cache->data = file_cache_get_map(cache->file_cache,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (offset == 0 && !mail_cache_verify_header(cache)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* already mapped */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (munmap(cache->mmap_base, cache->mmap_length) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_set_syscall_error(cache, "munmap()");
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen /* unusable, waiting for compression */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* map the whole file */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cache->mmap_base = mmap_ro_file(cache->fd, &cache->mmap_length);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_set_syscall_error(cache, "mmap()");
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainenstatic int mail_cache_open_and_verify(struct mail_cache *cache)
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen cache->filepath = i_strconcat(cache->index->filepath,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (cache->index->mmap_disable || cache->index->mmap_no_write)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_cache_set_syscall_error(cache, "open()");
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen file_cache_set_fd(cache->file_cache, cache->fd);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (mail_cache_map(cache, 0, sizeof(struct mail_cache_header)) < 0)
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainenstruct mail_cache *mail_cache_open_or_create(struct mail_index *index)
befeac661293b8d4206118ac50b8be9751df8424Timo Sirainen cache->field_pool = pool_alloconly_create("Cache fields", 1024);
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen hash_create(default_pool, cache->field_pool, 0,
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen strcase_hash, (hash_cmp_callback_t *)strcasecmp);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen /* failed for some reason - doesn't really matter,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen it's disabled for now. */
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen mail_index_register_expunge_handler(index, cache->ext_id,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen mail_index_register_sync_handler(index, cache->ext_id,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (mail_index_view_open_locked(cache->index, &view) < 0)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen ext = mail_index_view_get_ext(view, cache->ext_id);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen /* cache not used */
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen /* we want the latest cache file */
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen for (i = 0; i < 3; i++) {
a53cb86b4d733d9c48ee4d285bed477c80825804Timo Sirainen ret = mail_index_lock_fd(cache->index, cache->fd, F_WRLCK,
a53cb86b4d733d9c48ee4d285bed477c80825804Timo Sirainen "mail_index_wait_lock_fd()");
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen /* okay, so it was just compressed. try again. */
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen /* make sure our header is up to date */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void mail_cache_update_need_compress(struct mail_cache *cache)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen const struct mail_cache_header *hdr = cache->hdr;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen cont_percentage = hdr->continued_record_count * 100 /
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (cont_percentage >= COMPRESS_CONTINUED_PERCENTAGE &&
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* too many continued rows, compress */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen /* see if we've reached the max. deleted space in file */
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen max_del_space = hdr->used_file_size / 100 * COMPRESS_PERCENTAGE;
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenvoid mail_cache_unlock(struct mail_cache *cache)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen mail_cache_set_syscall_error(cache, "pwrite_full()");
a53cb86b4d733d9c48ee4d285bed477c80825804Timo Sirainen if (mail_index_lock_fd(cache->index, cache->fd, F_UNLCK, 0) <= 0) {
a53cb86b4d733d9c48ee4d285bed477c80825804Timo Sirainen "mail_index_wait_lock_fd(F_UNLCK)");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmail_cache_view_open(struct mail_cache *cache, struct mail_index_view *iview)
4b058f90f9e8a2c6b2eed275de4eb8cc5195a71dTimo Sirainen view->offsets_buf = buffer_create_dynamic(default_pool, 128);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_cache_view_close(struct mail_cache_view *view)