mail-index-view-sync.c revision 8afec4d1a32b78f540257a27769b372aad753384
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen array_t ARRAY_DEFINE(expunges, struct mail_transaction_expunge);
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainenmail_transaction_log_sort_expunges(array_t *expunges,
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen ARRAY_SET_TYPE(expunges, struct mail_transaction_expunge);
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen const struct mail_transaction_expunge *src_end;
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen /* @UNSAFE */
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen dest = array_get_modifyable(expunges, &dest_count);
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen array_append(expunges, src, src_size / sizeof(*src));
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen /* src[] must be sorted. */
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen i_assert(src+1 == src_end || src->uid2 < src[1].uid1);
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen for (; i < dest_count; i++) {
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen while (i < dest_count && src->uid2 >= dest[i].uid1-1) {
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen /* we can/must merge with next record */
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen if (first > 0 && new_exp.uid1 <= dest[first-1].uid2+1) {
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen /* continue previous record */
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen } else if (i == first) {
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen dest = array_get_modifyable(expunges, &dest_count);
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen /* use next record */
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen dest = array_get_modifyable(expunges, &dest_count);
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainenview_sync_get_expunges(struct mail_index_view *view, array_t *expunges_r)
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen ARRAY_SET_TYPE(expunges_r, struct mail_transaction_expunge);
659fe5d24825b160cae512538088020d97a60239Timo Sirainen struct mail_transaction_expunge *src, *src_end, *dest;
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen unsigned int count;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_transaction_log_view_set(view->log_view,
659fe5d24825b160cae512538088020d97a60239Timo Sirainen while ((ret = mail_transaction_log_view_next(view->log_view,
7b3bf1de3fa7eee2185d1e404812b50c295e2b93Timo Sirainen i_assert((hdr->type & MAIL_TRANSACTION_EXPUNGE) != 0);
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen mail_transaction_log_sort_expunges(expunges_r, data, hdr->size);
7b3bf1de3fa7eee2185d1e404812b50c295e2b93Timo Sirainen /* convert to sequences */
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen src = dest = array_get_modifyable(expunges_r, &count);
7b3bf1de3fa7eee2185d1e404812b50c295e2b93Timo Sirainen ret = mail_index_lookup_uid_range(view, src->uid1,
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen array_delete(expunges_r, count, array_count(expunges_r) - count);
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD | MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE)
d6f50f100ce17fa4b3a89e9567a5ff993b38b872Timo Sirainen (MAIL_TRANSACTION_EXPUNGE | MAIL_TRANSACTION_APPEND | \
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen MAIL_TRANSACTION_FLAG_UPDATE | MAIL_TRANSACTION_KEYWORD_UPDATE | \
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_index_view_sync_begin(struct mail_index_view *view,
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen enum mail_transaction_type log_get_mask, visible_mask;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* We must sync flags as long as view is mmap()ed, as the flags may
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen have already changed under us. */
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen i_assert((sync_mask & MAIL_INDEX_VIEW_VISIBLE_FLAGS_MASK) ==
18634dae6e304bac982bb1e0ff1b6b88fc448dbcTimo Sirainen /* Currently we're not handling correctly expunges + no-appends case */
18634dae6e304bac982bb1e0ff1b6b88fc448dbcTimo Sirainen i_assert((sync_mask & MAIL_INDEX_SYNC_TYPE_EXPUNGE) == 0 ||
18634dae6e304bac982bb1e0ff1b6b88fc448dbcTimo Sirainen (sync_mask & MAIL_INDEX_SYNC_TYPE_APPEND) != 0);
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (mail_index_view_lock_head(view, TRUE) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((sync_mask & MAIL_INDEX_SYNC_TYPE_EXPUNGE) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* get list of all expunges first */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (view_sync_get_expunges(view, &expunges) < 0)
bcf5af3335a814e4923ba1bf2e0d80eb6dabfb22Timo Sirainen /* only flags, appends and expunges can be left to be synced later */
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen visible_mask = mail_transaction_type_mask_get(sync_mask);
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen i_assert((visible_mask & ~MAIL_TRANSACTION_VISIBLE_SYNC_MASK) == 0);
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* we want to also get non-visible changes. especially because we use
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen the returned skipped-flag in mail_transaction_log_view_next() to
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen tell us if any visible changes were skipped. */
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen log_get_mask = visible_mask | (MAIL_TRANSACTION_TYPE_MASK ^
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_transaction_log_view_set(view->log_view,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx = i_new(struct mail_index_view_sync_ctx, 1);
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen mail_index_sync_map_init(&ctx->sync_map_ctx, view,
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen if ((sync_mask & MAIL_INDEX_SYNC_TYPE_EXPUNGE) != 0 &&
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen (sync_mask & MAIL_INDEX_SYNC_TYPE_APPEND) != 0) {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen /* keep the old mapping without expunges until we're
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen fully synced */
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* We need a private copy of the map if we don't want to
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen sync expunges.
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen If view's map is the head map, it means that it contains
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen already all the latest changes and there's no need for us
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen to apply any changes to it. This can only happen if there
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen hadn't been any expunges. */
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen uint32_t old_records_count = view->map->records_count;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* Using non-head mapping. We have to apply
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen transactions to it to get latest changes into it. */
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* Copy only the mails that we see currently, since
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen we're going to append the new ones when we see
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen their transactions. */
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen view->map->records_count = view->hdr.messages_count;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* Start the sync using our old view's header.
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen The old view->hdr may differ from map->hdr if
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen another view sharing the map with us had synced
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen i_assert(map->hdr_base == map->hdr_copy_buf->data);
20c26f4fcf9ef87434761829cc209c2f84ff5716Timo Sirainen i_assert(map->records_count == map->hdr.messages_count);
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* Syncing the view invalidates all previous looked up records.
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen Unreference the mappings this view keeps because of them. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int view_is_transaction_synced(struct mail_index_view *view,
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen const struct mail_index_view_log_sync_pos *pos;
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen unsigned int i, count;
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen for (i = 0; i < count; i++) {
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainenmail_index_view_sync_get_next_transaction(struct mail_index_view_sync_ctx *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_transaction_log_view *log_view = ctx->view->log_view;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* Get the next transaction from log. */
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen ret = mail_transaction_log_view_next(log_view, &ctx->hdr,
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen mail_transaction_log_view_get_prev_pos(log_view, &seq, &offset);
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* We skipped some (visible) transactions that were
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen outside our sync mask. */
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* We haven't skipped anything while syncing this view.
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen Update this view's synced log offset. */
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen view->log_file_offset = offset + sizeof(*ctx->hdr) +
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* skip flag changes that we committed ourself or have
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen already synced */
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen if (view_is_transaction_synced(view, seq, offset))
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* Apply transaction to view's mapping if needed (meaning we
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen didn't just re-map the view to head mapping). */
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen if (mail_index_sync_record(&ctx->sync_map_ctx,
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen if ((ctx->hdr->type & ctx->visible_sync_mask) == 0) {
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* non-visible change that we just wanted to update
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* We've been skipping some transactions, which means we'll
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen go through these same transaction again later. Since we're
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen syncing this one, we don't want to do it again. */
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen mail_index_view_add_synced_transaction(view, seq, offset);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen ~(MAIL_INDEX_MAIL_FLAG_DIRTY | MAIL_RECENT)) == 0)
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainenmail_index_view_sync_get_rec(struct mail_index_view_sync_ctx *ctx,
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen const struct mail_transaction_header *hdr = ctx->hdr;
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* data contains the appended records, but we don't care */
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* data contains mail_transaction_expunge[] */
d67f54632110cfb6aafe2d7cd1f99b031c0b208aTimo Sirainen const struct mail_transaction_flag_update *update =
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* data contains mail_transaction_flag_update[] */
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* skip internal flag changes */
d0143523a87b41eae0b118ff03aad539903b3555Timo Sirainen update = CONST_PTR_OFFSET(data, ctx->data_offset);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const struct mail_transaction_keyword_update *update = data;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* data contains mail_transaction_keyword_update header,
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen the keyword name and an array of { uint32_t uid1, uid2; } */
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* skip over the header and name */
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen ctx->data_offset = sizeof(*update) + update->name_size;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen ctx->data_offset += 4 - (ctx->data_offset % 4);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen uids = CONST_PTR_OFFSET(data, ctx->data_offset);
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* FIXME: rec->keyword_idx isn't set, but no-one cares
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen currently. perhaps the whole view syncing API should just
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen be returning type and uid range.. */
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen const struct mail_transaction_keyword_reset *reset =
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* data contains mail_transaction_keyword_reset[] */
26ff8f8a4867bf8e9551a27a2de8c12cd138b065Timo Sirainen rec->type = MAIL_INDEX_SYNC_TYPE_KEYWORD_RESET;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_index_view_sync_next(struct mail_index_view_sync_ctx *ctx,
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen if (ctx->hdr == NULL || ctx->data_offset == ctx->hdr->size) {
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen ret = mail_index_view_sync_get_next_transaction(ctx);
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen } while (!mail_index_view_sync_get_rec(ctx, sync_rec));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmail_index_view_sync_get_expunges(struct mail_index_view_sync_ctx *ctx,
9d3ccd79130199ffdb19a688027d49bf20a4aaaaTimo Sirainen unsigned int *count_r)
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainenmail_index_view_sync_clean_log_syncs(struct mail_index_view_sync_ctx *ctx)
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen const struct mail_index_view_log_sync_pos *pos;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen unsigned int i, count;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* Nothing skipped. Clean it up the quick way. */
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* Clean up until view's current syncing position */
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen for (i = 0; i < count; i++) {
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen if ((pos[i].log_file_offset >= view->log_file_offset &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid mail_index_view_sync_end(struct mail_index_view_sync_ctx *ctx)
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen mail_index_sync_map_deinit(&ctx->sync_map_ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we didn't sync everything */
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen (void)mail_transaction_log_view_set(view->log_view,