mail-index-view-sync.c revision a050ca9def13949dbaa67bd6574a41c4f397ae26
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
6b6011c2242e470b41316f92512b282b5e306dacTimo Sirainen array_t ARRAY_DEFINE(expunges, struct mail_transaction_expunge);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainenmail_transaction_log_sort_expunges(array_t *expunges,
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen ARRAY_SET_TYPE(expunges, struct mail_transaction_expunge);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen const struct mail_transaction_expunge *src_end;
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen /* @UNSAFE */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen dest = array_get_modifyable(expunges, &dest_count);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen array_append(expunges, src, src_size / sizeof(*src));
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen /* src[] must be sorted. */
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen i_assert(src+1 == src_end || src->uid2 < src[1].uid1);
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen for (; i < dest_count; i++) {
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen while (i < dest_count && src->uid2 >= dest[i].uid1-1) {
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen /* we can/must merge with next record */
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen if (first > 0 && new_exp.uid1 <= dest[first-1].uid2+1) {
eed03830015b7138b9d4522e72bef650aa24b45fTimo Sirainen /* continue previous record */
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen } else if (i == first) {
a566d9f8797dd66b4d5432a20ab2b9f7c8f76102Timo Sirainen dest = array_get_modifyable(expunges, &dest_count);
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* use next record */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen dest = array_get_modifyable(expunges, &dest_count);
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainenstatic int view_sync_set_log_view_range(struct mail_index_view *view,
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen const struct mail_index_header *hdr = view->index->hdr;
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen ret = mail_transaction_log_view_set(view->log_view,
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen /* FIXME: use the new index to get needed changes */
4fbf59562594dbbbe037f8d4c480dbf88f3fc708Timo Sirainen "Transaction log got desynced for index %s",
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainenview_sync_get_expunges(struct mail_index_view *view, array_t *expunges_r)
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen ARRAY_SET_TYPE(expunges_r, struct mail_transaction_expunge);
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen struct mail_transaction_expunge *src, *src_end, *dest;
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen unsigned int count;
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen if (view_sync_set_log_view_range(view, MAIL_TRANSACTION_EXPUNGE) < 0)
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen while ((ret = mail_transaction_log_view_next(view->log_view,
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen i_assert((hdr->type & MAIL_TRANSACTION_EXPUNGE) != 0);
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen mail_transaction_log_sort_expunges(expunges_r, data, hdr->size);
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen /* convert to sequences */
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen src = dest = array_get_modifyable(expunges_r, &count);
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen ret = mail_index_lookup_uid_range(view, src->uid1,
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen array_delete(expunges_r, count, array_count(expunges_r) - count);
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD | MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE)
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen (MAIL_TRANSACTION_EXPUNGE | MAIL_TRANSACTION_APPEND | \
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainen MAIL_TRANSACTION_FLAG_UPDATE | MAIL_TRANSACTION_KEYWORD_UPDATE | \
38f624b427aa8b6fad3765e6efd97c85a7f97a09Timo Sirainenint mail_index_view_sync_begin(struct mail_index_view *view,
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainen enum mail_transaction_type log_get_mask, visible_mask;
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainen /* We must sync flags as long as view is mmap()ed, as the flags may
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainen have already changed under us. */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen i_assert((sync_mask & MAIL_INDEX_VIEW_VISIBLE_FLAGS_MASK) ==
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen /* Currently we're not handling correctly expunges + no-appends case */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen i_assert((sync_mask & MAIL_INDEX_SYNC_TYPE_EXPUNGE) == 0 ||
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen (sync_mask & MAIL_INDEX_SYNC_TYPE_APPEND) != 0);
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen if (mail_index_view_lock_head(view, TRUE) < 0)
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if ((sync_mask & MAIL_INDEX_SYNC_TYPE_EXPUNGE) != 0) {
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen /* get list of all expunges first */
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen if (view_sync_get_expunges(view, &expunges) < 0)
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* only flags, appends and expunges can be left to be synced later */
e93ab1b206e3792a8dabc460ad2ee60aaf6830b1Timo Sirainen visible_mask = mail_transaction_type_mask_get(sync_mask);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen i_assert((visible_mask & ~MAIL_TRANSACTION_VISIBLE_SYNC_MASK) == 0);
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen /* we want to also get non-visible changes. especially because we use
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen the returned skipped-flag in mail_transaction_log_view_next() to
65514ab6ccc1889e1667211fddb0cca4b51017dfTimo Sirainen tell us if any visible changes were skipped. */
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen log_get_mask = visible_mask | (MAIL_TRANSACTION_TYPE_MASK ^
e5b06a21b5f857d7037fd6ff41ba3bd449d1232aTimo Sirainen if (view_sync_set_log_view_range(view, log_get_mask) < 0) {
6de95f63d4590814354fa5e35e92946c58d4562eTimo Sirainen ctx = i_new(struct mail_index_view_sync_ctx, 1);
6b6011c2242e470b41316f92512b282b5e306dacTimo Sirainen mail_index_sync_map_init(&ctx->sync_map_ctx, view,
315ce5be539bfe8bc7777ab0654499c49583cea2Timo Sirainen if ((sync_mask & MAIL_INDEX_SYNC_TYPE_EXPUNGE) != 0 &&
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen (sync_mask & MAIL_INDEX_SYNC_TYPE_APPEND) != 0) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* keep the old mapping without expunges until we're
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen fully synced */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* We need a private copy of the map if we don't want to
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen sync expunges.
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen If view's map is the head map, it means that it contains
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen already all the latest changes and there's no need for us
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen to apply any changes to it. This can only happen if there
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen hadn't been any expunges. */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen uint32_t old_records_count = view->map->records_count;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* Using non-head mapping. We have to apply
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen transactions to it to get latest changes into it. */
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen /* Copy only the mails that we see currently, since
009217abb57a24a4076092e8e4e165545747839eStephan Bosch we're going to append the new ones when we see
009217abb57a24a4076092e8e4e165545747839eStephan Bosch their transactions. */
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen view->map->records_count = view->hdr.messages_count;
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen /* Start the sync using our old view's header.
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen The old view->hdr may differ from map->hdr if
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen another view sharing the map with us had synced
eed0a07ecb946ec9d021f5b413fb33eb36e135fdTimo Sirainen i_assert(map->hdr_base == map->hdr_copy_buf->data);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen i_assert(map->records_count == map->hdr.messages_count);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* Syncing the view invalidates all previous looked up records.
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen Unreference the mappings this view keeps because of them. */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainenstatic int view_is_transaction_synced(struct mail_index_view *view,
3322dfd56c9cae5015a33bab4c80124c08c3d9caTimo Sirainen const struct mail_index_view_log_sync_pos *pos;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen unsigned int i, count;
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen for (i = 0; i < count; i++) {
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainenmail_index_view_sync_get_next_transaction(struct mail_index_view_sync_ctx *ctx)
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller struct mail_transaction_log_view *log_view = ctx->view->log_view;
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen /* Get the next transaction from log. */
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen ret = mail_transaction_log_view_next(log_view, &ctx->hdr,
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen mail_transaction_log_view_get_prev_pos(log_view, &seq, &offset);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* We skipped some (visible) transactions that were
86fafb22c02f4b85a9d59f2b60059a48286286fbTimo Sirainen outside our sync mask. */
86fafb22c02f4b85a9d59f2b60059a48286286fbTimo Sirainen /* We haven't skipped anything while syncing this view.
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen Update this view's synced log offset. */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen view->log_file_offset = offset + sizeof(*ctx->hdr) +
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* skip flag changes that we committed ourself or have
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen already synced */
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (view_is_transaction_synced(view, seq, offset))
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* Apply transaction to view's mapping if needed (meaning we
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen didn't just re-map the view to head mapping). */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if (mail_index_sync_record(&ctx->sync_map_ctx,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen if ((ctx->hdr->type & ctx->visible_sync_mask) == 0) {
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* non-visible change that we just wanted to update
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* We've been skipping some transactions, which means we'll
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen go through these same transaction again later. Since we're
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen syncing this one, we don't want to do it again. */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen mail_index_view_add_synced_transaction(view, seq, offset);
d2a2e0b6d302c17c33638a6fd48bd665a1c81e46Timo Sirainen ~(MAIL_INDEX_MAIL_FLAG_DIRTY | MAIL_RECENT)) == 0)
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainenmail_index_view_sync_get_rec(struct mail_index_view_sync_ctx *ctx,
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen const struct mail_transaction_header *hdr = ctx->hdr;
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen /* data contains the appended records, but we don't care */
7aa2dd189748ed57c2fb8d8d9b7cb3c4ac2f7ea5Timo Sirainen /* data contains mail_transaction_expunge[] */
d163fac99c7ca5b2ce2edfa83a1b2922cf66aeacTimo Sirainen const struct mail_transaction_flag_update *update =
ddbdc644a15f56f4b43596f1b8c0fc196c101445Timo Sirainen /* data contains mail_transaction_flag_update[] */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen /* skip internal flag changes */
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen update = CONST_PTR_OFFSET(data, ctx->data_offset);
c2ebc8f28b5504f280cd5d4adfe57ed70f9a7d83Timo Sirainen const struct mail_transaction_keyword_update *update = data;
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen /* data contains mail_transaction_keyword_update header,
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen the keyword name and an array of { uint32_t uid1, uid2; } */
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen /* skip over the header and name */
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen ctx->data_offset = sizeof(*update) + update->name_size;
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen ctx->data_offset += 4 - (ctx->data_offset % 4);
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen uids = CONST_PTR_OFFSET(data, ctx->data_offset);
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen const struct mail_transaction_keyword_reset *reset =
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen /* data contains mail_transaction_keyword_reset[] */
a338794c56fc9674121e262fcb67c3dc1da31436Timo Sirainen rec->type = MAIL_INDEX_SYNC_TYPE_KEYWORD_RESET;
7b22071c71a99bcb71ee9fcfbb83ed5bf5e08a2dTimo Sirainenint mail_index_view_sync_next(struct mail_index_view_sync_ctx *ctx,
32efae185f1f86167b3f00ea84f8502940c6c677Timo Sirainen if (ctx->hdr == NULL || ctx->data_offset == ctx->hdr->size) {
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen ret = mail_index_view_sync_get_next_transaction(ctx);
972c9172e9e6a0fc6053efb3d2ee9d354b67727fLennart Weller } while (!mail_index_view_sync_get_rec(ctx, sync_rec));
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainenmail_index_view_sync_get_expunges(struct mail_index_view_sync_ctx *ctx,
9a935c34e98ba7a9cc90784ceb63b2fbdab4105fTimo Sirainen unsigned int *count_r)
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainenmail_index_view_sync_clean_log_syncs(struct mail_index_view_sync_ctx *ctx)
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen const struct mail_index_view_log_sync_pos *pos;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen unsigned int i, count;
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen /* Nothing skipped. Clean it up the quick way. */
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen /* Clean up until view's current syncing position */
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen for (i = 0; i < count; i++) {
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen if ((pos[i].log_file_offset >= view->log_file_offset &&
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainenvoid mail_index_view_sync_end(struct mail_index_view_sync_ctx *ctx)
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen mail_index_sync_map_deinit(&ctx->sync_map_ctx);
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen /* we didn't sync everything */
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen /* set log view to empty range so unneeded memory gets freed */
e7b1f9db0128384b152b58ea65303d66484c9d7bTimo Sirainen (void)mail_transaction_log_view_set(view->log_view,