mail-index-view-sync.c revision 3b80595fcf2001cf7b2fcc6290823e38f4a142fc
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
f81a4d2002da0db33d11ca694d3a91b3ee2a0fdbTimo Sirainenmail_transaction_log_sort_expunges(ARRAY_TYPE(seq_range) *expunges,
f81a4d2002da0db33d11ca694d3a91b3ee2a0fdbTimo Sirainen /* Note that all the sequences are actually still UIDs at this point */
2c677e9d339bc91d5b54376ba2986f71476c06abTimo Sirainen /* @UNSAFE */
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainen dest = array_get_modifiable(expunges, &dest_count);
945631faab2bf1aed8d95a1fd0c317a9ce153725Timo Sirainen array_append(expunges, src, src_size / sizeof(*src));
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* src[] must be sorted. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen (src+1 != src_end && src->seq2 >= src[1].seq1))
945631faab2bf1aed8d95a1fd0c317a9ce153725Timo Sirainen for (; i < dest_count; i++) {
945631faab2bf1aed8d95a1fd0c317a9ce153725Timo Sirainen while (i < dest_count && src->seq2 >= dest[i].seq1-1) {
945631faab2bf1aed8d95a1fd0c317a9ce153725Timo Sirainen /* we can/must merge with next record */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (first > 0 && new_exp.seq1 <= dest[first-1].seq2+1) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* continue previous record */
d7095f3a4466fbb78b2d5eb3d322bc15a5b0ab1fTimo Sirainen } else if (i == first) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen dest = array_get_modifiable(expunges, &dest_count);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* use next record */
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen dest = array_get_modifiable(expunges, &dest_count);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenview_sync_set_log_view_range(struct mail_index_view *view, bool sync_expunges)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen const struct mail_index_header *hdr = &view->index->map->hdr;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* the view begins from the first non-synced transaction */
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen ret = mail_transaction_log_view_set(view->log_view,
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen /* FIXME: use the new index to get needed
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen "Transaction log got desynced for index %s",
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen /* we can't do this. sync only up to reset. */
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen mail_transaction_log_view_get_prev_pos(view->log_view,
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen /* we have only this reset log */
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen mail_transaction_log_view_clear(view->log_view);
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainenview_sync_get_expunges(struct mail_index_view *view,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (view_sync_set_log_view_range(view, TRUE) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* get a list of expunge transactions. there may be some that we have
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen already synced, but it doesn't matter because they'll get dropped
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen out when converting to sequences */
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen while ((ret = mail_transaction_log_view_next(view->log_view,
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) == 0)
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) {
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen /* this is simply a request for expunge */
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen if (mail_transaction_log_sort_expunges(expunges_r, data,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_transaction_log_view_set_corrupted(view->log_view,
1cad0dd34667548ba39f794ddeb9fc486cf4c666Timo Sirainen "Corrupted expunge record");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* convert UIDs to sequences */
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen src = dest = array_get_modifiable(expunges_r, &count);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen mail_index_lookup_uid_range(view, src->seq1, src->seq2,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen array_delete(expunges_r, count, array_count(expunges_r) - count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic bool have_existing_expunges(struct mail_index_view *view,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_lookup_uid_range(view, range->seq1, range->seq2,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic bool view_sync_have_expunges(struct mail_index_view *view)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_transaction_log_view_get_prev_pos(view->log_view,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen while ((ret = mail_transaction_log_view_next(view->log_view,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) == 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* this is simply a request for expunge */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* we have an expunge. see if it still exists. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (have_existing_expunges(view, data, hdr->size)) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_transaction_log_view_seek(view->log_view, seq, offset);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* handle failures as having expunges (which is safer).
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen we'll probably fail later. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenint mail_index_view_sync_begin(struct mail_index_view *view,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen unsigned int expunge_count = 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_set_error(view->index, "%s view is inconsistent",
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen sync_expunges = (flags & MAIL_INDEX_VIEW_SYNC_FLAG_NOEXPUNGES) == 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* get list of all expunges first */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (view_sync_set_log_view_range(view, sync_expunges) < 0) {
abfcd9f73b9ad1eeef4fe6e9940383defabf68c3Timo Sirainen ctx = i_new(struct mail_index_view_sync_ctx, 1);
abfcd9f73b9ad1eeef4fe6e9940383defabf68c3Timo Sirainen view->map->hdr.messages_count - expunge_count;
abfcd9f73b9ad1eeef4fe6e9940383defabf68c3Timo Sirainen mail_index_sync_map_init(&ctx->sync_map_ctx, view,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (sync_expunges || !view_sync_have_expunges(view)) {
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen i_assert(view->index->map->hdr.messages_count >=
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen /* keep the old mapping without expunges until we're
9887c39c5ba429169389153ca99de49e084a73f0Timo Sirainen fully synced */
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen /* We need a private copy of the map if we don't want to
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen sync expunges.
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen If view's map is the head map, it means that it contains
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen already all the latest changes and there's no need for us
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen to apply any changes to it. This can only happen if there
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen hadn't been any expunges. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* Using non-head mapping. We have to apply
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen transactions to it to get latest changes into it. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* Syncing the view invalidates all previous looked up records.
41bb0aa8e357876bc9a1916a37c9e3e78e5f8185Timo Sirainen Unreference the mappings this view keeps because of them. */
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenview_sync_is_hidden(struct mail_index_view *view, uint32_t seq, uoff_t offset)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct mail_index_view_log_sync_area *syncs;
7394389230750c45b105cdefb5850c81cae8cdc0Timo Sirainen unsigned int i, count;
659fe5d24825b160cae512538088020d97a60239Timo Sirainen syncs = array_get(&view->syncs_hidden, &count);
567e57b09a49bbb2a146b13f8617698eb56237feTimo Sirainen for (i = 0; i < count; i++) {
567e57b09a49bbb2a146b13f8617698eb56237feTimo Sirainen offset - syncs[i].log_file_offset < syncs[i].length &&
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenmail_index_view_sync_want(struct mail_index_view_sync_ctx *ctx,
51920d00fa50edf7b2e9b1019288d64b7abee7f3Timo Sirainen mail_transaction_log_view_get_prev_pos(view->log_view, &seq, &offset);
21ec6628c567eeff025af35d8027be01044b0b1aTimo Sirainen next_offset = offset + sizeof(*hdr) + hdr->size;
21ec6628c567eeff025af35d8027be01044b0b1aTimo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) != 0 &&
21ec6628c567eeff025af35d8027be01044b0b1aTimo Sirainen (hdr->type & MAIL_TRANSACTION_EXTERNAL) != 0) {
fa5957ffc9b676bfd649fa9953e63e72ee4ebeb4Timo Sirainen if ((ctx->flags & MAIL_INDEX_VIEW_SYNC_FLAG_NOEXPUNGES) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (LOG_IS_BEFORE(seq, offset, view->log_file_expunge_seq,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen /* already synced */
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen if (LOG_IS_BEFORE(seq, offset, view->log_file_head_seq,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen /* already synced */
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainenmail_index_view_sync_get_next_transaction(struct mail_index_view_sync_ctx *ctx)
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen struct mail_transaction_log_view *log_view = ctx->view->log_view;
5a7b52012bf77132bb8f466d07e0e88c63fdba42Timo Sirainen /* Get the next transaction from log. */
5a7b52012bf77132bb8f466d07e0e88c63fdba42Timo Sirainen ret = mail_transaction_log_view_next(log_view, &ctx->hdr,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* This is a visible record that we don't want to
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen mail_transaction_log_view_get_prev_pos(log_view, &seq, &offset);
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen /* If we started from a map that we didn't create ourself,
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen some of the transactions may already be synced. at the end
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen of this view sync we'll update file_seq=0 so that this check
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen always becomes FALSE for subsequent syncs. */
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen synced_to_map = view->map->hdr.log_file_seq != 0 &&
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen /* Apply transaction to view's mapping if needed (meaning we
e063aca6bc2f08bec516d4b631052ea9191f011dTimo Sirainen didn't just re-map the view to head mapping). */
e063aca6bc2f08bec516d4b631052ea9191f011dTimo Sirainen i_assert((hdr->type & MAIL_TRANSACTION_EXPUNGE) == 0 ||
e063aca6bc2f08bec516d4b631052ea9191f011dTimo Sirainen (hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (mail_index_sync_record(&ctx->sync_map_ctx,
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen /* skip changes committed by hidden transactions (eg. in IMAP
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen store +flags.silent command) */
d143077bd518de129b8d446fb58e003903e50867Timo Sirainenmail_index_view_sync_get_rec(struct mail_index_view_sync_ctx *ctx,
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen const struct mail_transaction_header *hdr = ctx->hdr;
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen /* data contains the appended records, but we don't care */
2c677e9d339bc91d5b54376ba2986f71476c06abTimo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) {
2c677e9d339bc91d5b54376ba2986f71476c06abTimo Sirainen /* this is simply a request for expunge */
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen /* data contains mail_transaction_expunge[] */
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen const struct mail_transaction_flag_update *update =
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen /* data contains mail_transaction_flag_update[] */
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen /* skip internal flag changes */
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen update = CONST_PTR_OFFSET(data, ctx->data_offset);
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen const struct mail_transaction_keyword_update *update = data;
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen /* data contains mail_transaction_keyword_update header,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen the keyword name and an array of { uint32_t uid1, uid2; } */
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen /* skip over the header and name */
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen ctx->data_offset = sizeof(*update) + update->name_size;
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen ctx->data_offset += 4 - (ctx->data_offset % 4);
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen uids = CONST_PTR_OFFSET(data, ctx->data_offset);
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen const struct mail_transaction_keyword_reset *reset =
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen /* data contains mail_transaction_keyword_reset[] */
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen rec->type = MAIL_INDEX_SYNC_TYPE_KEYWORD_RESET;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenbool mail_index_view_sync_next(struct mail_index_view_sync_ctx *ctx,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (ctx->hdr == NULL || ctx->data_offset == ctx->hdr->size) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen ret = mail_index_view_sync_get_next_transaction(ctx);
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen } while (!mail_index_view_sync_get_rec(ctx, sync_rec));
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainenvoid mail_index_view_sync_get_expunges(struct mail_index_view_sync_ctx *ctx,
d143077bd518de129b8d446fb58e003903e50867Timo Sirainenmail_index_view_sync_clean_log_syncs(struct mail_index_view *view)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const struct mail_index_view_log_sync_area *syncs;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen unsigned int i, count;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen /* Clean up to view's tail */
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen syncs = array_get(&view->syncs_hidden, &count);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen for (i = 0; i < count; i++) {
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen syncs[i].length > view->log_file_expunge_offset &&
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen syncs[i].log_file_seq == view->log_file_expunge_seq) ||
d143077bd518de129b8d446fb58e003903e50867Timo Sirainen syncs[i].log_file_seq > view->log_file_expunge_seq)
d143077bd518de129b8d446fb58e003903e50867Timo Sirainenint mail_index_view_sync_commit(struct mail_index_view_sync_ctx **_ctx)
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen /* we didn't sync everything */
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen i_assert(view->map->hdr.messages_count >= ctx->finish_min_msg_count);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen view->log_file_expunge_seq = view->log_file_head_seq;
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen view->log_file_expunge_offset = view->log_file_head_offset;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* log offsets have no meaning in views. make sure they're not
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen tried to be used wrong by setting them to zero. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_sync_map_deinit(&ctx->sync_map_ctx);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_view_sync_clean_log_syncs(ctx->view);
e26a771fad55dfba4d5021d12ed5685c951d9b7bTimo Sirainen /* set log view to empty range so unneeded memory gets freed */
e26a771fad55dfba4d5021d12ed5685c951d9b7bTimo Sirainen mail_transaction_log_view_clear(view->log_view);
e26a771fad55dfba4d5021d12ed5685c951d9b7bTimo Sirainenvoid mail_index_view_add_hidden_transaction(struct mail_index_view *view,
e26a771fad55dfba4d5021d12ed5685c951d9b7bTimo Sirainen unsigned int length)