mail-index-view-sync.c revision ffb79efcac37f807f75ab0a04c7b17a3d4af7167
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2003-2012 Dovecot authors, see the included COPYING file */
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen /* After syncing view, map is replaced with sync_new_map. */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* temporary variables while handling lost transaction logs: */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen ARRAY_TYPE(keyword_indexes) lost_old_kw, lost_new_kw;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* result of lost transaction logs: */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenview_sync_set_log_view_range(struct mail_index_view *view, bool sync_expunges,
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen const struct mail_index_header *hdr = &view->index->map->hdr;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen "%s log position went backwards "
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen view->log_file_head_seq, view->log_file_head_offset);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen /* the view begins from the first non-synced transaction */
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen ret = mail_transaction_log_view_set(view->log_view,
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* log was reset, but we don't want to sync expunges.
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen we can't do this, so sync only up to the reset. */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen mail_transaction_log_view_get_prev_pos(view->log_view,
d65cc3312d3126d34b51ae8eccd6b48215d50029Timo Sirainen /* we have only this reset log */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen mail_transaction_log_view_clear(view->log_view,
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainenstatic unsigned int
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainenview_sync_expunges2seqs(struct mail_index_view_sync_ctx *ctx)
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen /* convert UIDs to sequences */
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen src = dest = array_get_modifiable(&ctx->expunges, &count);
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen if (!mail_index_lookup_seq_range(view, src->seq1, src->seq2,
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainenview_sync_add_expunge_range(ARRAY_TYPE(seq_range) *dest,
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen unsigned int i, src_count;
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen for (i = 0; i < src_count; i++)
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen seq_range_array_add_range(dest, src[i].seq1, src[i].seq2);
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainenview_sync_add_expunge_guids(ARRAY_TYPE(seq_range) *dest,
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen const struct mail_transaction_expunge_guid *src,
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen unsigned int i, src_count;
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen for (i = 0; i < src_count; i++)
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainenview_sync_get_expunges(struct mail_index_view_sync_ctx *ctx,
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen /* get a list of expunge transactions. there may be some that we have
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen already synced, but it doesn't matter because they'll get dropped
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen out when converting to sequences. the uid ranges' validity has
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen already been verified, so we can use them directly. */
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen mail_transaction_log_view_mark(view->log_view);
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen while ((ret = mail_transaction_log_view_next(view->log_view,
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) {
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen /* skip expunge requests */
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXPUNGE_GUID) != 0) {
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen } else if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) != 0) {
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen mail_transaction_log_view_rewind(view->log_view);
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainen *expunge_count_r = view_sync_expunges2seqs(ctx);
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainenstatic bool have_existing_expunges(struct mail_index_view *view,
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (mail_index_lookup_seq_range(view, range->seq1, range->seq2,
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenhave_existing_guid_expunge(struct mail_index_view *view,
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen const struct mail_transaction_expunge_guid *expunges,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen const struct mail_transaction_expunge_guid *expunges_end;
e93ab1b206e3792a8dabc460ad2ee60aaf6830b1Timo Sirainen expunges_end = CONST_PTR_OFFSET(expunges, size);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen for (; expunges != expunges_end; expunges++) {
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen if (mail_index_lookup_seq(view, expunges->uid, &seq))
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainenstatic bool view_sync_have_expunges(struct mail_index_view *view)
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainen mail_transaction_log_view_mark(view->log_view);
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainen while ((ret = mail_transaction_log_view_next(view->log_view,
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* skip expunge requests */
3322dfd56c9cae5015a33bab4c80124c08c3d9caTimo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXPUNGE_GUID) != 0) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* we have an expunge. see if it still exists. */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (have_existing_guid_expunge(view, data, hdr->size)) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen } else if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) != 0) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* we have an expunge. see if it still exists. */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (have_existing_expunges(view, data, hdr->size)) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen mail_transaction_log_view_rewind(view->log_view);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* handle failures as having expunges (which is safer).
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen we'll probably fail later. */
009217abb57a24a4076092e8e4e165545747839eStephan Boschstatic int uint_cmp(const void *p1, const void *p2)
accba2f170529d73097e098d0bb6c13b7b4d6abfTimo Sirainenstatic bool view_sync_lost_keywords_equal(struct mail_index_view_sync_ctx *ctx)
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen old_idx = array_get_modifiable(&ctx->lost_old_kw, &old_count);
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen new_idx = array_get_modifiable(&ctx->lost_new_kw, &new_count);
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen qsort(old_idx, old_count, sizeof(*old_idx), uint_cmp);
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen qsort(new_idx, new_count, sizeof(*new_idx), uint_cmp);
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen return memcmp(old_idx, new_idx, old_count * sizeof(old_idx)) == 0;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstatic int view_sync_update_keywords(struct mail_index_view_sync_ctx *ctx,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen const unsigned int *kw_idx;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen const char *const *kw_names;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen unsigned int i, count;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen kw_idx = array_get(&ctx->lost_new_kw, &count);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen kw_names = array_idx(&ctx->view->index->keywords, 0);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen thdr.type = MAIL_TRANSACTION_KEYWORD_UPDATE | MAIL_TRANSACTION_EXTERNAL;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* add new flags one by one */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen for (i = 0; i < count; i++) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen kw_up.name_size = strlen(kw_names[kw_idx[i]]);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen buffer_append(ctx->lost_kw_buf, &kw_up, sizeof(kw_up));
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen buffer_append(ctx->lost_kw_buf, kw_names[kw_idx[i]],
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller buffer_append(ctx->lost_kw_buf, &uid, sizeof(uid));
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen buffer_append(ctx->lost_kw_buf, &uid, sizeof(uid));
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller if (mail_index_sync_record(&ctx->sync_map_ctx, &thdr,
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainenstatic int view_sync_apply_lost_changes(struct mail_index_view_sync_ctx *ctx,
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen struct mail_index_map *old_map = ctx->view->map;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen struct mail_index_map *new_map = ctx->view->index->map;
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller const struct mail_index_record *old_rec, *new_rec;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen old_rec = MAIL_INDEX_MAP_IDX(old_map, old_seq - 1);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen new_rec = MAIL_INDEX_MAP_IDX(new_map, new_seq - 1);
86fafb22c02f4b85a9d59f2b60059a48286286fbTimo Sirainen struct mail_transaction_flag_update flag_update;
86fafb22c02f4b85a9d59f2b60059a48286286fbTimo Sirainen /* check this before syncing the record, since it updates
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if ((old_rec->flags & MAIL_INDEX_FLAGS_MASK) !=
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen flag_update.uid1 = flag_update.uid2 = new_rec->uid;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen flag_update.remove_flags = ~new_rec->flags & 0xff;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen if (mail_index_sync_record(&ctx->sync_map_ctx, &thdr,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen mail_index_map_lookup_keywords(old_map, old_seq, &ctx->lost_old_kw);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen mail_index_map_lookup_keywords(new_map, new_seq, &ctx->lost_new_kw);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen struct mail_transaction_keyword_reset kw_reset;
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen /* remove all old flags by resetting them */
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen if (mail_index_sync_record(&ctx->sync_map_ctx, &thdr,
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen /* flags or keywords changed */
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen /* if modseq has changed include this message in changed flags
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen list, even if we didn't see any changes above. */
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen ext = array_idx(&new_map->extensions, ctx->lost_new_ext_idx);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen modseqp = CONST_PTR_OFFSET(new_rec, ext->record_offset);
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen /* without modseqs lost_flags isn't updated perfectly correctly, because
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen by the time we're comparing old flags it may have changed from what
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen we last sent to the client (because the map is shared). This could
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen be avoided by always keeping a private copy of the map in the view,
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen but that's a waste of memory for as rare of a problem as this. */
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainen seq_range_array_add(&ctx->lost_flags, 0, new_rec->uid);
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainenview_sync_get_log_lost_changes(struct mail_index_view_sync_ctx *ctx,
3322dfd56c9cae5015a33bab4c80124c08c3d9caTimo Sirainen struct mail_index_map *new_map = view->index->map;
32efae185f1f86167b3f00ea84f8502940c6c677Timo Sirainen const unsigned int old_count = old_map->hdr.messages_count;
3322dfd56c9cae5015a33bab4c80124c08c3d9caTimo Sirainen const unsigned int new_count = new_map->hdr.messages_count;
d163fac99c7ca5b2ce2edfa83a1b2922cf66aeacTimo Sirainen const struct mail_index_record *old_rec, *new_rec;
3322dfd56c9cae5015a33bab4c80124c08c3d9caTimo Sirainen unsigned int i, j;
3322dfd56c9cae5015a33bab4c80124c08c3d9caTimo Sirainen /* we don't update the map in the same order as it's typically done.
3322dfd56c9cae5015a33bab4c80124c08c3d9caTimo Sirainen map->rec_map may already have some messages appended that we don't
e93ab1b206e3792a8dabc460ad2ee60aaf6830b1Timo Sirainen want. get an atomic map to make sure these get removed. */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen (void)mail_index_sync_get_atomic_map(&ctx->sync_map_ctx);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (!mail_index_map_get_ext_idx(new_map, view->index->modseq_ext_id,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen ctx->lost_kw_buf = buffer_create_dynamic(pool_datastack_create(), 128);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* handle expunges and sync flags */
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen /* message found - check if flags have changed */
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen if (view_sync_apply_lost_changes(ctx, i + 1, j + 1) < 0)
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen /* message expunged */
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen seq_range_array_add(&ctx->expunges, 0, old_rec->uid);
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen /* new message appeared out of nowhere */
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen "%s view is inconsistent: "
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen "uid=%u inserted in the middle of mailbox",
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen /* if there are old messages left, they're all expunged */
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen for (; i < old_count; i++) {
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen seq_range_array_add(&ctx->expunges, 0, old_rec->uid);
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen /* if there are new messages left, they're all new messages */
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen thdr.type = MAIL_TRANSACTION_APPEND | MAIL_TRANSACTION_EXTERNAL;
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen for (; j < new_count; j++) {
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen if (mail_index_sync_record(&ctx->sync_map_ctx,
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen mail_index_map_lookup_keywords(new_map, j + 1,
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller *expunge_count_r = view_sync_expunges2seqs(ctx);
7b22071c71a99bcb71ee9fcfbb83ed5bf5e08a2dTimo Sirainen /* we have no idea how far we've synced - make sure these aren't used */
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen if ((ctx->flags & MAIL_INDEX_VIEW_SYNC_FLAG_NOEXPUNGES) != 0) {
7b22071c71a99bcb71ee9fcfbb83ed5bf5e08a2dTimo Sirainen view->log_file_head_seq = new_map->hdr.log_file_seq;
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller view->log_file_head_offset = new_map->hdr.log_file_head_offset;
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Wellerstatic int mail_index_view_sync_init_fix(struct mail_index_view_sync_ctx *ctx)
7b22071c71a99bcb71ee9fcfbb83ed5bf5e08a2dTimo Sirainen /* replace the view's map */
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen /* update log positions */
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen view->log_file_head_seq = seq = view->map->hdr.log_file_seq;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen if (mail_transaction_log_view_set(view->log_view, seq, offset,
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainenmail_index_view_sync_begin(struct mail_index_view *view,
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen unsigned int expunge_count = 0;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen /* Syncing the view invalidates all previous looked up records.
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen Unreference the mappings this view keeps because of them. */
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen ctx = i_new(struct mail_index_view_sync_ctx, 1);
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen sync_expunges = (flags & MAIL_INDEX_VIEW_SYNC_FLAG_NOEXPUNGES) == 0;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen if ((flags & MAIL_INDEX_VIEW_SYNC_FLAG_FIX_INCONSISTENT) != 0) {
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen /* just get this view synced - don't return anything */
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen mail_index_set_error(view->index, "%s view is inconsistent",
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen ret = view_sync_set_log_view_range(view, sync_expunges, &reset);
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen mail_index_sync_map_init(&ctx->sync_map_ctx, view,
170834eda87ac8e6b8b6577738ef373fc68f117dTimo Sirainen ret = view_sync_get_log_lost_changes(ctx, &expunge_count);
170834eda87ac8e6b8b6577738ef373fc68f117dTimo Sirainen mail_index_modseq_sync_end(&ctx->sync_map_ctx.modseq_ctx);
170834eda87ac8e6b8b6577738ef373fc68f117dTimo Sirainen mail_index_sync_map_deinit(&ctx->sync_map_ctx);
170834eda87ac8e6b8b6577738ef373fc68f117dTimo Sirainen "%s view syncing failed to apply changes",
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen /* get list of all expunges first */
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen if (view_sync_get_expunges(ctx, &expunge_count) < 0) {
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen have_expunges = view_sync_have_expunges(view);
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen view->map->hdr.messages_count - expunge_count;
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen if (reset && view->map->hdr.messages_count > 0) {
61d3fd14828b68d789f3df73d1dbed56e37b7931Timo Sirainen "%s reset, view is now inconsistent",
02e8b5f55210f413853998a0ba5832eb3f9a6dc6Timo Sirainen /* no expunges, we can just replace the map */
2ed2459dbd183bb371da4a0aecb2d2b74ae7c815Timo Sirainen "Index %s lost messages without expunging "
bc37bab86f0ae7b9d7149d2418340b88e6ef212fTimo Sirainen /* expunges seen. create a private map which we update.
bc37bab86f0ae7b9d7149d2418340b88e6ef212fTimo Sirainen if we're syncing expunges the map will finally be replaced
bc37bab86f0ae7b9d7149d2418340b88e6ef212fTimo Sirainen with the head map to remove the expunged messages. */
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen mail_index_sync_map_init(&ctx->sync_map_ctx, view,
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainenview_sync_is_hidden(struct mail_index_view *view, uint32_t seq, uoff_t offset)
ced943b0a9b49a5be38516302fe1631c1883debaTimo Sirainen const struct mail_index_view_log_sync_area *sync;
553a131eddb46d97967fd9610408b7f0829eab6fTimo Sirainen offset - sync->log_file_offset < sync->length &&
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainenmail_index_view_sync_want(struct mail_index_view_sync_ctx *ctx,
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen mail_transaction_log_view_get_prev_pos(view->log_view, &seq, &offset);
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen next_offset = offset + sizeof(*hdr) + hdr->size;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen (hdr->type & MAIL_TRANSACTION_EXTERNAL) != 0) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if ((ctx->flags & MAIL_INDEX_VIEW_SYNC_FLAG_NOEXPUNGES) != 0) {
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen if (LOG_IS_BEFORE(seq, offset, view->log_file_expunge_seq,
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* already synced */
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen if (LOG_IS_BEFORE(seq, offset, view->log_file_head_seq,
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen /* already synced */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenmail_index_view_sync_get_next_transaction(struct mail_index_view_sync_ctx *ctx)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen struct mail_transaction_log_view *log_view = ctx->view->log_view;
aeea3dbd1f4031634f7b318614adf51dcfc79f42Timo Sirainen /* Get the next transaction from log. */
aeea3dbd1f4031634f7b318614adf51dcfc79f42Timo Sirainen ret = mail_transaction_log_view_next(log_view, &ctx->hdr,
b02e7bac5b8b19795884229f64e6fbbd93a0d2deTimo Sirainen /* skip records we've already synced */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen } while (!mail_index_view_sync_want(ctx, hdr));
f6008a666d9c3df66fd8a437369133e8519b4e24Timo Sirainen mail_transaction_log_view_get_prev_pos(log_view, &seq, &offset);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* If we started from a map that we didn't create ourself,
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen some of the transactions may already be synced. at the end
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen of this view sync we'll update file_seq=0 so that this check
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen always becomes FALSE for subsequent syncs. */
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen synced_to_map = view->map->hdr.log_file_seq != 0 &&
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen LOG_IS_BEFORE(seq, offset, view->map->hdr.log_file_seq,
a795ff053b41be95cb94a33cd5501f8d2e843e20Timo Sirainen /* Apply transaction to view's mapping if needed (meaning we
a795ff053b41be95cb94a33cd5501f8d2e843e20Timo Sirainen didn't just re-map the view to head mapping). */
a795ff053b41be95cb94a33cd5501f8d2e843e20Timo Sirainen ret = mail_index_sync_record(&ctx->sync_map_ctx,
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen ctx->hidden = view_sync_is_hidden(view, seq, offset);
bc37bab86f0ae7b9d7149d2418340b88e6ef212fTimo Sirainenmail_index_view_sync_get_rec(struct mail_index_view_sync_ctx *ctx,
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen const struct mail_transaction_header *hdr = ctx->hdr;
ced943b0a9b49a5be38516302fe1631c1883debaTimo Sirainen switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
42abccd9b2a5a4190bd3c14ec2dcc10d51c0f491Timo Sirainen const struct mail_transaction_flag_update *update =
ddf6020f6fefe71c4422a8c55d012a62648ae3adTimo Sirainen /* data contains mail_transaction_flag_update[] */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (!MAIL_TRANSACTION_FLAG_UPDATE_IS_INTERNAL(update))
2ba9851abbaffe9592c06c0060dce40bb6da3b78Timo Sirainen /* skip internal flag changes */
2ba9851abbaffe9592c06c0060dce40bb6da3b78Timo Sirainen update = CONST_PTR_OFFSET(data, ctx->data_offset);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen const struct mail_transaction_keyword_update *update = data;
d65cc3312d3126d34b51ae8eccd6b48215d50029Timo Sirainen /* data contains mail_transaction_keyword_update header,
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen the keyword name and an array of { uint32_t uid1, uid2; } */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* skip over the header and name */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen ctx->data_offset = sizeof(*update) + update->name_size;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen ctx->data_offset += 4 - (ctx->data_offset % 4);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen uids = CONST_PTR_OFFSET(data, ctx->data_offset);
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen const struct mail_transaction_keyword_reset *reset =
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen /* data contains mail_transaction_keyword_reset[] */
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainenmail_index_view_sync_next_lost(struct mail_index_view_sync_ctx *ctx,
7ffa9e9809f10884a9167c19c09c980e3c1792b1Timo Sirainen unsigned int count;
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen sync_rec->type = MAIL_INDEX_VIEW_SYNC_TYPE_FLAGS;
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen sync_rec->uid1 = range[ctx->lost_flag_idx].seq1;
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen sync_rec->uid2 = range[ctx->lost_flag_idx].seq2;
da0420f1b5d5f5ab1079d1204d70dd51866ce025Timo Sirainenbool mail_index_view_sync_next(struct mail_index_view_sync_ctx *ctx,
61d3fd14828b68d789f3df73d1dbed56e37b7931Timo Sirainen return mail_index_view_sync_next_lost(ctx, sync_rec);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if (ctx->hdr == NULL || ctx->data_offset == ctx->hdr->size) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen ret = mail_index_view_sync_get_next_transaction(ctx);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen } while (!mail_index_view_sync_get_rec(ctx, sync_rec));
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainenvoid mail_index_view_sync_get_expunges(struct mail_index_view_sync_ctx *ctx,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainenmail_index_view_sync_clean_log_syncs(struct mail_index_view *view)
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen const struct mail_index_view_log_sync_area *syncs;
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen unsigned int i, count;
d25877a69c21fcd004f77bbfb1b8d0895d78e4ddTimo Sirainen /* Clean up to view's tail */
aeea3dbd1f4031634f7b318614adf51dcfc79f42Timo Sirainen syncs = array_get(&view->syncs_hidden, &count);
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen for (i = 0; i < count; i++) {
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen syncs[i].length > view->log_file_expunge_offset &&
6b6011c2242e470b41316f92512b282b5e306dacTimo Sirainen syncs[i].log_file_seq == view->log_file_expunge_seq) ||
6b6011c2242e470b41316f92512b282b5e306dacTimo Sirainen syncs[i].log_file_seq > view->log_file_expunge_seq)
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainenint mail_index_view_sync_commit(struct mail_index_view_sync_ctx **_ctx,
16dfe1f9c1c1a5abc5e5a12efa25619586f7e4e6Timo Sirainen if ((!ctx->last_read || view->inconsistent) &&
16dfe1f9c1c1a5abc5e5a12efa25619586f7e4e6Timo Sirainen (ctx->flags & MAIL_INDEX_VIEW_SYNC_FLAG_FIX_INCONSISTENT) == 0) {
16dfe1f9c1c1a5abc5e5a12efa25619586f7e4e6Timo Sirainen /* we didn't sync everything */
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen mail_index_modseq_sync_end(&ctx->sync_map_ctx.modseq_ctx);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* log offsets have no meaning in views. make sure they're not
1ee1a73bde20380ba39d572681397ad05dcdf9a1Timo Sirainen tried to be used wrong by setting them to zero. */
2ed2459dbd183bb371da4a0aecb2d2b74ae7c815Timo Sirainen i_assert(view->map->hdr.messages_count >= ctx->finish_min_msg_count);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen view->log_file_expunge_seq = view->log_file_head_seq;
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen view->log_file_expunge_offset = view->log_file_head_offset;
b9dce659b9135c87c7708b2bb0f14e8742db7e15Timo Sirainen mail_index_sync_map_deinit(&ctx->sync_map_ctx);
b9dce659b9135c87c7708b2bb0f14e8742db7e15Timo Sirainen mail_index_view_sync_clean_log_syncs(ctx->view);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* set log view to empty range so unneeded memory gets freed */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen mail_transaction_log_view_clear(view->log_view,
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen view->highest_modseq = mail_index_map_modseq_get_highest(view->map);
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainenvoid mail_index_view_add_hidden_transaction(struct mail_index_view *view,
ee77aba32f3d05ecd87cca445c77e1f1095035e2Timo Sirainen unsigned int length)