Mercurial > dovecot > original-hg > dovecot-1.2
view src/lib-index/mail-index-view-sync.c @ 2050:ee1095ccfd23 HEAD
Index header changes now go through transaction log. Removed the kludgy
parameters for mail_index_sync_end(). Removed code duplication of syncing
index root mapping and view mapping. Some fixes to handling uidvalidity and
nextuid in syncing.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 24 May 2004 04:50:16 +0300 |
parents | d2eafac70369 |
children | cb5269c052e0 |
line wrap: on
line source
/* Copyright (C) 2003-2004 Timo Sirainen */ #include "lib.h" #include "buffer.h" #include "mail-index-view-private.h" #include "mail-index-sync-private.h" #include "mail-transaction-log.h" #include "mail-transaction-util.h" struct mail_index_view_sync_ctx { struct mail_index_view *view; enum mail_index_sync_type sync_mask; buffer_t *expunges; const struct mail_transaction_header *hdr; const void *data; size_t data_offset; unsigned int skipped:1; unsigned int last_read:1; unsigned int sync_map_update:1; }; static int view_sync_get_expunges(struct mail_index_view *view, buffer_t **expunges_r) { const struct mail_transaction_header *hdr; struct mail_transaction_expunge *src, *src_end, *dest; const void *data; size_t size; int ret; *expunges_r = buffer_create_dynamic(default_pool, 512, (size_t)-1); /* with mask 0 we don't get anything, we'll just read the expunges while seeking to end */ if (mail_transaction_log_view_set(view->log_view, view->log_file_seq, view->log_file_offset, view->index->hdr->log_file_seq, view->index->hdr->log_file_offset, MAIL_TRANSACTION_EXPUNGE) < 0) return -1; while ((ret = mail_transaction_log_view_next(view->log_view, &hdr, &data, NULL)) > 0) { mail_transaction_log_sort_expunges(*expunges_r, data, hdr->size); } if (ret == 0) { /* convert to sequences */ src = dest = buffer_get_modifyable_data(*expunges_r, &size); src_end = src + size / sizeof(*src); for (; src != src_end; src++) { ret = mail_index_lookup_uid_range(view, src->uid1, src->uid2, &dest->uid1, &dest->uid2); i_assert(ret == 0); if (dest->uid1 == 0) size -= sizeof(*dest); else dest++; } buffer_set_used_size(*expunges_r, size); } else { buffer_set_used_size(*expunges_r, 0); } mail_transaction_log_view_unset(view->log_view); return ret; } int mail_index_view_sync_begin(struct mail_index_view *view, enum mail_index_sync_type sync_mask, struct mail_index_view_sync_ctx **ctx_r) { const struct mail_index_header *hdr; struct mail_index_view_sync_ctx *ctx; struct mail_index_map *map; enum mail_transaction_type mask; buffer_t *expunges = NULL; /* We must sync flags as long as view is mmap()ed, as the flags may have already changed under us. */ i_assert((sync_mask & MAIL_INDEX_SYNC_TYPE_FLAGS) != 0); i_assert(view->transactions == 0); i_assert(!view->syncing); if (mail_index_view_lock_head(view, TRUE) < 0) return -1; hdr = view->index->hdr; if ((sync_mask & MAIL_INDEX_SYNC_TYPE_EXPUNGE) != 0) { /* get list of all expunges first */ if (view_sync_get_expunges(view, &expunges) < 0) return -1; } mask = mail_transaction_type_mask_get(sync_mask); if (mail_transaction_log_view_set(view->log_view, view->log_file_seq, view->log_file_offset, hdr->log_file_seq, hdr->log_file_offset, mask) < 0) { if (expunges != NULL) buffer_free(expunges); return -1; } ctx = i_new(struct mail_index_view_sync_ctx, 1); ctx->view = view; ctx->sync_mask = sync_mask; ctx->expunges = expunges; if ((sync_mask & MAIL_INDEX_SYNC_TYPE_EXPUNGE) != 0) { view->new_map = view->index->map; view->new_map->refcount++; /* keep the old mapping without expunges until we're fully synced */ } else { /* we need a private copy of the map if we don't want to sync expunges */ if (view->map != view->index->map) ctx->sync_map_update = TRUE; map = mail_index_map_to_memory(view->map); mail_index_unmap(view->index, view->map); view->map = map; } view->syncing = TRUE; *ctx_r = ctx; return 0; } static int view_is_transaction_synced(struct mail_index_view *view, uint32_t seq, uoff_t offset) { const unsigned char *data, *end; size_t size; if (view->log_syncs == NULL) return 0; data = buffer_get_data(view->log_syncs, &size); end = data + size; for (; data < end; ) { if (*((const uoff_t *)data) == offset && *((const uint32_t *)(data + sizeof(uoff_t))) == seq) return 1; data += sizeof(uoff_t) + sizeof(uint32_t); } return 0; } static int mail_index_view_sync_next_trans(struct mail_index_view_sync_ctx *ctx, uint32_t *seq_r, uoff_t *offset_r) { struct mail_transaction_log_view *log_view = ctx->view->log_view; struct mail_index_view *view = ctx->view; int ret, skipped; ret = mail_transaction_log_view_next(log_view, &ctx->hdr, &ctx->data, &skipped); if (ret <= 0) { if (ret < 0) return -1; ctx->last_read = TRUE; return 1; } if (skipped) ctx->skipped = TRUE; mail_transaction_log_view_get_prev_pos(log_view, seq_r, offset_r); /* skip flag changes that we committed ourself or have already synced */ if (view_is_transaction_synced(view, *seq_r, *offset_r)) return 0; /* expunges have to be synced afterwards so that caller can still get information of the messages. otherwise caller most likely wants to see only updated information. */ if (ctx->sync_map_update && (ctx->hdr->type & MAIL_TRANSACTION_EXPUNGE) == 0) { if (mail_transaction_map(ctx->hdr, ctx->data, &mail_index_map_sync_funcs, view) < 0) return -1; } return 1; } #define FLAG_UPDATE_IS_INTERNAL(u, empty) \ (((u)->add_flags | (u)->remove_flags) == MAIL_INDEX_MAIL_FLAG_DIRTY && \ memcmp((u)->add_keywords, empty, INDEX_KEYWORDS_BYTE_COUNT) == 0 && \ memcmp((u)->add_keywords, empty, INDEX_KEYWORDS_BYTE_COUNT) == 0) static int mail_index_view_sync_get_rec(struct mail_index_view_sync_ctx *ctx, struct mail_index_sync_rec *rec) { static keywords_mask_t empty_keywords = { 0, }; const struct mail_transaction_header *hdr = ctx->hdr; const void *data = ctx->data; switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) { case MAIL_TRANSACTION_APPEND: { rec->type = MAIL_INDEX_SYNC_TYPE_APPEND; rec->uid1 = rec->uid2 = 0; ctx->data_offset += hdr->size; break; } case MAIL_TRANSACTION_EXPUNGE: { const struct mail_transaction_expunge *exp = CONST_PTR_OFFSET(data, ctx->data_offset); ctx->data_offset += sizeof(*exp); mail_index_sync_get_expunge(rec, exp); break; } case MAIL_TRANSACTION_FLAG_UPDATE: { const struct mail_transaction_flag_update *update = CONST_PTR_OFFSET(data, ctx->data_offset); for (;;) { ctx->data_offset += sizeof(*update); if (!FLAG_UPDATE_IS_INTERNAL(update, empty_keywords)) break; if (ctx->data_offset == ctx->hdr->size) return 0; } mail_index_sync_get_update(rec, update); break; } default: i_unreached(); } return 1; } int mail_index_view_sync_next(struct mail_index_view_sync_ctx *ctx, struct mail_index_sync_rec *sync_rec) { struct mail_index_view *view = ctx->view; uint32_t seq; uoff_t offset; int ret; do { if (ctx->hdr == NULL || ctx->data_offset == ctx->hdr->size) { ctx->data_offset = 0; do { ret = mail_index_view_sync_next_trans(ctx, &seq, &offset); if (ret < 0) return -1; if (ctx->last_read) return 0; if (!ctx->skipped) { view->log_file_seq = seq; view->log_file_offset = offset + sizeof(*ctx->hdr) + ctx->hdr->size; } } while (ret == 0); if (ctx->skipped) { mail_index_view_add_synced_transaction(view, seq, offset); } } } while (!mail_index_view_sync_get_rec(ctx, sync_rec)); return 1; } const uint32_t * mail_index_view_sync_get_expunges(struct mail_index_view_sync_ctx *ctx, size_t *count_r) { const uint32_t *data; size_t size; data = buffer_get_data(ctx->expunges, &size); *count_r = size / (sizeof(uint32_t)*2); return data; } void mail_index_view_sync_end(struct mail_index_view_sync_ctx *ctx) { struct mail_index_view *view = ctx->view; i_assert(view->syncing); if (view->log_syncs != NULL && !ctx->skipped) buffer_set_used_size(view->log_syncs, 0); if (!ctx->last_read && ctx->hdr != NULL && ctx->data_offset != ctx->hdr->size) { /* we didn't sync everything */ view->inconsistent = TRUE; } if (view->new_map != NULL) { mail_index_unmap(view->index, view->map); view->map = view->new_map; view->new_map = NULL; view->map_protected = FALSE; } if ((ctx->sync_mask & MAIL_INDEX_SYNC_TYPE_APPEND) != 0) view->messages_count = view->map->records_count; mail_transaction_log_view_unset(view->log_view); if (ctx->expunges != NULL) buffer_free(ctx->expunges); view->syncing = FALSE; i_free(ctx); } void mail_index_view_add_synced_transaction(struct mail_index_view *view, uint32_t log_file_seq, uoff_t log_file_offset) { if (view->log_syncs == NULL) { view->log_syncs = buffer_create_dynamic(default_pool, 128, (size_t)-1); } buffer_append(view->log_syncs, &log_file_offset, sizeof(log_file_offset)); buffer_append(view->log_syncs, &log_file_seq, sizeof(log_file_seq)); }