mail-index-view-sync.c revision d2b0d5daa7350cd0d67f011e8b390a256f5f4218
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainenmail_transaction_log_sort_expunges(ARRAY_TYPE(seq_range) *expunges,
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen /* Note that all the sequences are actually still UIDs at this point */
150e64c376365becf1ec5c9d45912ecb840eea96Timo Sirainen /* @UNSAFE */
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen dest = array_get_modifiable(expunges, &dest_count);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen array_append(expunges, src, src_size / sizeof(*src));
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen /* src[] must be sorted. */
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen i_assert(src+1 == src_end || src->seq2 < src[1].seq1);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen for (; i < dest_count; i++) {
bc3698b8892df8003b410daea6f5bbcd20433808Timo Sirainen while (i < dest_count && src->seq2 >= dest[i].seq1-1) {
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen /* we can/must merge with next record */
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen if (first > 0 && new_exp.seq1 <= dest[first-1].seq2+1) {
ccb77e2f63626ec46e5745ef4f38baa8e8e504fcTimo Sirainen /* continue previous record */
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen } else if (i == first) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen dest = array_get_modifiable(expunges, &dest_count);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen /* use next record */
bd74402ca1a39ec303075fefb1212d7e18a71531Timo Sirainen dest = array_get_modifiable(expunges, &dest_count);
ef11d3930c3602fc86349a4e3a53442df470b601Timo Sirainenstatic int view_sync_set_log_view_range(struct mail_index_view *view,
ef11d3930c3602fc86349a4e3a53442df470b601Timo Sirainen const struct mail_index_header *hdr = view->index->hdr;
ef11d3930c3602fc86349a4e3a53442df470b601Timo Sirainen ret = mail_transaction_log_view_set(view->log_view,
ccb77e2f63626ec46e5745ef4f38baa8e8e504fcTimo Sirainen /* FIXME: use the new index to get needed changes */
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen "Transaction log got desynced for index %s",
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainenview_sync_get_expunges(struct mail_index_view *view,
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen unsigned int count;
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen if (view_sync_set_log_view_range(view, MAIL_TRANSACTION_EXPUNGE) < 0)
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen while ((ret = mail_transaction_log_view_next(view->log_view,
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen i_assert((hdr->type & MAIL_TRANSACTION_EXPUNGE) != 0);
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen mail_transaction_log_sort_expunges(expunges_r, data, hdr->size);
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen /* convert UIDs to sequences */
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen src = dest = array_get_modifiable(expunges_r, &count);
68efcccb384f2d6871164b072457e87473502c51Timo Sirainen ret = mail_index_lookup_uid_range(view, src->seq1,
a54be2bd26d6f0860d194d3aeedfa6b7fc14d24cTimo Sirainen array_delete(expunges_r, count, array_count(expunges_r) - count);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainenstatic void mail_index_view_hdr_update(struct mail_index_view *view,
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen /* Keep message count the same. */
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen map->hdr.messages_count = view->hdr.messages_count;
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen /* Keep the old message flag counts also, although they may be
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen somewhat stale already. We just don't want them to be more than
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen our old messages_count. */
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen map->hdr.recent_messages_count = view->hdr.recent_messages_count;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen map->hdr.seen_messages_count = view->hdr.seen_messages_count;
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainen map->hdr.deleted_messages_count = view->hdr.deleted_messages_count;
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen /* Keep log position so we know where to continue syncing */
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen map->hdr.log_file_seq = view->hdr.log_file_seq;
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen map->hdr.log_file_int_offset = view->hdr.log_file_int_offset;
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen map->hdr.log_file_ext_offset = view->hdr.log_file_ext_offset;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen buffer_write(map->hdr_copy_buf, 0, &map->hdr, sizeof(map->hdr));
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainen MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD | MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE)
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainen (MAIL_TRANSACTION_EXPUNGE | MAIL_TRANSACTION_APPEND | \
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainen MAIL_TRANSACTION_FLAG_UPDATE | MAIL_TRANSACTION_KEYWORD_UPDATE | \
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainenint mail_index_view_sync_begin(struct mail_index_view *view,
68efcccb384f2d6871164b072457e87473502c51Timo Sirainen enum mail_transaction_type log_get_mask, visible_mask;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen /* We must sync flags as long as view is mmap()ed, as the flags may
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen have already changed under us. */
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen i_assert((sync_mask & MAIL_INDEX_VIEW_VISIBLE_FLAGS_MASK) ==
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen /* Currently we're not handling correctly expunges + no-appends case */
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen i_assert((sync_mask & MAIL_INDEX_SYNC_TYPE_EXPUNGE) == 0 ||
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen (sync_mask & MAIL_INDEX_SYNC_TYPE_APPEND) != 0);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen if (mail_index_view_lock_head(view, TRUE) < 0)
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen if ((sync_mask & MAIL_INDEX_SYNC_TYPE_EXPUNGE) != 0) {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen /* get list of all expunges first */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if (view_sync_get_expunges(view, &expunges) < 0)
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen /* only flags, appends and expunges can be left to be synced later */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen visible_mask = mail_transaction_type_mask_get(sync_mask);
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen i_assert((visible_mask & ~MAIL_TRANSACTION_VISIBLE_SYNC_MASK) == 0);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* we want to also get non-visible changes. especially because we use
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen the returned skipped-flag in mail_transaction_log_view_next() to
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen tell us if any visible changes were skipped. */
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen log_get_mask = visible_mask | (MAIL_TRANSACTION_TYPE_MASK ^
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if (view_sync_set_log_view_range(view, log_get_mask) < 0) {
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen ctx = i_new(struct mail_index_view_sync_ctx, 1);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen mail_index_sync_map_init(&ctx->sync_map_ctx, view,
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if ((sync_mask & MAIL_INDEX_SYNC_TYPE_EXPUNGE) != 0 &&
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen (sync_mask & MAIL_INDEX_SYNC_TYPE_APPEND) != 0) {
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* since we're syncing everything, the counters get fixed */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* keep the old mapping without expunges until we're
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen fully synced */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* We need a private copy of the map if we don't want to
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen sync expunges.
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen If view's map is the head map, it means that it contains
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen already all the latest changes and there's no need for us
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen to apply any changes to it. This can only happen if there
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen hadn't been any expunges. */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen uint32_t old_records_count = view->map->records_count;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* Using non-head mapping. We have to apply
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen transactions to it to get latest changes into it. */
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen /* Unless map was synced at the exact same position as
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen view, the message flags can't be reliably used to
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen update flag counters. */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* Copy only the mails that we see currently, since
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen we're going to append the new ones when we see
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen their transactions. */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen view->map->records_count = view->hdr.messages_count;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* Start the sync using our old view's header.
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen The old view->hdr may differ from map->hdr if
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen another view sharing the map with us had synced
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen i_assert(map->hdr_base == map->hdr_copy_buf->data);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen i_assert(map->records_count == map->hdr.messages_count);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* Syncing the view invalidates all previous looked up records.
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen Unreference the mappings this view keeps because of them. */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainenstatic bool view_sync_pos_find(ARRAY_TYPE(view_log_sync_pos) *sync_arr,
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen const struct mail_index_view_log_sync_pos *syncs;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen unsigned int i, count;
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen for (i = 0; i < count; i++) {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainenmail_index_view_sync_get_next_transaction(struct mail_index_view_sync_ctx *ctx)
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen struct mail_transaction_log_view *log_view = ctx->view->log_view;
294f1a51763015cda0e2d874c5027d6fe7a2cd54Timo Sirainen /* Get the next transaction from log. */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen ret = mail_transaction_log_view_next(log_view, &ctx->hdr,
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen /* We skipped some (visible) transactions that were
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen outside our sync mask. Note that we may get here
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen even when ret=0. */
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen mail_transaction_log_view_get_prev_pos(log_view, &seq, &offset);
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen /* We haven't skipped anything while syncing this view.
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen Update this view's synced log offset. */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen view->log_file_offset = offset + sizeof(*ctx->hdr) +
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* skip everything we've already synced */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if (view_sync_pos_find(&view->syncs_done, seq, offset))
2d340205d897e23fbecb40c8e63a4ca49bd6739bTimo Sirainen /* We've been skipping some transactions, which means
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen we'll go through these same transactions again
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen later. Since we're syncing this one, we don't want
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen to do it again. */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen mail_index_view_add_synced_transaction(view, seq,
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* Apply transaction to view's mapping if needed (meaning we
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen didn't just re-map the view to head mapping). */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if (mail_index_sync_record(&ctx->sync_map_ctx,
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if ((ctx->hdr->type & ctx->visible_sync_mask) == 0) {
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* non-visible change that we just wanted to update
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen /* skip changes committed by hidden transactions (eg. in IMAP
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen store +flags.silent command) */
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen if (view_sync_pos_find(&view->syncs_hidden, seq, offset))
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen ~(MAIL_INDEX_MAIL_FLAG_DIRTY | MAIL_RECENT)) == 0)
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainenmail_index_view_sync_get_rec(struct mail_index_view_sync_ctx *ctx,
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen const struct mail_transaction_header *hdr = ctx->hdr;
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen /* data contains the appended records, but we don't care */
case MAIL_TRANSACTION_FLAG_UPDATE: {
case MAIL_TRANSACTION_KEYWORD_UPDATE: {
case MAIL_TRANSACTION_KEYWORD_RESET: {
i_unreached();
int ret;
if (ret <= 0)
return ret;
unsigned int i, count;
for (i = 0; i < count; i++) {