mail-index-view-sync.c revision 86bde2c1838d1ce967fa2b394bb952004a4adcb7
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen/* Copyright (c) 2003-2012 Dovecot authors, see the included COPYING file */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen /* After syncing view, map is replaced with sync_new_map. */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen /* temporary variables while handling lost transaction logs: */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen ARRAY_TYPE(keyword_indexes) lost_old_kw, lost_new_kw;
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainen /* result of lost transaction logs: */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenview_sync_set_log_view_range(struct mail_index_view *view, bool sync_expunges,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen const struct mail_index_header *hdr = &view->index->map->hdr;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen "%s log position went backwards "
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen view->log_file_head_seq, view->log_file_head_offset);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen /* the view begins from the first non-synced transaction */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen ret = mail_transaction_log_view_set(view->log_view,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen /* log was reset, but we don't want to sync expunges.
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen we can't do this, so sync only up to the reset. */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen mail_transaction_log_view_get_prev_pos(view->log_view,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen /* we have only this reset log */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen mail_transaction_log_view_clear(view->log_view,
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainenstatic unsigned int
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenview_sync_expunges2seqs(struct mail_index_view_sync_ctx *ctx)
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainen /* convert UIDs to sequences */
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainen src = dest = array_get_modifiable(&ctx->expunges, &count);
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainen if (!mail_index_lookup_seq_range(view, src->seq1, src->seq2,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenview_sync_add_expunge_range(ARRAY_TYPE(seq_range) *dest,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen unsigned int i, src_count;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen for (i = 0; i < src_count; i++)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen seq_range_array_add_range(dest, src[i].seq1, src[i].seq2);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenview_sync_add_expunge_guids(ARRAY_TYPE(seq_range) *dest,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen const struct mail_transaction_expunge_guid *src,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen unsigned int i, src_count;
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainen for (i = 0; i < src_count; i++)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenview_sync_get_expunges(struct mail_index_view_sync_ctx *ctx,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen /* get a list of expunge transactions. there may be some that we have
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainen already synced, but it doesn't matter because they'll get dropped
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainen out when converting to sequences. the uid ranges' validity has
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen already been verified, so we can use them directly. */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen mail_transaction_log_view_mark(view->log_view);
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainen while ((ret = mail_transaction_log_view_next(view->log_view,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) {
a326f9da3c18a4ccfb28e72f87161eaf3624eaf2Timo Sirainen /* skip expunge requests */
a326f9da3c18a4ccfb28e72f87161eaf3624eaf2Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXPUNGE_GUID) != 0) {
2bc963ea051ddacefe0fa5e26280e8ef853fd6c6Timo Sirainen } else if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) != 0) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen mail_transaction_log_view_rewind(view->log_view);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen *expunge_count_r = view_sync_expunges2seqs(ctx);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic bool have_existing_expunges(struct mail_index_view *view,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (mail_index_lookup_seq_range(view, range->seq1, range->seq2,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenhave_existing_guid_expunge(struct mail_index_view *view,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen const struct mail_transaction_expunge_guid *expunges,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen const struct mail_transaction_expunge_guid *expunges_end;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen expunges_end = CONST_PTR_OFFSET(expunges, size);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen for (; expunges != expunges_end; expunges++) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (mail_index_lookup_seq(view, expunges->uid, &seq))
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic bool view_sync_have_expunges(struct mail_index_view *view)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen mail_transaction_log_view_mark(view->log_view);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen while ((ret = mail_transaction_log_view_next(view->log_view,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen /* skip expunge requests */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXPUNGE_GUID) != 0) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen /* we have an expunge. see if it still exists. */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (have_existing_guid_expunge(view, data, hdr->size)) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen } else if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) != 0) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen /* we have an expunge. see if it still exists. */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (have_existing_expunges(view, data, hdr->size)) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen mail_transaction_log_view_rewind(view->log_view);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen /* handle failures as having expunges (which is safer).
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen we'll probably fail later. */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic int uint_cmp(const void *p1, const void *p2)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic bool view_sync_lost_keywords_equal(struct mail_index_view_sync_ctx *ctx)
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen old_idx = array_get_modifiable(&ctx->lost_old_kw, &old_count);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen new_idx = array_get_modifiable(&ctx->lost_new_kw, &new_count);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen qsort(old_idx, old_count, sizeof(*old_idx), uint_cmp);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen qsort(new_idx, new_count, sizeof(*new_idx), uint_cmp);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen return memcmp(old_idx, new_idx, old_count * sizeof(old_idx)) == 0;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic int view_sync_update_keywords(struct mail_index_view_sync_ctx *ctx,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen const unsigned int *kw_idx;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen const char *const *kw_names;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen unsigned int i, count;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen kw_idx = array_get(&ctx->lost_new_kw, &count);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen kw_names = array_idx(&ctx->view->index->keywords, 0);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen thdr.type = MAIL_TRANSACTION_KEYWORD_UPDATE | MAIL_TRANSACTION_EXTERNAL;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen /* add new flags one by one */
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen for (i = 0; i < count; i++) {
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen kw_up.name_size = strlen(kw_names[kw_idx[i]]);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen buffer_append(ctx->lost_kw_buf, &kw_up, sizeof(kw_up));
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen buffer_append(ctx->lost_kw_buf, kw_names[kw_idx[i]],
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen buffer_append(ctx->lost_kw_buf, &uid, sizeof(uid));
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen buffer_append(ctx->lost_kw_buf, &uid, sizeof(uid));
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen if (mail_index_sync_record(&ctx->sync_map_ctx, &thdr,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainenstatic int view_sync_apply_lost_changes(struct mail_index_view_sync_ctx *ctx,
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen struct mail_index_map *old_map = ctx->view->map;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen struct mail_index_map *new_map = ctx->view->index->map;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen const struct mail_index_record *old_rec, *new_rec;
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen old_rec = MAIL_INDEX_MAP_IDX(old_map, old_seq - 1);
5ef28f68edef46f69961b19b7c1dcd8ec5a955e8Timo Sirainen new_rec = MAIL_INDEX_MAP_IDX(new_map, new_seq - 1);
&flag_update) < 0)
&kw_reset) < 0)
if (changed) {
if (changed)
unsigned int *expunge_count_r)
for (; i < old_count; i++) {
for (; j < new_count; j++) {
bool reset;
struct mail_index_view_sync_ctx *
unsigned int expunge_count = 0;
int ret;
if (sync_expunges)
return ctx;
return ctx;
if (ret < 0) {
return ctx;
if (ret == 0) {
if (!sync_expunges)
if (ret < 0) {
return ctx;
} else if (sync_expunges) {
return ctx;
if (!have_expunges) {
if (sync_expunges) {
#ifdef DEBUG
return ctx;
return FALSE;
return TRUE;
return FALSE;
MAIL_TRANSACTION_EXPUNGE_GUID)) != 0 &&
return FALSE;
return FALSE;
return FALSE;
return TRUE;
int ret;
bool synced_to_map;
if (ret <= 0) {
if (ret < 0)
MAIL_TRANSACTION_EXPUNGE_GUID)) == 0) {
if (ret < 0)
case MAIL_TRANSACTION_FLAG_UPDATE: {
case MAIL_TRANSACTION_KEYWORD_UPDATE: {
case MAIL_TRANSACTION_KEYWORD_RESET: {
return FALSE;
return TRUE;
unsigned int count;
return FALSE;
return TRUE;
int ret;
if (ret <= 0) {
if (ret < 0)
return FALSE;
return TRUE;
unsigned int i, count;
for (i = 0; i < count; i++) {
bool *delayed_expunges_r)
#ifdef DEBUG
return ret;
unsigned int length)