Mercurial > dovecot > original-hg > dovecot-1.2
changeset 6037:d911d943438e HEAD
Recent flag handling rewrite. Still not perfect with maildir.
line wrap: on
line diff
--- a/src/lib-index/mail-index-fsck.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-index/mail-index-fsck.c Mon Jul 16 09:48:02 2007 +0300 @@ -72,11 +72,9 @@ hdr.log_file_seq = file_seq; hdr.messages_count = 0; - hdr.recent_messages_count = 0; hdr.seen_messages_count = 0; hdr.deleted_messages_count = 0; - hdr.first_recent_uid_lowwater = 0; hdr.first_unseen_uid_lowwater = 0; hdr.first_deleted_uid_lowwater = 0; @@ -88,16 +86,11 @@ } hdr.messages_count++; - if ((rec->flags & MAIL_RECENT) != 0) - hdr.recent_messages_count++; if ((rec->flags & MAIL_SEEN) != 0) hdr.seen_messages_count++; if ((rec->flags & MAIL_DELETED) != 0) hdr.deleted_messages_count++; - if ((rec->flags & MAIL_RECENT) != 0 && - hdr.first_recent_uid_lowwater == 0) - hdr.first_recent_uid_lowwater = rec->uid; if ((rec->flags & MAIL_SEEN) == 0 && hdr.first_unseen_uid_lowwater == 0) hdr.first_unseen_uid_lowwater = rec->uid; @@ -115,12 +108,14 @@ hdr.next_uid = last_uid+1; } - if (hdr.first_recent_uid_lowwater == 0) - hdr.first_recent_uid_lowwater = hdr.next_uid; if (hdr.first_unseen_uid_lowwater == 0) hdr.first_unseen_uid_lowwater = hdr.next_uid; if (hdr.first_deleted_uid_lowwater == 0) hdr.first_deleted_uid_lowwater = hdr.next_uid; + if (hdr.first_recent_uid > hdr.next_uid) + hdr.first_recent_uid = hdr.next_uid; + if (hdr.first_recent_uid == 0) + hdr.first_recent_uid = 1; CHECK(log_file_seq, !=); CHECK(log_file_head_offset, !=); @@ -128,13 +123,12 @@ CHECK(uid_validity, !=); CHECK(messages_count, !=); - CHECK(recent_messages_count, !=); CHECK(seen_messages_count, !=); CHECK(deleted_messages_count, !=); - CHECK(first_recent_uid_lowwater, <); CHECK(first_unseen_uid_lowwater, <); CHECK(first_deleted_uid_lowwater, <); + CHECK(first_recent_uid, !=); map->hdr = hdr; return 1;
--- a/src/lib-index/mail-index-map.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-index/mail-index-map.c Mon Jul 16 09:48:02 2007 +0300 @@ -301,11 +301,11 @@ if (hdr->next_uid == 0) return 0; - if (hdr->recent_messages_count > hdr->messages_count || - hdr->seen_messages_count > hdr->messages_count || + if (hdr->seen_messages_count > hdr->messages_count || hdr->deleted_messages_count > hdr->messages_count) return 0; - if (hdr->first_recent_uid_lowwater > hdr->next_uid || + if (hdr->first_recent_uid == 0 || + hdr->first_recent_uid > hdr->next_uid || hdr->first_unseen_uid_lowwater > hdr->next_uid || hdr->first_deleted_uid_lowwater > hdr->next_uid) return 0; @@ -638,6 +638,7 @@ hdr->indexid = index->indexid; hdr->log_file_seq = 1; hdr->next_uid = 1; + hdr->first_recent_uid = 1; } struct mail_index_map *mail_index_map_alloc(struct mail_index *index)
--- a/src/lib-index/mail-index-sync-update.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-index/mail-index-sync-update.c Mon Jul 16 09:48:02 2007 +0300 @@ -93,26 +93,6 @@ uint8_t old_flags, uint8_t new_flags, const char **error_r) { - if (((old_flags ^ new_flags) & MAIL_RECENT) != 0) { - /* different recent-flag */ - if ((old_flags & MAIL_RECENT) == 0) { - hdr->recent_messages_count++; - if (hdr->recent_messages_count > hdr->messages_count) { - *error_r = "Recent counter wrong"; - return -1; - } - } else { - if (hdr->recent_messages_count == 0 || - hdr->recent_messages_count > hdr->messages_count) { - *error_r = "Recent counter wrong"; - return -1; - } - - if (--hdr->recent_messages_count == 0) - hdr->first_recent_uid_lowwater = hdr->next_uid; - } - } - if (((old_flags ^ new_flags) & MAIL_SEEN) != 0) { /* different seen-flag */ if ((old_flags & MAIL_SEEN) != 0) { @@ -169,9 +149,6 @@ mail_index_header_update_lowwaters(struct mail_index_header *hdr, const struct mail_index_record *rec) { - if ((rec->flags & MAIL_RECENT) != 0 && - rec->uid < hdr->first_recent_uid_lowwater) - hdr->first_recent_uid_lowwater = rec->uid; if ((rec->flags & MAIL_SEEN) == 0 && rec->uid < hdr->first_unseen_uid_lowwater) hdr->first_unseen_uid_lowwater = rec->uid; @@ -335,7 +312,7 @@ flag_mask = ~u->remove_flags; if (((u->add_flags | u->remove_flags) & - (MAIL_SEEN | MAIL_DELETED | MAIL_RECENT)) == 0) { + (MAIL_SEEN | MAIL_DELETED)) == 0) { /* we're not modifying any counted/lowwatered flags */ for (idx = seq1-1; idx < seq2; idx++) { rec = MAIL_INDEX_MAP_IDX(view->map, idx); @@ -626,7 +603,7 @@ void mail_index_map_check(struct mail_index_map *map) { const struct mail_index_header *hdr = &map->hdr; - unsigned int i, del = 0, recent = 0, seen = 0; + unsigned int i, del = 0, seen = 0; i_assert(hdr->messages_count == map->records_count); for (i = 0; i < map->records_count; i++) { @@ -638,17 +615,12 @@ i_assert(rec->uid >= hdr->first_deleted_uid_lowwater); del++; } - if (rec->flags & MAIL_RECENT) { - i_assert(rec->uid >= hdr->first_recent_uid_lowwater); - recent++; - } if (rec->flags & MAIL_SEEN) seen++; else i_assert(rec->uid >= hdr->first_unseen_uid_lowwater); } i_assert(del == hdr->deleted_messages_count); - i_assert(recent == hdr->recent_messages_count); i_assert(seen == hdr->seen_messages_count); } #endif
--- a/src/lib-index/mail-index-sync.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-index/mail-index-sync.c Mon Jul 16 09:48:02 2007 +0300 @@ -15,6 +15,7 @@ struct mail_index *index; struct mail_index_view *view; struct mail_index_transaction *sync_trans, *ext_trans; + enum mail_index_sync_flags flags; const struct mail_transaction_header *hdr; const void *data; @@ -170,27 +171,6 @@ return 0; } -static int mail_index_sync_add_recent_updates(struct mail_index_sync_ctx *ctx) -{ - const struct mail_index_record *rec; - uint32_t seq, messages_count; - bool seen_recent = FALSE; - - messages_count = mail_index_view_get_messages_count(ctx->view); - for (seq = 1; seq <= messages_count; seq++) { - if (mail_index_lookup(ctx->view, seq, &rec) < 0) - return -1; - - if ((rec->flags & MAIL_RECENT) != 0) { - seen_recent = TRUE; - mail_index_update_flags(ctx->sync_trans, rec->uid, - MODIFY_REMOVE, MAIL_RECENT); - } - } - - return 0; -} - static void mail_index_sync_update_mailbox_pos(struct mail_index_sync_ctx *ctx) { @@ -205,8 +185,7 @@ } static int -mail_index_sync_read_and_sort(struct mail_index_sync_ctx *ctx, - enum mail_index_sync_flags flags) +mail_index_sync_read_and_sort(struct mail_index_sync_ctx *ctx) { struct mail_index_transaction *sync_trans = ctx->sync_trans; struct mail_index_sync_list *synclist; @@ -215,17 +194,12 @@ int ret; if ((ctx->view->map->hdr.flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) && - (flags & MAIL_INDEX_SYNC_FLAG_FLUSH_DIRTY) != 0) { + (ctx->flags & MAIL_INDEX_SYNC_FLAG_FLUSH_DIRTY) != 0) { /* show dirty flags as flag updates */ if (mail_index_sync_add_dirty_updates(ctx) < 0) return -1; } - if ((flags & MAIL_INDEX_SYNC_FLAG_DROP_RECENT) != 0) { - if (mail_index_sync_add_recent_updates(ctx) < 0) - return -1; - } - /* read all transactions from log into a transaction in memory. skip the external ones, they're already synced to mailbox and included in our view */ @@ -287,7 +261,7 @@ enum mail_index_sync_flags flags, uint32_t log_file_seq, uoff_t log_file_offset) { - if (hdr->recent_messages_count > 0 && + if (hdr->first_recent_uid < hdr->next_uid && (flags & MAIL_INDEX_SYNC_FLAG_DROP_RECENT) != 0) return TRUE; @@ -385,6 +359,7 @@ ctx->index = index; ctx->last_tail_seq = hdr->log_file_seq; ctx->last_tail_offset = hdr->log_file_tail_offset; + ctx->flags = flags; ctx->view = mail_index_view_open(index); @@ -410,7 +385,7 @@ /* we need to have all the transactions sorted to optimize caller's mailbox access patterns */ - if (mail_index_sync_read_and_sort(ctx, flags) < 0) { + if (mail_index_sync_read_and_sort(ctx) < 0) { mail_index_sync_rollback(&ctx); return -1; } @@ -599,7 +574,7 @@ { struct mail_index_sync_ctx *ctx = *_ctx; struct mail_index *index = ctx->index; - uint32_t seq, diff; + uint32_t seq, diff, next_uid; uoff_t offset; bool want_rotate; int ret = 0; @@ -612,6 +587,14 @@ (void)mail_cache_compress(index->cache, ctx->ext_trans); } + next_uid = mail_index_transaction_get_next_uid(ctx->ext_trans); + if ((ctx->flags & MAIL_INDEX_SYNC_FLAG_DROP_RECENT) != 0 && + index->map->hdr.first_recent_uid < next_uid) { + mail_index_update_header(ctx->ext_trans, + offsetof(struct mail_index_header, first_recent_uid), + &next_uid, sizeof(next_uid), FALSE); + } + if (mail_index_transaction_commit(&ctx->ext_trans, &seq, &offset) < 0) { mail_index_sync_end(&ctx); return -1;
--- a/src/lib-index/mail-index-transaction-private.h Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-index/mail-index-transaction-private.h Mon Jul 16 09:48:02 2007 +0300 @@ -89,6 +89,7 @@ void mail_index_transaction_unref(struct mail_index_transaction **t); void mail_index_transaction_sort_appends(struct mail_index_transaction *t); +uint32_t mail_index_transaction_get_next_uid(struct mail_index_transaction *t); bool mail_index_seq_array_lookup(const ARRAY_TYPE(seq_array) *array, uint32_t seq, unsigned int *idx_r);
--- a/src/lib-index/mail-index-transaction-view.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-index/mail-index-transaction-view.c Mon Jul 16 09:48:02 2007 +0300 @@ -42,23 +42,16 @@ struct mail_index_view_transaction *tview = (struct mail_index_view_transaction *)view; const struct mail_index_header *hdr; - const struct mail_index_record *recs; - unsigned int count; + uint32_t next_uid; /* FIXME: header counters may not be correct */ hdr = tview->super->get_header(view); - if (array_is_created(&tview->t->appends)) { - /* update next_uid from appends, if UIDs have been given yet */ - mail_index_transaction_sort_appends(tview->t); - - recs = array_get(&tview->t->appends, &count); - if (count > 0 && recs[count-1].uid != 0) { - i_assert(recs[count-1].uid >= hdr->next_uid); - tview->hdr = *hdr; - tview->hdr.next_uid = recs[count-1].uid + 1; - hdr = &tview->hdr; - } + next_uid = mail_index_transaction_get_next_uid(tview->t); + if (next_uid != hdr->next_uid) { + tview->hdr = *hdr; + tview->hdr.next_uid = next_uid; + hdr = &tview->hdr; } return hdr; }
--- a/src/lib-index/mail-index-transaction.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-index/mail-index-transaction.c Mon Jul 16 09:48:02 2007 +0300 @@ -424,6 +424,40 @@ t->appends_nonsorted = FALSE; } +uint32_t mail_index_transaction_get_next_uid(struct mail_index_transaction *t) +{ + const struct mail_index_header *hdr; + const struct mail_index_record *recs; + unsigned int count, offset; + uint32_t next_uid; + + next_uid = t->view->map->hdr.next_uid; + if (array_is_created(&t->appends)) { + /* get next_uid from appends if they have UIDs */ + mail_index_transaction_sort_appends(t); + + recs = array_get(&t->appends, &count); + if (count > 0 && recs[count-1].uid != 0) { + i_assert(recs[count-1].uid >= next_uid); + next_uid = recs[count-1].uid + 1; + } + } + + /* see if it's been updated in pre/post header changes */ + offset = offsetof(struct mail_index_header, next_uid); + if (t->post_hdr_mask[offset] != 0) { + hdr = (const void *)t->post_hdr_change; + if (hdr->next_uid > next_uid) + next_uid = hdr->next_uid; + } + if (t->pre_hdr_mask[offset] != 0) { + hdr = (const void *)t->pre_hdr_change; + if (hdr->next_uid > next_uid) + next_uid = hdr->next_uid; + } + return next_uid; +} + static int _mail_index_transaction_commit(struct mail_index_transaction *t, uint32_t *log_file_seq_r, uoff_t *log_file_offset_r)
--- a/src/lib-index/mail-index-view-sync.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-index/mail-index-view-sync.c Mon Jul 16 09:48:02 2007 +0300 @@ -466,7 +466,7 @@ #define FLAG_UPDATE_IS_INTERNAL(u) \ ((((u)->add_flags | (u)->remove_flags) & \ - ~(MAIL_INDEX_MAIL_FLAG_DIRTY | MAIL_RECENT)) == 0) + ~MAIL_INDEX_MAIL_FLAG_DIRTY) == 0) static bool mail_index_view_sync_get_rec(struct mail_index_view_sync_ctx *ctx,
--- a/src/lib-index/mail-index-view.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-index/mail-index-view.c Mon Jul 16 09:48:02 2007 +0300 @@ -339,8 +339,6 @@ *seq_r = 0; - if ((flags_mask & MAIL_RECENT) != 0 && (flags & MAIL_RECENT) != 0) - LOW_UPDATE(view->map->hdr.first_recent_uid_lowwater); if ((flags_mask & MAIL_SEEN) != 0 && (flags & MAIL_SEEN) == 0) LOW_UPDATE(view->map->hdr.first_unseen_uid_lowwater); if ((flags_mask & MAIL_DELETED) != 0 && (flags & MAIL_DELETED) != 0)
--- a/src/lib-index/mail-index.h Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-index/mail-index.h Mon Jul 16 09:48:02 2007 +0300 @@ -64,12 +64,12 @@ uint32_t next_uid; uint32_t messages_count; - uint32_t recent_messages_count; + uint32_t unused_old_recent_messages_count; uint32_t seen_messages_count; uint32_t deleted_messages_count; - /* these UIDs may not exist and may not even be unseen */ - uint32_t first_recent_uid_lowwater; + uint32_t first_recent_uid; + /* these UIDs may not exist and may not even be unseen/deleted */ uint32_t first_unseen_uid_lowwater; uint32_t first_deleted_uid_lowwater;
--- a/src/lib-mail/mail-types.h Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-mail/mail-types.h Mon Jul 16 09:48:02 2007 +0300 @@ -9,7 +9,8 @@ MAIL_DRAFT = 0x10, MAIL_RECENT = 0x20, - MAIL_FLAGS_MASK = 0x3f + MAIL_FLAGS_MASK = 0x3f, + MAIL_FLAGS_NONRECENT = (MAIL_FLAGS_MASK ^ MAIL_RECENT) }; enum modify_type {
--- a/src/lib-storage/index/cydir/cydir-save.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-storage/index/cydir/cydir-save.c Mon Jul 16 09:48:02 2007 +0300 @@ -112,7 +112,7 @@ t_pop(); /* add to index */ - save_flags = (flags & ~MAIL_RECENT) | MAIL_RECENT; + save_flags = flags & ~MAIL_RECENT; mail_index_append(ctx->trans, 0, &ctx->seq); mail_index_update_flags(ctx->trans, ctx->seq, MODIFY_REPLACE, save_flags);
--- a/src/lib-storage/index/cydir/cydir-sync.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-storage/index/cydir/cydir-sync.c Mon Jul 16 09:48:02 2007 +0300 @@ -77,6 +77,17 @@ return -1; } + /* mark the newly seen messages as recent */ + if (mail_index_lookup_uid_range(ctx->sync_view, hdr->first_recent_uid, + hdr->next_uid, &seq1, &seq2) < 0) { + mail_storage_set_index_error(&ctx->mbox->ibox); + return -1; + } + if (seq1 != 0) { + index_mailbox_set_recent_seq(&ctx->mbox->ibox, ctx->sync_view, + seq1, seq2); + } + while (ret > 0 && (ret = mail_index_sync_next(ctx->index_sync_ctx, &sync_rec)) > 0) {
--- a/src/lib-storage/index/dbox/dbox-save.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-storage/index/dbox/dbox-save.c Mon Jul 16 09:48:02 2007 +0300 @@ -219,7 +219,7 @@ ctx->mail_offset = ctx->file->output->offset; /* add to index */ - save_flags = (flags & ~MAIL_RECENT) | MAIL_RECENT; + save_flags = flags & ~MAIL_RECENT; mail_index_append(ctx->trans, 0, &ctx->seq); mail_index_update_flags(ctx->trans, ctx->seq, MODIFY_REPLACE, save_flags);
--- a/src/lib-storage/index/dbox/dbox-sync.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-storage/index/dbox/dbox-sync.c Mon Jul 16 09:48:02 2007 +0300 @@ -74,23 +74,6 @@ return 0; } -static int dbox_update_recent_flags(struct dbox_sync_context *ctx, - uint32_t seq1, uint32_t seq2) -{ - uint32_t seq; - const struct mail_index_record *rec; - - for (seq = seq1; seq <= seq2; seq++) { - if (mail_index_lookup(ctx->sync_view, seq, &rec) < 0) { - mail_storage_set_index_error(&ctx->mbox->ibox); - return -1; - } - if ((rec->flags & MAIL_RECENT) != 0) - index_mailbox_set_recent(&ctx->mbox->ibox, seq); - } - return 0; -} - static int dbox_sync_add(struct dbox_sync_context *ctx, const struct mail_index_sync_rec *sync_rec) { @@ -124,10 +107,6 @@ case MAIL_INDEX_SYNC_TYPE_FLAGS: dbox_sync_rec.value.flags.add = sync_rec->add_flags; dbox_sync_rec.value.flags.remove = sync_rec->remove_flags; - if ((sync_rec->remove_flags & MAIL_RECENT) != 0) { - if (dbox_update_recent_flags(ctx, seq1, seq2) < 0) - return -1; - } break; case MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD: case MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE:
--- a/src/lib-storage/index/index-mail.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-storage/index/index-mail.c Mon Jul 16 09:48:02 2007 +0300 @@ -115,7 +115,7 @@ struct index_mail *mail = (struct index_mail *) _mail; struct index_mail_data *data = &mail->data; - data->flags = data->rec->flags & MAIL_FLAGS_MASK; + data->flags = data->rec->flags & MAIL_FLAGS_NONRECENT; if (index_mailbox_is_recent(mail->ibox, data->seq)) data->flags |= MAIL_RECENT; @@ -1110,7 +1110,7 @@ struct index_mail *imail = (struct index_mail *)mail; mail_index_update_flags(imail->trans->trans, mail->seq, modify_type, - flags & MAIL_FLAGS_MASK); + flags & MAIL_FLAGS_NONRECENT); return 0; }
--- a/src/lib-storage/index/index-status.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-storage/index/index-status.c Mon Jul 16 09:48:02 2007 +0300 @@ -14,7 +14,7 @@ /* we can get most of the status items without any trouble */ hdr = mail_index_get_header(ibox->view); status_r->messages = hdr->messages_count; - status_r->recent = ibox->synced_recent_count; + status_r->recent = ibox->recent_flags_count; status_r->unseen = hdr->messages_count - hdr->seen_messages_count; status_r->uidvalidity = hdr->uid_validity;
--- a/src/lib-storage/index/index-storage.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-storage/index/index-storage.c Mon Jul 16 09:48:02 2007 +0300 @@ -432,8 +432,8 @@ index_mailbox_check_remove_all(ibox); if (ibox->index != NULL) index_storage_unref(ibox->index); - if (ibox->recent_flags != NULL) - buffer_free(ibox->recent_flags); + if (array_is_created(&ibox->recent_flags)) + array_free(&ibox->recent_flags); i_free(ibox->cache_fields); pool_unref(box->pool);
--- a/src/lib-storage/index/index-storage.h Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-storage/index/index-storage.h Mon Jul 16 09:48:02 2007 +0300 @@ -33,8 +33,6 @@ struct mail_cache *cache; struct mail_vfuncs *mail_vfuncs; - bool (*is_recent)(struct index_mailbox *ibox, uint32_t uid); - uint32_t md5hdr_ext_idx; struct timeout *notify_to; @@ -52,16 +50,15 @@ struct mail_cache_field *cache_fields; unsigned int mail_cache_min_mail_count; - buffer_t *recent_flags; - uint32_t recent_flags_start_seq, recent_flags_count; + ARRAY_TYPE(seq_range) recent_flags; + uint32_t recent_flags_prev_uid; + uint32_t recent_flags_count; - uint32_t synced_recent_count; time_t sync_last_check; unsigned int readonly:1; unsigned int keep_recent:1; unsigned int keep_locked:1; - unsigned int recent_flags_synced:1; unsigned int sent_diskspace_warning:1; unsigned int sent_readonly_flags_warning:1; unsigned int notify_pending:1; @@ -117,10 +114,11 @@ void index_keywords_free(struct mailbox_transaction_context *t, struct mail_keywords *keywords); -void index_mailbox_set_recent(struct index_mailbox *ibox, uint32_t seq); -bool index_mailbox_is_recent(struct index_mailbox *ibox, uint32_t seq); - -unsigned int index_storage_get_recent_count(struct mail_index_view *view); +void index_mailbox_set_recent_uid(struct index_mailbox *ibox, uint32_t uid); +void index_mailbox_set_recent_seq(struct index_mailbox *ibox, + struct mail_index_view *view, + uint32_t seq1, uint32_t seq2); +bool index_mailbox_is_recent(struct index_mailbox *ibox, uint32_t uid); void index_mailbox_check_add(struct index_mailbox *ibox, const char *path);
--- a/src/lib-storage/index/index-sync.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-storage/index/index-sync.c Mon Jul 16 09:48:02 2007 +0300 @@ -19,114 +19,54 @@ bool failed; }; -void index_mailbox_set_recent(struct index_mailbox *ibox, uint32_t seq) +void index_mailbox_set_recent_uid(struct index_mailbox *ibox, uint32_t uid) { - unsigned char *p; - size_t dest_idx; + if (uid <= ibox->recent_flags_prev_uid) { + i_assert(seq_range_exists(&ibox->recent_flags, uid)); + return; + } + ibox->recent_flags_prev_uid = uid; - i_assert(seq != 0); + seq_range_array_add(&ibox->recent_flags, 64, uid); + ibox->recent_flags_count++; +} - if (ibox->recent_flags_start_seq == 0) { - ibox->recent_flags = buffer_create_dynamic(default_pool, 128); - ibox->recent_flags_start_seq = seq; - } else if (seq < ibox->recent_flags_start_seq) { - dest_idx = ibox->recent_flags_start_seq - seq; - buffer_copy(ibox->recent_flags, dest_idx, - ibox->recent_flags, 0, (size_t)-1); - memset(buffer_get_modifiable_data(ibox->recent_flags, NULL), - 0, dest_idx); - ibox->recent_flags_start_seq = seq; - } +void index_mailbox_set_recent_seq(struct index_mailbox *ibox, + struct mail_index_view *view, + uint32_t seq1, uint32_t seq2) +{ + uint32_t uid; + int ret; - p = buffer_get_space_unsafe(ibox->recent_flags, - seq - ibox->recent_flags_start_seq, 1); - if (*p == 0) { - ibox->recent_flags_count++; - *p = 1; + for (; seq1 <= seq2; seq1++) { + ret = mail_index_lookup_uid(view, seq1, &uid); + i_assert(ret == 0); + index_mailbox_set_recent_uid(ibox, uid); } } -bool index_mailbox_is_recent(struct index_mailbox *ibox, uint32_t seq) +bool index_mailbox_is_recent(struct index_mailbox *ibox, uint32_t uid) { - const unsigned char *data; - size_t size; - uint32_t idx; - - if (seq < ibox->recent_flags_start_seq || - ibox->recent_flags_start_seq == 0) - return FALSE; - - idx = seq - ibox->recent_flags_start_seq; - data = buffer_get_data(ibox->recent_flags, &size); - return idx < size ? data[idx] : FALSE; + return array_is_created(&ibox->recent_flags) && + seq_range_exists(&ibox->recent_flags, uid); } static void index_mailbox_expunge_recent(struct index_mailbox *ibox, uint32_t seq1, uint32_t seq2) { - const unsigned char *data; - size_t size; - uint32_t i, idx, count, move; - - if (ibox->recent_flags_start_seq == 0) { - /* no recent flags */ - return; - } - - if (seq2 < ibox->recent_flags_start_seq) { - /* expunging messages before recent flags, just modify - the recent start position */ - ibox->recent_flags_start_seq -= seq2 - seq1 + 1; - return; - } - - if (seq1 < ibox->recent_flags_start_seq) { - move = ibox->recent_flags_start_seq - seq1; - seq1 = ibox->recent_flags_start_seq; - } else { - move = 0; - } + uint32_t uid; + int ret; - idx = seq1 - ibox->recent_flags_start_seq; - count = seq2 - seq1 + 1; - - data = buffer_get_data(ibox->recent_flags, &size); - if (idx < size) { - if (idx + count > size) - count = size - idx; - - for (i = 0; i < count; i++) { - if (data[idx+i]) - ibox->recent_flags_count--; - } - - buffer_copy(ibox->recent_flags, idx, - ibox->recent_flags, idx + count, (size_t)-1); - buffer_write_zero(ibox->recent_flags, size - count, count); - - buffer_set_used_size(ibox->recent_flags, size - count); - } - ibox->recent_flags_start_seq -= move; -} - -static int index_mailbox_update_recent(struct index_mailbox *ibox, - uint32_t seq1, uint32_t seq2) -{ - const struct mail_index_record *rec; + if (!array_is_created(&ibox->recent_flags)) + return; for (; seq1 <= seq2; seq1++) { - if (mail_index_lookup(ibox->view, seq1, &rec) < 0) { - mail_storage_set_index_error(ibox); - return -1; - } + ret = mail_index_lookup_uid(ibox->view, seq1, &uid); + i_assert(ret == 0); - if ((rec->flags & MAIL_RECENT) != 0 || - (ibox->is_recent != NULL && - ibox->is_recent(ibox, rec->uid))) - index_mailbox_set_recent(ibox, seq1); + if (seq_range_array_remove(&ibox->recent_flags, uid)) + ibox->recent_flags_count--; } - - return 0; } struct mailbox_sync_context * @@ -158,11 +98,6 @@ return &ctx->ctx; } - if (!ibox->recent_flags_synced) { - ibox->recent_flags_synced = TRUE; - index_mailbox_update_recent(ibox, 1, ctx->messages_count); - } - if ((flags & MAILBOX_SYNC_FLAG_NO_EXPUNGES) == 0) { mail_index_view_sync_get_expunges(ctx->sync_ctx, &ctx->expunges); @@ -299,21 +234,32 @@ struct index_mailbox_sync_context *ctx = (struct index_mailbox_sync_context *)_ctx; struct index_mailbox *ibox = ctx->ibox; - uint32_t messages_count; + const struct mail_index_header *hdr; + uint32_t seq1, seq2; int ret = ctx->failed ? -1 : 0; if (ctx->sync_ctx != NULL) mail_index_view_sync_end(&ctx->sync_ctx); + if (ibox->keep_recent) { + /* mailbox syncing didn't necessarily update our recent state */ + hdr = mail_index_get_header(ibox->view); + if (hdr->first_recent_uid > ibox->recent_flags_prev_uid) { + if (mail_index_lookup_uid_range(ibox->view, + hdr->first_recent_uid, + hdr->next_uid, + &seq1, &seq2) < 0) { + mail_storage_set_index_error(ctx->ibox); + return -1; + } + if (seq1 != 0) { + index_mailbox_set_recent_seq(ibox, ibox->view, + seq1, seq2); + } + } + } + if (ret == 0) { - messages_count = mail_index_view_get_messages_count(ibox->view); - if (messages_count != ctx->messages_count) { - index_mailbox_update_recent(ibox, - ctx->messages_count+1, - messages_count); - } - ibox->synced_recent_count = ibox->recent_flags_count; - ret = status_items == 0 ? 0 : index_storage_get_status_locked(ctx->ibox, status_items, status_r);
--- a/src/lib-storage/index/maildir/maildir-save.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-storage/index/maildir/maildir-save.c Mon Jul 16 09:48:02 2007 +0300 @@ -608,9 +608,6 @@ *t->ictx.last_saved_uid = first_uid + ctx->files_count - 1; } - flags = MAILDIR_UIDLIST_REC_FLAG_NEW_DIR | - MAILDIR_UIDLIST_REC_FLAG_RECENT; - /* move them into new/ and/or cur/ */ ret = 0; ctx->moving = TRUE; @@ -636,6 +633,9 @@ t_push(); newdir = maildir_get_updated_filename(ctx, mf, &dest); + flags = MAILDIR_UIDLIST_REC_FLAG_RECENT; + if (newdir) + flags |= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR; ret = maildir_uidlist_sync_next(ctx->uidlist_sync_ctx, dest, flags); i_assert(ret > 0);
--- a/src/lib-storage/index/maildir/maildir-storage.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-storage/index/maildir/maildir-storage.c Mon Jul 16 09:48:02 2007 +0300 @@ -415,13 +415,6 @@ return 0; } -static bool maildir_is_recent(struct index_mailbox *ibox, uint32_t uid) -{ - struct maildir_mailbox *mbox = (struct maildir_mailbox *)ibox; - - return maildir_uidlist_is_recent(mbox->uidlist, uid); -} - static void maildir_lock_touch_timeout(struct maildir_mailbox *mbox) { (void)maildir_uidlist_lock_touch(mbox->uidlist); @@ -458,7 +451,6 @@ mbox->ibox.box.pool = pool; mbox->ibox.storage = &storage->storage; mbox->ibox.mail_vfuncs = &maildir_mail_vfuncs; - mbox->ibox.is_recent = maildir_is_recent; mbox->ibox.index = index; mbox->storage = storage;
--- a/src/lib-storage/index/maildir/maildir-sync-index.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-storage/index/maildir/maildir-sync-index.c Mon Jul 16 09:48:02 2007 +0300 @@ -27,7 +27,7 @@ enum mail_flags flags; ARRAY_TYPE(keyword_indexes) keywords; - uint32_t seq, uid; + uint32_t seq, uid, last_nonrecent_seq, last_nonrecent_uid; bool changed; }; @@ -133,8 +133,7 @@ i_assert(ret > 0); } - uflags &= (MAILDIR_UIDLIST_REC_FLAG_NEW_DIR | - MAILDIR_UIDLIST_REC_FLAG_RECENT); + uflags &= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR; maildir_uidlist_sync_remove(ctx->uidlist_sync_ctx, filename); ret = maildir_uidlist_sync_next(ctx->uidlist_sync_ctx, filename, uflags); @@ -155,9 +154,15 @@ struct mail_index_sync_ctx *sync_ctx; struct mail_index_view *view; struct mail_index_transaction *trans; + enum mail_index_sync_flags sync_flags; + + sync_flags = 0; + /* don't drop recent messages if we're saving messages */ + if (!mbox->ibox.keep_recent && maildir_sync_ctx != NULL) + sync_flags |= MAIL_INDEX_SYNC_FLAG_DROP_RECENT; if (mail_index_sync_begin(mbox->ibox.index, &sync_ctx, &view, &trans, - (uint32_t)-1, (uoff_t)-1, 0) <= 0) { + (uint32_t)-1, (uoff_t)-1, sync_flags) <= 0) { mail_storage_set_index_error(&mbox->ibox); return -1; } @@ -179,6 +184,46 @@ return 0; } +static int maildir_sync_recent_state(struct maildir_index_sync_context *ctx) +{ + const struct mail_index_header *hdr; + uint32_t seq1, seq2, first_recent_uid; + + /* see what index thinks is the lowest recent sequence */ + hdr = mail_index_get_header(ctx->view); + if (mail_index_lookup_uid_range(ctx->view, hdr->first_recent_uid, + hdr->next_uid, &seq1, &seq2) < 0) { + mail_storage_set_index_error(&ctx->mbox->ibox); + return -1; + } + + if (seq1 == 0 && hdr->first_recent_uid >= ctx->last_nonrecent_uid + 1) { + /* nothing new */ + return 0; + } + + if (ctx->last_nonrecent_seq >= seq1) { + /* we've seen newer non-recent messages. */ + seq1 = ctx->last_nonrecent_seq + 1; + } + + if (seq2 < ctx->seq) + seq2 = ctx->seq - 1; + + if (seq1 <= seq2) { + index_mailbox_set_recent_seq(&ctx->mbox->ibox, ctx->view, + seq1, seq2); + } + + if (ctx->mbox->ibox.keep_recent && + hdr->first_recent_uid < ctx->last_nonrecent_uid + 1) { + first_recent_uid = ctx->last_nonrecent_uid + 1; + mail_index_update_header(ctx->trans, + offsetof(struct mail_index_header, first_recent_uid), + &first_recent_uid, sizeof(first_recent_uid), FALSE); + } + return 0; +} int maildir_sync_index_finish(struct maildir_index_sync_context **_ctx, bool failed, bool cancel) { @@ -191,6 +236,8 @@ if (ret < 0 || cancel) mail_index_sync_rollback(&ctx->sync_ctx); else { + maildir_sync_recent_state(ctx); + /* Set syncing_commit=TRUE so that if any sync callbacks try to access mails which got lost (eg. expunge callback trying to open the file which was just unlinked) we don't try to @@ -291,17 +338,16 @@ at all even for newly seen mails */ ctx->flags &= ~mbox->private_flags_mask; - if ((uflags & MAILDIR_UIDLIST_REC_FLAG_RECENT) != 0 && - (uflags & MAILDIR_UIDLIST_REC_FLAG_NEW_DIR) != 0 && - (uflags & MAILDIR_UIDLIST_REC_FLAG_MOVED) == 0) { - /* mail is recent for next session as well */ - ctx->flags |= MAIL_RECENT; - } - __again: ctx->seq = ++seq; ctx->uid = uid; + if ((uflags & MAILDIR_UIDLIST_REC_FLAG_RECENT) == 0 && + (uflags & MAILDIR_UIDLIST_REC_FLAG_NONSYNCED) == 0) { + ctx->last_nonrecent_seq = seq; + ctx->last_nonrecent_uid = uid; + } + if (seq > hdr->messages_count) { if (uid < hdr_next_uid) { maildir_handle_uid_insertion(ctx, uflags, @@ -356,7 +402,7 @@ if (maildir_file_do(mbox, ctx->uid, maildir_expunge, ctx) >= 0) { /* successful expunge */ - mail_index_expunge(trans, ctx->seq); + mail_index_expunge(trans, seq); } if ((++changes % MAILDIR_SLOW_MOVE_COUNT) == 0) maildir_sync_notify(ctx->maildir_sync_ctx); @@ -366,20 +412,9 @@ /* the private flags are stored only in indexes, keep them */ ctx->flags |= rec->flags & mbox->private_flags_mask; - if ((rec->flags & MAIL_RECENT) != 0) { - index_mailbox_set_recent(&mbox->ibox, seq); - if (mbox->ibox.keep_recent) { - ctx->flags |= MAIL_RECENT; - } else { - mail_index_update_flags(trans, seq, - MODIFY_REMOVE, - MAIL_RECENT); - } - } - if ((uflags & MAILDIR_UIDLIST_REC_FLAG_NONSYNCED) != 0) { /* partial syncing */ - if ((ctx->flags & MAIL_RECENT) != 0) { + if ((uflags & MAILDIR_UIDLIST_REC_FLAG_NEW_DIR) != 0) { /* we last saw this mail in new/, but it's not there anymore. possibly expunged, make sure. */ @@ -403,15 +438,9 @@ continue; } - if ((ctx->flags & ~MAIL_RECENT) != - (rec->flags & (MAIL_FLAGS_MASK^MAIL_RECENT))) { + if (ctx->flags != (rec->flags & MAIL_FLAGS_NONRECENT)) { mail_index_update_flags(trans, seq, MODIFY_REPLACE, ctx->flags); - } else if ((ctx->flags & MAIL_RECENT) == 0 && - (rec->flags & MAIL_RECENT) != 0) { - /* just remove recent flag */ - mail_index_update_flags(trans, seq, MODIFY_REMOVE, - MAIL_RECENT); } /* update keywords if they have changed */
--- a/src/lib-storage/index/maildir/maildir-sync.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-storage/index/maildir/maildir-sync.c Mon Jul 16 09:48:02 2007 +0300 @@ -453,16 +453,15 @@ /* someone else moved it already */ dir_changed = TRUE; move_count++; - flags |= MAILDIR_UIDLIST_REC_FLAG_MOVED; + flags |= MAILDIR_UIDLIST_REC_FLAG_MOVED | + MAILDIR_UIDLIST_REC_FLAG_RECENT; } else if (ENOSPACE(errno) || errno == EACCES) { /* not enough disk space / read-only maildir, leave here */ - flags |= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR | - MAILDIR_UIDLIST_REC_FLAG_RECENT; + flags |= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR; move_new = FALSE; } else { - flags |= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR | - MAILDIR_UIDLIST_REC_FLAG_RECENT; + flags |= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR; mail_storage_set_critical(storage, "rename(%s, %s) failed: %m", str_c(src), str_c(dest)); @@ -645,6 +644,22 @@ } } +static bool move_recent_messages(struct maildir_sync_context *ctx) +{ + const struct mail_index_header *hdr; + + if (ctx->mbox->ibox.keep_recent) + return FALSE; + + (void)maildir_uidlist_refresh(ctx->mbox->uidlist); + + /* if there are files in new/, we'll need to move them. we'll check + this by checking if we have any recent messages */ + hdr = mail_index_get_header(ctx->mbox->ibox.view); + return hdr->first_recent_uid < + maildir_uidlist_get_next_uid(ctx->mbox->uidlist); +} + static int maildir_sync_context(struct maildir_sync_context *ctx, bool forced, bool sync_last_commit) { @@ -659,8 +674,11 @@ &new_changed, &cur_changed) < 0) return -1; - if (!new_changed && !cur_changed) - return 1; + if (!new_changed && !cur_changed) { + if (!move_recent_messages(ctx)) + return 1; + new_changed = TRUE; + } } else { new_changed = cur_changed = TRUE; }
--- a/src/lib-storage/index/maildir/maildir-uidlist.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-storage/index/maildir/maildir-uidlist.c Mon Jul 16 09:48:02 2007 +0300 @@ -84,7 +84,6 @@ unsigned int version; unsigned int uid_validity, next_uid, prev_read_uid, last_seen_uid; unsigned int read_records_count; - uint32_t first_recent_uid; uoff_t last_read_offset; string_t *hdr_extensions; @@ -247,14 +246,6 @@ i_free(uidlist); } -static void -maildir_uidlist_mark_recent(struct maildir_uidlist *uidlist, uint32_t uid) -{ - if (uidlist->first_recent_uid == 0 || - uid < uidlist->first_recent_uid) - uidlist->first_recent_uid = uid; -} - static int maildir_uid_cmp(const void *p1, const void *p2) { const struct maildir_uidlist_rec *const *rec1 = p1, *const *rec2 = p2; @@ -738,50 +729,6 @@ return NULL; } -bool maildir_uidlist_is_recent(struct maildir_uidlist *uidlist, uint32_t uid) -{ - enum maildir_uidlist_rec_flag flags; - - if (uidlist->first_recent_uid == 0 || uid < uidlist->first_recent_uid) - return FALSE; - - if (maildir_uidlist_lookup(uidlist, uid, &flags) == NULL) - return FALSE; - - i_assert(uidlist->first_recent_uid != uid || - (flags & MAILDIR_UIDLIST_REC_FLAG_RECENT) != 0); - return (flags & MAILDIR_UIDLIST_REC_FLAG_RECENT) != 0; -} - -uint32_t maildir_uidlist_get_recent_count(struct maildir_uidlist *uidlist) -{ - struct maildir_uidlist_rec *const *recs; - unsigned int idx, count; - uint32_t recent_count; - - if (!uidlist->initial_sync) { - /* we haven't synced yet, trust index */ - const struct mail_index_header *hdr; - - hdr = mail_index_get_header(uidlist->mbox->ibox.view); - return hdr->recent_messages_count; - } - - /* all recent messages were in new/ dir, so even if we did only - a partial sync we should know all the recent messages. */ - - if (uidlist->first_recent_uid == 0) - return 0; - - recs = array_get(&uidlist->records, &count); - maildir_uidlist_lookup_rec(uidlist, uidlist->first_recent_uid, &idx); - for (recent_count = 0; idx < count; idx++) { - if ((recs[idx]->flags & MAILDIR_UIDLIST_REC_FLAG_RECENT) != 0) - recent_count++; - } - return recent_count; -} - uint32_t maildir_uidlist_get_uid_validity(struct maildir_uidlist *uidlist) { return uidlist->uid_validity; @@ -1110,10 +1057,6 @@ uidlist->change_counter++; } - if ((flags & MAILDIR_UIDLIST_REC_FLAG_RECENT) != 0 && - rec->uid != (uint32_t)-1) - maildir_uidlist_mark_recent(uidlist, rec->uid); - rec->flags = (rec->flags | flags) & ~MAILDIR_UIDLIST_REC_FLAG_NONSYNCED; rec->filename = p_strdup(uidlist->record_pool, filename); hash_insert(uidlist->files, rec->filename, rec); @@ -1165,6 +1108,9 @@ return 0; } + /* probably was in new/ and now we're seeing it in cur/. + remove new/moved flags so if this happens again we'll know + to check for duplicates. */ rec->flags &= ~(MAILDIR_UIDLIST_REC_FLAG_NEW_DIR | MAILDIR_UIDLIST_REC_FLAG_MOVED); } else { @@ -1179,15 +1125,13 @@ rec->uid = (uint32_t)-1; ctx->new_files_count++; ctx->changed = TRUE; + /* didn't exist in uidlist, it's recent */ + flags |= MAILDIR_UIDLIST_REC_FLAG_RECENT; } array_append(&ctx->records, &rec, 1); } - if ((flags & MAILDIR_UIDLIST_REC_FLAG_RECENT) != 0 && - rec->uid != (uint32_t)-1) - maildir_uidlist_mark_recent(uidlist, rec->uid); - rec->flags = (rec->flags | flags) & ~MAILDIR_UIDLIST_REC_FLAG_NONSYNCED; rec->filename = p_strdup(ctx->record_pool, filename); hash_insert(ctx->files, rec->filename, rec); @@ -1268,12 +1212,6 @@ i_assert(recs[dest]->uid == (uint32_t)-1); recs[dest]->uid = ctx->uidlist->next_uid++; recs[dest]->flags &= ~MAILDIR_UIDLIST_REC_FLAG_MOVED; - - if ((recs[dest]->flags & - MAILDIR_UIDLIST_REC_FLAG_RECENT) != 0) { - maildir_uidlist_mark_recent(ctx->uidlist, - recs[dest]->uid); - } } ctx->new_files_count = 0;
--- a/src/lib-storage/index/maildir/maildir-uidlist.h Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-storage/index/maildir/maildir-uidlist.h Mon Jul 16 09:48:02 2007 +0300 @@ -53,10 +53,6 @@ const char * maildir_uidlist_lookup_ext(struct maildir_uidlist *uidlist, uint32_t uid, enum maildir_uidlist_rec_ext_key key); -/* Returns TRUE if mail with given UID is recent. */ -bool maildir_uidlist_is_recent(struct maildir_uidlist *uidlist, uint32_t uid); -/* Returns number of recent messages. */ -uint32_t maildir_uidlist_get_recent_count(struct maildir_uidlist *uidlist); uint32_t maildir_uidlist_get_uid_validity(struct maildir_uidlist *uidlist); uint32_t maildir_uidlist_get_next_uid(struct maildir_uidlist *uidlist);
--- a/src/lib-storage/index/mbox/mbox-sync-private.h Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-storage/index/mbox/mbox-sync-private.h Mon Jul 16 09:48:02 2007 +0300 @@ -131,6 +131,7 @@ uint32_t prev_msg_uid, next_uid, idx_next_uid; uint32_t seq, idx_seq, need_space_seq; + uint32_t last_nonrecent_idx_seq, last_nonrecent_uid; off_t expunged_space, space_diff; unsigned int dest_first_mail:1;
--- a/src/lib-storage/index/mbox/mbox-sync.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib-storage/index/mbox/mbox-sync.c Mon Jul 16 09:48:02 2007 +0300 @@ -357,7 +357,7 @@ struct mailbox *box = &sync_ctx->mbox->ibox.box; uint8_t mbox_flags; - mbox_flags = mail->flags & MAIL_FLAGS_MASK; + mbox_flags = mail->flags & MAIL_FLAGS_NONRECENT; if (mail_ctx->dirty) mbox_flags |= MAIL_INDEX_MAIL_FLAG_DIRTY; @@ -384,7 +384,7 @@ enum mailbox_sync_type sync_type; memset(&idx_mail, 0, sizeof(idx_mail)); - idx_mail.flags = rec->flags; + idx_mail.flags = rec->flags & ~MAIL_RECENT; /* get old keywords */ t_push(); @@ -404,35 +404,23 @@ if (sync_type != 0 && box->v.sync_notify != NULL) box->v.sync_notify(box, rec->uid, sync_type); -#define SYNC_FLAGS (MAIL_RECENT | MAIL_INDEX_MAIL_FLAG_DIRTY) if ((idx_mail.flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) { /* flags are dirty. ignore whatever was in the mbox, - but update recent/dirty flag states if needed. */ - mbox_flags &= SYNC_FLAGS; - mbox_flags |= idx_mail.flags & ~SYNC_FLAGS; + but update dirty flag state if needed. */ + mbox_flags &= ~MAIL_INDEX_MAIL_FLAG_DIRTY; + mbox_flags |= + idx_mail.flags & ~MAIL_INDEX_MAIL_FLAG_DIRTY; if (sync_ctx->delay_writes) mbox_flags |= MAIL_INDEX_MAIL_FLAG_DIRTY; - } else { - /* keep index's internal flags */ - mbox_flags &= MAIL_FLAGS_MASK | SYNC_FLAGS; - mbox_flags |= idx_mail.flags & - ~(MAIL_FLAGS_MASK | SYNC_FLAGS); } - if ((idx_mail.flags & ~SYNC_FLAGS) != - (mbox_flags & ~SYNC_FLAGS)) { + if ((idx_mail.flags & ~MAIL_INDEX_MAIL_FLAG_DIRTY) != + (mbox_flags & ~MAIL_INDEX_MAIL_FLAG_DIRTY)) { /* flags other than recent/dirty have changed */ mail_index_update_flags(sync_ctx->t, sync_ctx->idx_seq, MODIFY_REPLACE, mbox_flags); } else { if (((idx_mail.flags ^ mbox_flags) & - MAIL_RECENT) != 0) { - /* drop recent flag (it can only be dropped) */ - mail_index_update_flags(sync_ctx->t, - sync_ctx->idx_seq, - MODIFY_REMOVE, MAIL_RECENT); - } - if (((idx_mail.flags ^ mbox_flags) & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) { /* dirty flag state changed */ bool dirty = (mbox_flags & @@ -458,11 +446,9 @@ } } - if (mail_ctx->recent && - (rec == NULL || (rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) == 0 || - (rec->flags & MAIL_RECENT) != 0)) { - index_mailbox_set_recent(&sync_ctx->mbox->ibox, - sync_ctx->idx_seq); + if (!mail_ctx->recent) { + sync_ctx->last_nonrecent_idx_seq = sync_ctx->idx_seq; + sync_ctx->last_nonrecent_uid = mail->uid; } /* update from_offsets, but not if we're going to rewrite this message. @@ -926,7 +912,21 @@ if (index_sync_changes_have(sync_ctx->sync_changes)) return 1; + if (sync_ctx->hdr->first_recent_uid <= next_uid && + !sync_ctx->mbox->ibox.keep_recent) { + /* we'll need to rewrite Status: O headers */ + return 1; + } + uid = index_sync_changes_get_next_uid(sync_ctx->sync_changes); + + if (sync_ctx->hdr->first_recent_uid < sync_ctx->hdr->next_uid && + (uid > sync_ctx->hdr->first_recent_uid || uid == 0) && + !sync_ctx->mbox->ibox.keep_recent) { + /* we'll need to rewrite Status: O headers */ + uid = sync_ctx->hdr->first_recent_uid; + } + if (uid != 0) { /* we can skip forward to next record which needs updating. */ if (uid != next_uid) { @@ -1331,6 +1331,7 @@ static int mbox_sync_update_index_header(struct mbox_sync_context *sync_ctx) { const struct stat *st; + uint32_t first_recent_uid; st = i_stream_stat(sync_ctx->file_input, FALSE); if (st == NULL) { @@ -1415,12 +1416,53 @@ &sync_size, sizeof(sync_size), TRUE); } + first_recent_uid = !sync_ctx->mbox->ibox.keep_recent ? 0 : + sync_ctx->last_nonrecent_uid + 1; + if (sync_ctx->hdr->first_recent_uid < first_recent_uid) { + mail_index_update_header(sync_ctx->t, + offsetof(struct mail_index_header, first_recent_uid), + &first_recent_uid, sizeof(first_recent_uid), FALSE); + } + sync_ctx->mbox->mbox_dirty_stamp = st->st_mtime; sync_ctx->mbox->mbox_dirty_size = st->st_size; return 0; } +static int mbox_sync_recent_state(struct mbox_sync_context *sync_ctx) +{ + uint32_t seq1, seq2; + + /* see what index thinks is the lowest recent sequence */ + if (mail_index_lookup_uid_range(sync_ctx->sync_view, + sync_ctx->hdr->first_recent_uid, + sync_ctx->hdr->next_uid, + &seq1, &seq2) < 0) { + mail_storage_set_index_error(&sync_ctx->mbox->ibox); + return -1; + } + + if (seq1 == 0 && sync_ctx->idx_seq <= 1) { + /* nothing new */ + return 0; + } + + if (sync_ctx->last_nonrecent_idx_seq >= seq1) { + /* we've seen newer non-recent messages. */ + seq1 = sync_ctx->last_nonrecent_idx_seq + 1; + } + + if (seq2 < sync_ctx->idx_seq) + seq2 = sync_ctx->idx_seq - 1; + + if (seq1 <= seq2) { + index_mailbox_set_recent_seq(&sync_ctx->mbox->ibox, + sync_ctx->sync_view, seq1, seq2); + } + return 0; +} + static void mbox_sync_restart(struct mbox_sync_context *sync_ctx) { sync_ctx->base_uid_validity = 0; @@ -1511,6 +1553,8 @@ partial = FALSE; } + if (mbox_sync_recent_state(sync_ctx) < 0) + return -1; if (mbox_sync_handle_eof_updates(sync_ctx, &mail_ctx) < 0) return -1; @@ -1664,6 +1708,13 @@ return ret; } + if (!mbox->ibox.keep_recent) { + /* see if we need to drop recent flags */ + sync_ctx.hdr = mail_index_get_header(sync_view); + if (sync_ctx.hdr->first_recent_uid < sync_ctx.hdr->next_uid) + changed = 1; + } + if (!changed && !mail_index_sync_have_more(index_sync_ctx)) { /* nothing to do */ __nothing_to_do:
--- a/src/lib/seq-range-array.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib/seq-range-array.c Mon Jul 16 09:48:02 2007 +0300 @@ -100,22 +100,22 @@ } } -void seq_range_array_remove(ARRAY_TYPE(seq_range) *array, uint32_t seq) +bool seq_range_array_remove(ARRAY_TYPE(seq_range) *array, uint32_t seq) { struct seq_range *data, value; unsigned int idx, left_idx, right_idx, count; if (!array_is_created(array)) - return; + return FALSE; data = array_get_modifiable(array, &count); if (count == 0) - return; + return FALSE; /* quick checks */ if (seq > data[count-1].seq2 || seq < data[0].seq1) { /* outside the range */ - return; + return FALSE; } if (data[count-1].seq2 == seq) { /* shrink last range */ @@ -123,7 +123,7 @@ data[count-1].seq2--; else array_delete(array, count-1, 1); - return; + return TRUE; } if (data[0].seq1 == seq) { /* shrink up first range */ @@ -131,7 +131,7 @@ data[0].seq1++; else array_delete(array, 0, 1); - return; + return TRUE; } /* somewhere in the middle, array is sorted so find it with @@ -166,9 +166,10 @@ array_insert(array, idx + 1, &value, 1); } - break; + return TRUE; } } + return FALSE; } void seq_range_array_remove_range(ARRAY_TYPE(seq_range) *array,
--- a/src/lib/seq-range-array.h Mon Jul 16 07:52:50 2007 +0300 +++ b/src/lib/seq-range-array.h Mon Jul 16 09:48:02 2007 +0300 @@ -9,7 +9,7 @@ void seq_range_array_add(ARRAY_TYPE(seq_range) *array, unsigned int init_count, uint32_t seq); -void seq_range_array_remove(ARRAY_TYPE(seq_range) *array, uint32_t seq); +bool seq_range_array_remove(ARRAY_TYPE(seq_range) *array, uint32_t seq); void seq_range_array_remove_range(ARRAY_TYPE(seq_range) *array, uint32_t seq1, uint32_t seq2); bool seq_range_exists(const ARRAY_TYPE(seq_range) *array, uint32_t seq);
--- a/src/util/idxview.c Mon Jul 16 07:52:50 2007 +0300 +++ b/src/util/idxview.c Mon Jul 16 09:48:02 2007 +0300 @@ -62,10 +62,9 @@ printf("uid validity = %u\n", hdr.uid_validity); printf("next uid = %u\n", hdr.next_uid); printf("messages count = %u\n", hdr.messages_count); - printf("recent messages count = %u\n", hdr.recent_messages_count); printf("seen messages count = %u\n", hdr.seen_messages_count); printf("deleted messages count = %u\n", hdr.deleted_messages_count); - printf("first recent uid lowwater = %u\n", hdr.first_recent_uid_lowwater); + printf("first recent uid = %u\n", hdr.first_recent_uid); printf("first unseen uid lowwater = %u\n", hdr.first_unseen_uid_lowwater); printf("first deleted uid lowwater = %u\n", hdr.first_deleted_uid_lowwater); printf("log file seq = %u\n", hdr.log_file_seq);