mail-cache-sync-update.c revision 1b75126c39121b25f0bba048758b56d4b4b9bf1a
145N/A/* Copyright (c) 2004-2007 Dovecot authors, see the included COPYING file */
145N/A
145N/A#include "lib.h"
145N/A#include "file-cache.h"
145N/A#include "mail-cache-private.h"
145N/A#include "mail-index-view-private.h"
145N/A#include "mail-index-sync-private.h"
145N/A
145N/Astruct mail_cache_sync_context {
145N/A uoff_t invalidate_highwater;
145N/A
145N/A unsigned int locked:1;
145N/A unsigned int lock_failed:1;
145N/A unsigned int nfs_attr_cache_flushed:1;
145N/A};
145N/A
145N/Astatic void mail_cache_handler_deinit(struct mail_index_sync_map_ctx *sync_ctx,
145N/A struct mail_cache_sync_context *ctx)
145N/A{
145N/A if (ctx == NULL)
5630N/A return;
145N/A
145N/A if (ctx->locked)
145N/A (void)mail_cache_unlock(sync_ctx->view->index->cache);
187N/A i_free(ctx);
3996N/A}
187N/A
187N/Astatic struct mail_cache_sync_context *mail_cache_handler_init(void **context)
187N/A{
145N/A struct mail_cache_sync_context *ctx;
187N/A
187N/A if (*context != NULL)
187N/A ctx = *context;
145N/A else {
1273N/A *context = i_new(struct mail_cache_sync_context, 1);
1273N/A ctx = *context;
1273N/A ctx->invalidate_highwater = (uoff_t)-1;
5630N/A }
5630N/A return ctx;
5630N/A}
5630N/A
5630N/Astatic int mail_cache_handler_lock(struct mail_cache_sync_context *ctx,
187N/A struct mail_cache *cache)
5630N/A{
197N/A int ret;
197N/A
197N/A if (ctx->locked)
197N/A return 1;
187N/A if (ctx->lock_failed)
5630N/A return 0;
187N/A
5630N/A if (!ctx->locked) {
5630N/A if ((ret = mail_cache_lock(cache, TRUE)) <= 0) {
5630N/A ctx->lock_failed = TRUE;
5630N/A return ret;
5630N/A }
5630N/A ctx->locked = TRUE;
5630N/A }
5630N/A return 1;
5630N/A}
145N/A
4409N/Astatic int get_cache_file_seq(struct mail_index_view *view,
4409N/A uint32_t *cache_file_seq_r)
4409N/A{
4409N/A const struct mail_index_ext *ext;
4409N/A
4409N/A ext = mail_index_view_get_ext(view, view->index->cache->ext_id);
192N/A if (ext == NULL)
192N/A return 0;
192N/A
145N/A *cache_file_seq_r = ext->reset_id;
145N/A return 1;
145N/A}
187N/A
4409N/Aint mail_cache_expunge_handler(struct mail_index_sync_map_ctx *sync_ctx,
3468N/A uint32_t seq ATTR_UNUSED, const void *data,
187N/A void **sync_context, void *context)
5630N/A{
5630N/A struct mail_cache *cache = context;
5630N/A struct mail_cache_sync_context *ctx = *sync_context;
5630N/A const uint32_t *cache_offset = data;
187N/A uint32_t cache_file_seq;
1900N/A int ret;
191N/A
145N/A if (data == NULL) {
5630N/A mail_cache_handler_deinit(sync_ctx, ctx);
5630N/A *sync_context = NULL;
5630N/A return 0;
5630N/A }
5630N/A
187N/A if (*cache_offset == 0)
2541N/A return 0;
187N/A
187N/A if (MAIL_CACHE_IS_UNUSABLE(cache))
187N/A return 0;
187N/A
187N/A ctx = mail_cache_handler_init(context);
1900N/A ret = mail_cache_handler_lock(ctx, cache);
1900N/A if (ret <= 0)
1900N/A return ret;
187N/A
187N/A if (!get_cache_file_seq(sync_ctx->view, &cache_file_seq))
187N/A return 0;
145N/A
197N/A if (!MAIL_CACHE_IS_UNUSABLE(cache) &&
197N/A cache_file_seq == cache->hdr->file_seq)
197N/A (void)mail_cache_delete(cache, *cache_offset);
145N/A return 0;
197N/A}
int mail_cache_sync_handler(struct mail_index_sync_map_ctx *sync_ctx,
uint32_t seq ATTR_UNUSED,
void *old_data, const void *new_data,
void **context)
{
struct mail_index_view *view = sync_ctx->view;
struct mail_cache *cache = view->index->cache;
struct mail_cache_sync_context *ctx = *context;
const uint32_t *old_cache_offset = old_data;
const uint32_t *new_cache_offset = new_data;
uint32_t cache_file_seq, cur_seq, tail_seq;
uoff_t cur_offset, tail_offset;
int ret;
if (new_cache_offset == NULL) {
mail_cache_handler_deinit(sync_ctx, ctx);
*context = NULL;
return 1;
}
if (MAIL_CACHE_IS_UNUSABLE(cache))
return 1;
ctx = mail_cache_handler_init(context);
if (cache->file_cache != NULL) {
/* flush attribute cache only once per sync */
if (!ctx->nfs_attr_cache_flushed && cache->index->nfs_flush) {
ctx->nfs_attr_cache_flushed = TRUE;
mail_cache_flush_read_cache(cache, FALSE);
}
/* don't invalidate anything that's already been invalidated
within this sync. */
if (*new_cache_offset < ctx->invalidate_highwater) {
file_cache_invalidate(cache->file_cache,
*new_cache_offset,
ctx->invalidate_highwater -
*new_cache_offset);
ctx->invalidate_highwater = *new_cache_offset;
}
}
if (*old_cache_offset == 0 || *old_cache_offset == *new_cache_offset ||
sync_ctx->type == MAIL_INDEX_SYNC_HANDLER_VIEW)
return 1;
mail_transaction_log_view_get_prev_pos(view->log_view,
&cur_seq, &cur_offset);
mail_transaction_log_get_mailbox_sync_pos(view->index->log,
&tail_seq, &tail_offset);
if (LOG_IS_BEFORE(cur_seq, cur_offset, tail_seq, tail_offset)) {
/* already been linked */
return 1;
}
/* we'll need to link the old and new cache records */
ret = mail_cache_handler_lock(ctx, cache);
if (ret <= 0)
return ret < 0 ? -1 : 1;
if (!get_cache_file_seq(view, &cache_file_seq))
return 1;
if (cache_file_seq != cache->hdr->file_seq) {
/* cache has been compressed, don't modify it */
return 1;
}
if (mail_cache_link(cache, *old_cache_offset, *new_cache_offset) < 0)
return -1;
return 1;
}
void mail_cache_sync_lost_handler(struct mail_index *index)
{
if (!MAIL_CACHE_IS_UNUSABLE(index->cache))
mail_cache_flush_read_cache(index->cache, FALSE);
file_cache_invalidate(index->cache->file_cache, 0, (uoff_t)-1);
}