mail-index-view-sync.c revision b9c44feadade0481b957f2978640afb3317bd1df
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (c) 2003-2008 Dovecot authors, see the included COPYING file */
f1765f773591385d513fb68e1799fd1cb4206852Timo Sirainen /* After syncing view, map is replaced with sync_new_map. */
94a8cb0ee1d85569ad1a2acacd92d3ce22f8a1cbTimo Sirainenmail_transaction_log_sort_expunges(ARRAY_TYPE(seq_range) *expunges,
94a8cb0ee1d85569ad1a2acacd92d3ce22f8a1cbTimo Sirainen /* Note that all the sequences are actually still UIDs at this point */
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen /* @UNSAFE */
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen dest = array_get_modifiable(expunges, &dest_count);
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen array_append(expunges, src, src_size / sizeof(*src));
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen /* src[] must be sorted. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen (src+1 != src_end && src->seq2 >= src[1].seq1))
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen for (; i < dest_count; i++) {
94a8cb0ee1d85569ad1a2acacd92d3ce22f8a1cbTimo Sirainen while (i < dest_count && src->seq2 >= dest[i].seq1-1) {
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen /* we can/must merge with next record */
94a8cb0ee1d85569ad1a2acacd92d3ce22f8a1cbTimo Sirainen if (first > 0 && new_exp.seq1 <= dest[first-1].seq2+1) {
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen /* continue previous record */
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen } else if (i == first) {
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen dest = array_get_modifiable(expunges, &dest_count);
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen /* use next record */
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen dest = array_get_modifiable(expunges, &dest_count);
49e9acb52bb5d328f8cf10bce1082c4bc213caeaTimo Sirainenview_sync_set_log_view_range(struct mail_index_view *view, bool sync_expunges,
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen const struct mail_index_header *hdr = &view->index->map->hdr;
1d06a935b555024420d1c22249f0c847e51a9b7aTimo Sirainen /* we'll just directly to the end */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* the view begins from the first non-synced transaction */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen ret = mail_transaction_log_view_set(view->log_view,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* FIXME: use the new index to get needed
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen "Transaction log got desynced for index %s",
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* we can't do this. sync only up to reset. */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen mail_transaction_log_view_get_prev_pos(view->log_view,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* we have only this reset log */
c680a6b35b459045e92814778908da5a93922107Timo Sirainen mail_transaction_log_view_clear(view->log_view,
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainenview_sync_get_expunges(struct mail_index_view *view,
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen if (view_sync_set_log_view_range(view, TRUE, FALSE, &reset) < 0)
5cdd348121e62a6244ba2f93db781731f7129a71Timo Sirainen /* get a list of expunge transactions. there may be some that we have
5cdd348121e62a6244ba2f93db781731f7129a71Timo Sirainen already synced, but it doesn't matter because they'll get dropped
5cdd348121e62a6244ba2f93db781731f7129a71Timo Sirainen out when converting to sequences */
659fe5d24825b160cae512538088020d97a60239Timo Sirainen while ((ret = mail_transaction_log_view_next(view->log_view,
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) == 0)
e063aca6bc2f08bec516d4b631052ea9191f011dTimo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) {
e063aca6bc2f08bec516d4b631052ea9191f011dTimo Sirainen /* this is simply a request for expunge */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (mail_transaction_log_sort_expunges(expunges_r, data,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_transaction_log_view_set_corrupted(view->log_view,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "Corrupted expunge record");
94a8cb0ee1d85569ad1a2acacd92d3ce22f8a1cbTimo Sirainen /* convert UIDs to sequences */
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen src = dest = array_get_modifiable(expunges_r, &count);
3da614c39dd29f536c485089e67839b4cf89fed3Timo Sirainen if (!mail_index_lookup_seq_range(view, src->seq1, src->seq2,
b032dc80e358f09893f09999f172ff12f5dbbb8eTimo Sirainen array_delete(expunges_r, count, array_count(expunges_r) - count);
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainenstatic bool have_existing_expunges(struct mail_index_view *view,
3da614c39dd29f536c485089e67839b4cf89fed3Timo Sirainen if (mail_index_lookup_seq_range(view, range->seq1, range->seq2,
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainenstatic bool view_sync_have_expunges(struct mail_index_view *view)
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen mail_transaction_log_view_get_prev_pos(view->log_view,
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen while ((ret = mail_transaction_log_view_next(view->log_view,
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) == 0)
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) {
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen /* this is simply a request for expunge */
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen /* we have an expunge. see if it still exists. */
88187ee880b4829443e0d55ea7d145d9d5880217Timo Sirainen if (have_existing_expunges(view, data, hdr->size)) {
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen mail_transaction_log_view_seek(view->log_view, seq, offset);
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen /* handle failures as having expunges (which is safer).
ba94d6d7e2f7b07d51f5c27e7532f6502ac9a298Timo Sirainen we'll probably fail later. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint mail_index_view_sync_begin(struct mail_index_view *view,
687794a61c9e3bf27c712b442b8fc8836c63ae44Timo Sirainen unsigned int expunge_count = 0;
f1765f773591385d513fb68e1799fd1cb4206852Timo Sirainen bool reset, sync_expunges, quick_sync, have_expunges;
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen quick_sync = (flags & MAIL_INDEX_VIEW_SYNC_FLAG_FIX_INCONSISTENT) != 0;
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen if ((flags & MAIL_INDEX_VIEW_SYNC_FLAG_FIX_INCONSISTENT) == 0) {
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen "%s view is inconsistent",
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen sync_expunges = (flags & MAIL_INDEX_VIEW_SYNC_FLAG_NOEXPUNGES) == 0;
1d06a935b555024420d1c22249f0c847e51a9b7aTimo Sirainen /* get list of all expunges first */
1d06a935b555024420d1c22249f0c847e51a9b7aTimo Sirainen if (view_sync_get_expunges(view, &expunges, &expunge_count) < 0)
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen if (view_sync_set_log_view_range(view, sync_expunges, quick_sync,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx = i_new(struct mail_index_view_sync_ctx, 1);
fb36dcb603524f860f1e4edf987fd3b028acac6fTimo Sirainen ctx->finish_min_msg_count = reset || quick_sync ? 0 :
687794a61c9e3bf27c712b442b8fc8836c63ae44Timo Sirainen view->map->hdr.messages_count - expunge_count;
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen mail_index_sync_map_init(&ctx->sync_map_ctx, view,
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen if (reset && view->map->hdr.messages_count > 0 &&
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen (flags & MAIL_INDEX_VIEW_SYNC_FLAG_FIX_INCONSISTENT) == 0) {
530c3ece3717ad8193046ea7774227f91971a0dcTimo Sirainen "%s reset, view is now inconsistent",
f1765f773591385d513fb68e1799fd1cb4206852Timo Sirainen have_expunges = view_sync_have_expunges(view);
f1765f773591385d513fb68e1799fd1cb4206852Timo Sirainen /* no expunges, we can just replace the map */
07afd4db18860589803c46a3ee0559bda1c9e1b4Timo Sirainen "Index %s lost messages without expunging "
f1765f773591385d513fb68e1799fd1cb4206852Timo Sirainen /* expunges seen. create a private map which we update.
f1765f773591385d513fb68e1799fd1cb4206852Timo Sirainen if we're syncing expunges the map will finally be replaced
f1765f773591385d513fb68e1799fd1cb4206852Timo Sirainen with the head map to remove the expunged messages. */
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* Syncing the view invalidates all previous looked up records.
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen Unreference the mappings this view keeps because of them. */
24c6aaf3c540d078021bb4a326982ae4e3d7eaf8Timo Sirainenview_sync_is_hidden(struct mail_index_view *view, uint32_t seq, uoff_t offset)
87ca2e468841829b44c09d618ac02f61a30b7a49Timo Sirainen const struct mail_index_view_log_sync_area *syncs;
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen unsigned int i, count;
8ef80b0b9c73fb0a0188788b14b3e15084b7a452Timo Sirainen syncs = array_get(&view->syncs_hidden, &count);
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen for (i = 0; i < count; i++) {
87ca2e468841829b44c09d618ac02f61a30b7a49Timo Sirainen offset - syncs[i].log_file_offset < syncs[i].length &&
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainenmail_index_view_sync_want(struct mail_index_view_sync_ctx *ctx,
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen mail_transaction_log_view_get_prev_pos(view->log_view, &seq, &offset);
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen next_offset = offset + sizeof(*hdr) + hdr->size;
8ef80b0b9c73fb0a0188788b14b3e15084b7a452Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) != 0 &&
8ef80b0b9c73fb0a0188788b14b3e15084b7a452Timo Sirainen (hdr->type & MAIL_TRANSACTION_EXTERNAL) != 0) {
8ef80b0b9c73fb0a0188788b14b3e15084b7a452Timo Sirainen if ((ctx->flags & MAIL_INDEX_VIEW_SYNC_FLAG_NOEXPUNGES) != 0) {
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen if (LOG_IS_BEFORE(seq, offset, view->log_file_expunge_seq,
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen /* already synced */
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen if (LOG_IS_BEFORE(seq, offset, view->log_file_head_seq,
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen /* already synced */
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,
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen /* skip records we've already synced */
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen } while (!mail_index_view_sync_want(ctx, hdr));
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen mail_transaction_log_view_get_prev_pos(log_view, &seq, &offset);
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen /* If we started from a map that we didn't create ourself,
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen some of the transactions may already be synced. at the end
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen of this view sync we'll update file_seq=0 so that this check
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen always becomes FALSE for subsequent syncs. */
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen synced_to_map = view->map->hdr.log_file_seq != 0 &&
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen LOG_IS_BEFORE(seq, offset, view->map->hdr.log_file_seq,
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen /* Apply transaction to view's mapping if needed (meaning we
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen didn't just re-map the view to head mapping). */
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen i_assert((hdr->type & MAIL_TRANSACTION_EXPUNGE) == 0 ||
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen (hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0);
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen ret = mail_index_sync_record(&ctx->sync_map_ctx,
b9c44feadade0481b957f2978640afb3317bd1dfTimo Sirainen ctx->hidden = view_sync_is_hidden(view, seq, offset);
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 */
e063aca6bc2f08bec516d4b631052ea9191f011dTimo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) {
e063aca6bc2f08bec516d4b631052ea9191f011dTimo Sirainen /* this is simply a request for expunge */
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);
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;
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainenbool 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));
94a8cb0ee1d85569ad1a2acacd92d3ce22f8a1cbTimo Sirainenvoid mail_index_view_sync_get_expunges(struct mail_index_view_sync_ctx *ctx,
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainenmail_index_view_sync_clean_log_syncs(struct mail_index_view *view)
87ca2e468841829b44c09d618ac02f61a30b7a49Timo Sirainen const struct mail_index_view_log_sync_area *syncs;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen unsigned int i, count;
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen /* Clean up to view's tail */
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen syncs = array_get(&view->syncs_hidden, &count);
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen for (i = 0; i < count; i++) {
cc6ed00c61fda24799c905e403b94a2a8c39ae5cTimo Sirainen syncs[i].length > view->log_file_expunge_offset &&
cc6ed00c61fda24799c905e403b94a2a8c39ae5cTimo Sirainen syncs[i].log_file_seq == view->log_file_expunge_seq) ||
cc6ed00c61fda24799c905e403b94a2a8c39ae5cTimo Sirainen syncs[i].log_file_seq > view->log_file_expunge_seq)
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainenint mail_index_view_sync_commit(struct mail_index_view_sync_ctx **_ctx)
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen if ((!ctx->last_read || view->inconsistent) &&
62f4a199b5c9a0862f486cbf18e195cc621bbe25Timo Sirainen (ctx->flags & MAIL_INDEX_VIEW_SYNC_FLAG_FIX_INCONSISTENT) == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we didn't sync everything */
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen mail_index_modseq_sync_end(&ctx->sync_map_ctx.modseq_ctx);
687794a61c9e3bf27c712b442b8fc8836c63ae44Timo Sirainen i_assert(view->map->hdr.messages_count >= ctx->finish_min_msg_count);
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen view->log_file_expunge_seq = view->log_file_head_seq;
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen view->log_file_expunge_offset = view->log_file_head_offset;
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen /* log offsets have no meaning in views. make sure they're not
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen tried to be used wrong by setting them to zero. */
20b9283d4af31e45e588014da427fb2dbcd3227aTimo Sirainen mail_index_sync_map_deinit(&ctx->sync_map_ctx);
0d70a702dec63d22535684fec6a7247c5f153208Timo Sirainen mail_index_view_sync_clean_log_syncs(ctx->view);
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen /* set log view to empty range so unneeded memory gets freed */
c680a6b35b459045e92814778908da5a93922107Timo Sirainen mail_transaction_log_view_clear(view->log_view,
03739a8eaad2d8b34b9d87dbbe5b13c5d5dfa11aTimo Sirainenvoid mail_index_view_add_hidden_transaction(struct mail_index_view *view,
87ca2e468841829b44c09d618ac02f61a30b7a49Timo Sirainen unsigned int length)