mail-cache.c revision f81801789c71f64a2fc3c44d09f9864bbc68cd45
/* Copyright (c) 2003-2012 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "array.h"
#include "buffer.h"
#include "hash.h"
#include "nfs-workarounds.h"
#include "file-cache.h"
#include "mmap-util.h"
#include "read-full.h"
#include "write-full.h"
#include "mail-cache-private.h"
#include <unistd.h>
const char *function)
{
function);
}
{
}
{
/* mark the cache as unusable */
}
{
T_BEGIN {
"Corrupted index cache file %s: %s",
} T_END;
}
{
}
cache->mmap_length = 0;
}
}
{
return;
else if (!ESTALE_FSTAT(errno))
}
{
if (MAIL_CACHE_IS_UNUSABLE(cache)) {
if (cache->need_compress_file_seq != 0) {
/* we're waiting for compression */
return FALSE;
}
/* disabled */
return FALSE;
}
}
return TRUE;
/* see if the file has changed */
}
return TRUE;
}
/* file changed */
return TRUE;
}
/* if the old file has been deleted, the new file may have
the same inode as the old one. we'll catch this here by
checking if fstat() fails with ESTALE */
if (ESTALE_FSTAT(errno))
return TRUE;
return FALSE;
}
}
return FALSE;
}
{
struct mail_index_view *view;
const struct mail_index_ext *ext;
const void *data;
if (!mail_cache_need_reopen(cache)) {
/* reopening does no good */
return 0;
}
cache->need_compress_file_seq = 0;
else
return -1;
}
return -1;
if (mail_cache_header_fields_read(cache) < 0)
return -1;
/* still different - maybe a race condition or maybe the
file_seq really is corrupted. either way, this shouldn't
happen often so we'll just mark cache to be compressed
later which fixes this. */
return 0;
}
return 1;
}
{
unsigned int cont_percentage;
/* too many continued rows, compress */
}
/* see if we've reached the max. deleted space in file */
}
const struct mail_cache_header *hdr)
{
/* check that the header is still ok */
return FALSE;
}
/* version changed - upgrade silently */
return FALSE;
}
/* architecture change - handle silently(?) */
return FALSE;
}
/* index id changed - handle silently */
return FALSE;
}
return FALSE;
}
/* only check the header if we're locked */
return TRUE;
return FALSE;
}
return FALSE;
}
return FALSE;
}
return TRUE;
}
static int
{
if (offset == 0) {
/* verify the header validity only with offset=0. this way
we won't waste time re-verifying it all the time */
return -1;
}
}
if (!copy_hdr)
else {
sizeof(cache->hdr_ro_copy));
}
} else {
}
return 0;
return 1;
}
static int
const void **data_r)
{
const void *hdr_data;
void *data;
/* already mapped */
} else {
}
if (ret < 0) {
cache->mmap_length = 0;
return -1;
}
}
const void **data_r)
{
const void *data;
if (size == 0)
size = sizeof(struct mail_cache_header);
cache->remap_counter++;
if (cache->map_with_read)
if (ret < 0) {
/* In case of ESTALE we'll simply fail without error
messages. The caller will then just have to
fallback to generating the value itself.
We can't simply reopen the cache flie, because
using it requires also having updated file
offsets. */
return -1;
}
&cache->mmap_length);
}
/* already mapped */
return 1;
}
} else {
/* unusable, waiting for compression or
index is in memory */
return -1;
}
}
/* map the whole file */
cache->mmap_length = 0;
return -1;
}
}
{
const void *data;
return 0;
cache->need_compress_file_seq = 0;
return 0;
}
return -1;
}
&data) < 0)
return -1;
return 1;
}
{
int ret;
if (ret > 0)
if (ret < 0) {
/* failed for some reason - doesn't really matter,
it's disabled for now. */
}
return ret;
}
{
struct mail_cache *cache;
if (!MAIL_INDEX_IS_IN_MEMORY(index) &&
}
return cache;
}
{
struct mail_cache *cache;
return cache;
}
{
struct mail_cache *cache;
if (!MAIL_INDEX_IS_IN_MEMORY(index)) {
}
return cache;
}
{
}
}
{
unsigned int timeout_secs;
int ret;
if (cache->last_lock_failed) {
/* previous locking failed. don't waste time waiting on it
again, just try once to see if it's available now. */
}
nonblock ? 0 : timeout_secs,
} else {
enum dotlock_create_flags flags =
if (ret < 0) {
"file_dotlock_create()");
}
}
/* don't bother warning if locking failed due to a timeout. since cache
updating isn't all that important we're using a very short timeout
so it can be triggered sometimes on heavy load */
if (ret <= 0)
return ret;
TRUE);
return 1;
}
{
else
}
static int
bool nonblock)
{
const struct mail_index_ext *ext;
const void *data;
struct mail_index_view *iview;
int i, ret;
(void)mail_cache_open_and_verify(cache);
if (MAIL_CACHE_IS_UNUSABLE(cache) ||
return 0;
/* cache not used */
return 0;
}
for (i = 0; i < 3; i++) {
(require_same_reset_id || i == 0)) {
/* we want the latest cache file */
/* either we're still waiting for index to
catch up with a cache compression, or
that catching up is never going to happen */
ret = 0;
break;
}
break;
}
ret = -1;
break;
}
/* got it */
break;
}
/* okay, so it was just compressed. try again. */
(void)mail_cache_unlock(cache);
ret = 0;
}
if (ret > 0) {
/* make sure our header is up to date */
sizeof(struct mail_cache_header));
}
else {
(void)mail_cache_unlock(cache);
ret = -1;
}
}
return ret;
}
{
}
{
}
{
int ret = 0;
if (MAIL_CACHE_IS_UNUSABLE(cache)) {
/* we found it to be broken during the lock. just clean up. */
return -1;
}
if (cache->hdr_modified) {
ret = -1;
}
}
return ret;
}
{
return -1;
}
return 0;
}
{
return !MAIL_CACHE_IS_UNUSABLE(cache);
}
struct mail_cache_view *
{
struct mail_cache_view *view;
return view;
}
{
}
bool update)
{
}
{
const struct mail_index_header *idx_hdr;
return 1;
&message_count)) {
/* all messages are too old */
return message_count+1;
}
return first_new_seq;
}