mail-index-view.c revision 6d25922a089626f5535d51358e33d3337783a410
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenvoid mail_index_view_clone(struct mail_index_view *dest,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_log_view_open(src->index->log);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenvoid mail_index_view_ref(struct mail_index_view *view)
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainenstatic void _view_close(struct mail_index_view *view)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_transaction_log_view_close(&view->log_view);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic void mail_index_view_check_nextuid(struct mail_index_view *view)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen rec = MAIL_INDEX_MAP_IDX(view->map, view->hdr.messages_count-1);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenint mail_index_view_lock_head(struct mail_index_view *view, bool update_index)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen unsigned int lock_id;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (MAIL_INDEX_MAP_IS_IN_MEMORY(view->index->map))
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (!mail_index_is_locked(view->index, view->lock_id)) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (mail_index_lock_shared(view->index, update_index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (mail_index_map(view->index, FALSE) <= 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* index was rebuilt */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (mail_index_lock_shared(view->index, TRUE, &lock_id) < 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_unlock(view->index, view->lock_id);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenint mail_index_view_lock(struct mail_index_view *view)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* not head mapping, no need to lock */
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen return mail_index_view_lock_head(view, FALSE);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenvoid mail_index_view_unlock(struct mail_index_view *view)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (view->lock_id != 0 && view->transactions == 0) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_unlock(view->index, view->lock_id);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenbool mail_index_view_is_inconsistent(struct mail_index_view *view)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstruct mail_index *mail_index_view_get_index(struct mail_index_view *view)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenvoid mail_index_view_transaction_ref(struct mail_index_view *view)
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainenvoid mail_index_view_transaction_unref(struct mail_index_view *view)
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainenstatic void mail_index_view_ref_map(struct mail_index_view *view,
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen unsigned int i, count;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* if map is already referenced, do nothing */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen for (i = 0; i < count; i++) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* reference the given mapping. the reference is dropped when the view
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen is synchronized or closed. */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenvoid mail_index_view_unref_maps(struct mail_index_view *view)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen unsigned int i, count;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen maps = array_get_modifiable(&view->map_refs, &count);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen for (i = 0; i < count; i++)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic uint32_t _view_get_messages_count(struct mail_index_view *view)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic const struct mail_index_header *
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic int _view_lookup_full(struct mail_index_view *view, uint32_t seq,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen const struct mail_index_record *rec, *head_rec;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_assert(seq > 0 && seq <= mail_index_view_get_messages_count(view));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* look up the record */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_set_error(view->index, "Corrupted Index file %s: "
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen "Record [%u].uid=0", view->index->filepath, seq);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* view's mapping is latest. we can use it directly. */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* look up the record from head mapping. it may contain some changes. */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (mail_index_view_lock_head(view, FALSE) < 0)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* start looking up from the same sequence as in the old view.
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if there are no expunges, it's there. otherwise it's somewhere
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen before (since records can't be inserted).
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen usually there are only a few expunges, so just going downwards from
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen our initial sequence position is probably faster than binary
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* everything is expunged from head. use the old record. */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen } while (seq > 0);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* found it. use it. reference the index mapping so that the
cc833a7a4e2258afdc834ace4bfe6579820a1df3Timo Sirainen returned record doesn't get invalidated after next sync. */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen mail_index_view_ref_map(view, view->index->map);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* expuned from head. use the old record. */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic int _view_lookup_uid(struct mail_index_view *view, uint32_t seq,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_assert(seq > 0 && seq <= mail_index_view_get_messages_count(view));
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen *uid_r = MAIL_INDEX_MAP_IDX(view->map, seq-1)->uid;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic uint32_t mail_index_bsearch_uid(struct mail_index_view *view,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen const struct mail_index_record *rec_base, *rec;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen i_assert(view->hdr.messages_count <= view->map->records_count);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* optimization: the message can be only the first one */
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen rec = CONST_PTR_OFFSET(rec_base, idx * record_size);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* left_idx was initially messages_count */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen rec = CONST_PTR_OFFSET(rec_base, idx * record_size);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* we want uid or larger */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen idx == view->hdr.messages_count-1 ? 0 : idx+2;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* we want uid or smaller */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic int _view_lookup_uid_range(struct mail_index_view *view,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen *first_seq_r = mail_index_bsearch_uid(view, first_uid, 0, 1);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen MAIL_INDEX_MAP_IDX(view->map, *first_seq_r-1)->uid > last_uid) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* we want the last message */
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen /* optimization - binary lookup only from right side: */
2e99f3f3bb35715ce5e0a75a2f2a9bac3ab4224bTimo Sirainen *last_seq_r = mail_index_bsearch_uid(view, last_uid,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic int _view_lookup_first(struct mail_index_view *view,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen STMT_START { if ((x) > low_uid) low_uid = x; } STMT_END
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if ((flags_mask & MAIL_RECENT) != 0 && (flags & MAIL_RECENT) != 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen LOW_UPDATE(view->map->hdr.first_recent_uid_lowwater);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if ((flags_mask & MAIL_SEEN) != 0 && (flags & MAIL_SEEN) == 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen LOW_UPDATE(view->map->hdr.first_unseen_uid_lowwater);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if ((flags_mask & MAIL_DELETED) != 0 && (flags & MAIL_DELETED) != 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen LOW_UPDATE(view->map->hdr.first_deleted_uid_lowwater);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (mail_index_lookup_uid_range(view, low_uid, low_uid,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_assert(view->hdr.messages_count <= view->map->records_count);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen for (; seq <= view->hdr.messages_count; seq++) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if ((rec->flags & flags_mask) == (uint8_t)flags) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenstatic int _view_lookup_ext_full(struct mail_index_view *view, uint32_t seq,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen uint32_t ext_id, struct mail_index_map **map_r,
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen const void **data_r)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if ((ret = mail_index_lookup_full(view, seq, map_r, &rec)) < 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (rec == NULL || !mail_index_map_get_ext_idx(*map_r, ext_id, &idx)) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen *data_r = offset == 0 ? NULL : CONST_PTR_OFFSET(rec, offset);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic int _view_get_header_ext(struct mail_index_view *view,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* if we have a mapping, the view where it's from is already locked */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* no mapping given, use head mapping */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (mail_index_view_lock_head(view, FALSE) < 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (!mail_index_map_get_ext_idx(map, ext_id, &idx)) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* extension doesn't exist in this index file */
8cd0a1a2200e65cd134d03fe3f93ec02f1746359Timo Sirainen *data_r = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenvoid mail_index_view_close(struct mail_index_view **_view)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainenuint32_t mail_index_view_get_messages_count(struct mail_index_view *view)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenmail_index_get_header(struct mail_index_view *view)
51b979b6414b940f04677a7e2d064be119345954Timo Sirainenint mail_index_lookup(struct mail_index_view *view, uint32_t seq,
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen return mail_index_lookup_full(view, seq, &map, rec_r);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenint mail_index_lookup_full(struct mail_index_view *view, uint32_t seq,
629600d9a85e8025c15a5eaeb80329e116e022c9Timo Sirainen return view->v.lookup_full(view, seq, map_r, rec_r);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenint mail_index_lookup_keywords(struct mail_index_view *view, uint32_t seq,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen const unsigned char *keyword_data;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen const unsigned int *keyword_idx_map;
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* get the keywords data. */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen ret = mail_index_lookup_ext_full(view, seq, ext_id, &map, &data);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* no keywords at all in index */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen (void)mail_index_ext_get_size(view, ext_id, map, NULL,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* keyword_idx_map[] contains file => index keyword mapping */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (!array_is_created(&map->keyword_idx_map)) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen keyword_idx_map = array_get(&map->keyword_idx_map,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* first do the quick check to see if there's keywords at all */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* keyword header was updated, parse it again
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen it so we know what this keyword is called */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (mail_index_map_parse_keywords(view->index,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* pointer may have changed. update it. */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* extra bits set in keyword bytes.
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen shouldn't happen, but just ignore. */
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenint mail_index_lookup_uid(struct mail_index_view *view, uint32_t seq,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenint mail_index_lookup_uid_range(struct mail_index_view *view,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return view->v.lookup_uid_range(view, first_uid, last_uid,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenint mail_index_lookup_first(struct mail_index_view *view, enum mail_flags flags,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return view->v.lookup_first(view, flags, flags_mask, seq_r);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenint mail_index_lookup_ext(struct mail_index_view *view, uint32_t seq,
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen return view->v.lookup_ext_full(view, seq, ext_id, &map, data_r);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenint mail_index_lookup_ext_full(struct mail_index_view *view, uint32_t seq,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen uint32_t ext_id, struct mail_index_map **map_r,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen const void **data_r)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return view->v.lookup_ext_full(view, seq, ext_id, map_r, data_r);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenint mail_index_get_header_ext(struct mail_index_view *view, uint32_t ext_id,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return view->v.get_header_ext(view, NULL, ext_id, data_r, data_size_r);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenint mail_index_map_get_header_ext(struct mail_index_view *view,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return view->v.get_header_ext(view, map, ext_id, data_r, data_size_r);
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainenint mail_index_ext_get_size(struct mail_index_view *view __attr_unused__,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen uint32_t *hdr_size_r, uint16_t *record_size_r,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (!mail_index_map_get_ext_idx(map, ext_id, &idx)) {
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen /* extension doesn't exist in this index file */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic struct mail_index_view_vfuncs view_vfuncs = {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstruct mail_index_view *mail_index_view_open(struct mail_index *index)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen view->log_view = mail_transaction_log_view_open(index->log);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen view->log_file_seq = view->map->hdr.log_file_seq;
51795bfe9d05d92fe942cb451aec2b9d16d32a11Timo Sirainenmail_index_view_get_ext(struct mail_index_view *view, uint32_t ext_id)
4bc96ba6f1d67a90a75fa131bcd2cd508ea5a05aTimo Sirainen if (!mail_index_map_get_ext_idx(view->map, ext_id, &idx))