From: Timo Sirainen Date: Sun, 14 Dec 2008 05:19:48 +0000 (+0200) Subject: mail_get_flags/keywords() now returns updated values if they've been changed within... X-Git-Tag: 1.2.alpha5~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3fe9483b2b412a14493e3120751b0e99ecfe9388;p=thirdparty%2Fdovecot%2Fcore.git mail_get_flags/keywords() now returns updated values if they've been changed within transaction. --HG-- branch : HEAD --- diff --git a/src/lib-index/mail-index-dummy-view.c b/src/lib-index/mail-index-dummy-view.c index 9ca058b276..c625a4ae58 100644 --- a/src/lib-index/mail-index-dummy-view.c +++ b/src/lib-index/mail-index-dummy-view.c @@ -29,6 +29,7 @@ static struct mail_index_view_vfuncs dummy_view_vfuncs = { NULL, NULL, NULL, + NULL, NULL }; diff --git a/src/lib-index/mail-index-transaction-private.h b/src/lib-index/mail-index-transaction-private.h index 979c639e86..99bc50589c 100644 --- a/src/lib-index/mail-index-transaction-private.h +++ b/src/lib-index/mail-index-transaction-private.h @@ -100,6 +100,12 @@ uint32_t mail_index_transaction_get_next_uid(struct mail_index_transaction *t); void mail_index_transaction_convert_to_uids(struct mail_index_transaction *t); void mail_index_transaction_check_conflicts(struct mail_index_transaction *t); +unsigned int +mail_index_transaction_get_flag_update_pos(struct mail_index_transaction *t, + unsigned int left_idx, + unsigned int right_idx, + uint32_t seq); + bool mail_index_seq_array_lookup(const ARRAY_TYPE(seq_array) *array, uint32_t seq, unsigned int *idx_r); diff --git a/src/lib-index/mail-index-transaction-view.c b/src/lib-index/mail-index-transaction-view.c index 87e5576332..3c16ad7a0b 100644 --- a/src/lib-index/mail-index-transaction-view.c +++ b/src/lib-index/mail-index-transaction-view.c @@ -15,8 +15,12 @@ struct mail_index_view_transaction { struct mail_index_map *lookup_map; struct mail_index_header hdr; + buffer_t *lookup_return_data; uint32_t lookup_prev_seq; + + unsigned int recs_count; + struct mail_index_record *recs; }; static void tview_close(struct mail_index_view *view) @@ -29,6 +33,7 @@ static void tview_close(struct mail_index_view *view) mail_index_unmap(&tview->lookup_map); if (tview->lookup_return_data != NULL) buffer_free(&tview->lookup_return_data); + i_free(tview->recs); tview->super->close(view); mail_index_transaction_unref(&t); @@ -64,6 +69,42 @@ tview_get_header(struct mail_index_view *view) return hdr; } +static const struct mail_index_record * +tview_apply_flag_updates(struct mail_index_view_transaction *tview, + const struct mail_index_record *rec, uint32_t seq) +{ + struct mail_index_transaction *t = tview->t; + const struct mail_transaction_flag_update *updates; + unsigned int idx, count; + + /* see if there are any flag updates */ + if (seq < t->min_flagupdate_seq || seq > t->max_flagupdate_seq || + !array_is_created(&t->updates)) + return rec; + + updates = array_get(&t->updates, &count); + idx = mail_index_transaction_get_flag_update_pos(t, 0, count, seq); + if (seq < updates[idx].uid1 || seq > updates[idx].uid2) + return rec; + + /* yes, we have flag updates. since we can't modify rec directly and + we want to be able to handle multiple mail_index_lookup() calls + without the second one overriding the first one's data, we'll + create a records array and return data from there */ + if (tview->recs == NULL) { + tview->recs_count = t->first_new_seq; + tview->recs = i_new(struct mail_index_record, + tview->recs_count); + } + i_assert(tview->recs_count == t->first_new_seq); + i_assert(seq > 0 && seq <= tview->recs_count); + + tview->recs[seq-1] = *rec; + tview->recs[seq-1].flags |= updates[idx].add_flags; + tview->recs[seq-1].flags &= ~updates[idx].remove_flags; + return &tview->recs[seq-1]; +} + static const struct mail_index_record * tview_lookup_full(struct mail_index_view *view, uint32_t seq, struct mail_index_map **map_r, bool *expunged_r) @@ -81,8 +122,8 @@ tview_lookup_full(struct mail_index_view *view, uint32_t seq, } rec = tview->super->lookup_full(view, seq, map_r, expunged_r); + rec = tview_apply_flag_updates(tview, rec, seq); - /* if we're expunged within this transaction, return 0 */ if (array_is_created(&tview->t->expunges) && seq_range_exists(&tview->t->expunges, seq)) *expunged_r = TRUE; @@ -190,6 +231,73 @@ static void tview_lookup_first(struct mail_index_view *view, } } +static void keyword_index_add(ARRAY_TYPE(keyword_indexes) *keywords, + unsigned int idx) +{ + const unsigned int *indexes; + unsigned int i, count; + + indexes = array_get(keywords, &count); + for (i = 0; i < count; i++) { + if (indexes[i] == idx) + return; + } + array_append(keywords, &idx, 1); +} + +static void keyword_index_remove(ARRAY_TYPE(keyword_indexes) *keywords, + unsigned int idx) +{ + const unsigned int *indexes; + unsigned int i, count; + + indexes = array_get(keywords, &count); + for (i = 0; i < count; i++) { + if (indexes[i] == idx) { + array_delete(keywords, i, 1); + break; + } + } +} + +static void tview_lookup_keywords(struct mail_index_view *view, uint32_t seq, + ARRAY_TYPE(keyword_indexes) *keyword_idx) +{ + struct mail_index_view_transaction *tview = + (struct mail_index_view_transaction *)view; + struct mail_index_transaction *t = tview->t; + const struct mail_index_transaction_keyword_update *updates; + unsigned int i, count; + + tview->super->lookup_keywords(view, seq, keyword_idx); + + if (seq < t->min_flagupdate_seq || seq > t->max_flagupdate_seq) { + /* no keyword updates for this sequence */ + return; + } + + /* apply any keyword updates in this transaction */ + if (array_is_created(&t->keyword_resets)) { + if (seq_range_exists(&t->keyword_resets, seq)) + array_clear(keyword_idx); + } + + if (array_is_created(&t->keyword_updates)) + updates = array_get(&t->keyword_updates, &count); + else { + updates = NULL; + count = 0; + } + for (i = 0; i < count; i++) { + if (array_is_created(&updates[i].add_seq) && + seq_range_exists(&updates[i].add_seq, seq)) + keyword_index_add(keyword_idx, i); + else if (array_is_created(&updates[i].remove_seq) && + seq_range_exists(&updates[i].remove_seq, seq)) + keyword_index_remove(keyword_idx, i); + } +} + static struct mail_index_map * tview_get_lookup_map(struct mail_index_view_transaction *tview) { @@ -336,6 +444,7 @@ static struct mail_index_view_vfuncs trans_view_vfuncs = { tview_lookup_uid, tview_lookup_seq_range, tview_lookup_first, + tview_lookup_keywords, tview_lookup_ext_full, tview_get_header_ext, tview_ext_get_reset_id diff --git a/src/lib-index/mail-index-transaction.c b/src/lib-index/mail-index-transaction.c index 90268a0985..f3593c5eb0 100644 --- a/src/lib-index/mail-index-transaction.c +++ b/src/lib-index/mail-index-transaction.c @@ -805,10 +805,11 @@ mail_transaction_update_want_add(struct mail_index_transaction *t, return FALSE; } -static uint32_t -mail_index_find_update_insert_pos(struct mail_index_transaction *t, - unsigned int left_idx, unsigned int right_idx, - uint32_t seq) +unsigned int +mail_index_transaction_get_flag_update_pos(struct mail_index_transaction *t, + unsigned int left_idx, + unsigned int right_idx, + uint32_t seq) { const struct mail_transaction_flag_update *updates; unsigned int idx, count; @@ -1038,8 +1039,8 @@ void mail_index_update_flags_range(struct mail_index_transaction *t, first_idx = 0; count = t->last_update_idx + 1; } - idx = mail_index_find_update_insert_pos(t, first_idx, count, - u.uid1); + idx = mail_index_transaction_get_flag_update_pos(t, first_idx, + count, u.uid1); mail_index_insert_flag_update(t, u, idx); } } @@ -1567,7 +1568,7 @@ mail_index_update_cancel(struct mail_index_transaction *t, uint32_t seq) return ret; updates = array_get_modifiable(&t->updates, &count); - i = mail_index_find_update_insert_pos(t, 0, count, seq); + i = mail_index_transaction_get_flag_update_pos(t, 0, count, seq); if (i < count && updates[i].uid1 <= seq && updates[i].uid2 >= seq) { /* exists */ ret = TRUE; diff --git a/src/lib-index/mail-index-view-private.h b/src/lib-index/mail-index-view-private.h index af27c24986..ead2c51b70 100644 --- a/src/lib-index/mail-index-view-private.h +++ b/src/lib-index/mail-index-view-private.h @@ -26,6 +26,8 @@ struct mail_index_view_vfuncs { void (*lookup_first)(struct mail_index_view *view, enum mail_flags flags, uint8_t flags_mask, uint32_t *seq_r); + void (*lookup_keywords)(struct mail_index_view *view, uint32_t seq, + ARRAY_TYPE(keyword_indexes) *keyword_idx); void (*lookup_ext_full)(struct mail_index_view *view, uint32_t seq, uint32_t ext_id, struct mail_index_map **map_r, const void **data_r, bool *expunged_r); diff --git a/src/lib-index/mail-index-view.c b/src/lib-index/mail-index-view.c index e54ad467b2..58e4aed767 100644 --- a/src/lib-index/mail-index-view.c +++ b/src/lib-index/mail-index-view.c @@ -332,6 +332,62 @@ static void view_lookup_first(struct mail_index_view *view, } } +static void +mail_index_data_lookup_keywords(struct mail_index_map *map, + const unsigned char *data, + ARRAY_TYPE(keyword_indexes) *keyword_idx) +{ + const unsigned int *keyword_idx_map; + unsigned int i, j, keyword_count, index_idx; + uint32_t idx; + uint16_t record_size; + + array_clear(keyword_idx); + if (data == NULL) { + /* no keywords at all in index */ + return; + } + (void)mail_index_ext_get_size(NULL, map->index->keywords_ext_id, + map, NULL, &record_size, NULL); + + /* keyword_idx_map[] contains file => index keyword mapping */ + if (!array_is_created(&map->keyword_idx_map)) + return; + + keyword_idx_map = array_get(&map->keyword_idx_map, &keyword_count); + for (i = 0, idx = 0; i < record_size; i++) { + /* first do the quick check to see if there's keywords at all */ + if (data[i] == 0) + continue; + + idx = i * CHAR_BIT; + for (j = 0; j < CHAR_BIT; j++, idx++) { + if ((data[i] & (1 << j)) == 0) + continue; + + if (idx >= keyword_count) { + /* extra bits set in keyword bytes. + shouldn't happen, but just ignore. */ + break; + } + + index_idx = keyword_idx_map[idx]; + array_append(keyword_idx, &index_idx, 1); + } + } +} + +static void view_lookup_keywords(struct mail_index_view *view, uint32_t seq, + ARRAY_TYPE(keyword_indexes) *keyword_idx) +{ + struct mail_index_map *map; + const void *data; + + mail_index_lookup_ext_full(view, seq, view->index->keywords_ext_id, + &map, &data, NULL); + mail_index_data_lookup_keywords(map, data, keyword_idx); +} + static void view_lookup_ext_full(struct mail_index_view *view, uint32_t seq, uint32_t ext_id, struct mail_index_map **map_r, @@ -442,51 +498,6 @@ bool mail_index_is_expunged(struct mail_index_view *view, uint32_t seq) return expunged; } -static void -mail_index_data_lookup_keywords(struct mail_index_map *map, - const unsigned char *data, - ARRAY_TYPE(keyword_indexes) *keyword_idx) -{ - const unsigned int *keyword_idx_map; - unsigned int i, j, keyword_count, index_idx; - uint32_t idx; - uint16_t record_size; - - array_clear(keyword_idx); - if (data == NULL) { - /* no keywords at all in index */ - return; - } - (void)mail_index_ext_get_size(NULL, map->index->keywords_ext_id, - map, NULL, &record_size, NULL); - - /* keyword_idx_map[] contains file => index keyword mapping */ - if (!array_is_created(&map->keyword_idx_map)) - return; - - keyword_idx_map = array_get(&map->keyword_idx_map, &keyword_count); - for (i = 0, idx = 0; i < record_size; i++) { - /* first do the quick check to see if there's keywords at all */ - if (data[i] == 0) - continue; - - idx = i * CHAR_BIT; - for (j = 0; j < CHAR_BIT; j++, idx++) { - if ((data[i] & (1 << j)) == 0) - continue; - - if (idx >= keyword_count) { - /* extra bits set in keyword bytes. - shouldn't happen, but just ignore. */ - break; - } - - index_idx = keyword_idx_map[idx]; - array_append(keyword_idx, &index_idx, 1); - } - } -} - void mail_index_map_lookup_keywords(struct mail_index_map *map, uint32_t seq, ARRAY_TYPE(keyword_indexes) *keyword_idx) { @@ -509,12 +520,7 @@ void mail_index_map_lookup_keywords(struct mail_index_map *map, uint32_t seq, void mail_index_lookup_keywords(struct mail_index_view *view, uint32_t seq, ARRAY_TYPE(keyword_indexes) *keyword_idx) { - struct mail_index_map *map; - const void *data; - - mail_index_lookup_ext_full(view, seq, view->index->keywords_ext_id, - &map, &data, NULL); - mail_index_data_lookup_keywords(map, data, keyword_idx); + view->v.lookup_keywords(view, seq, keyword_idx); } void mail_index_lookup_uid(struct mail_index_view *view, uint32_t seq, @@ -625,6 +631,7 @@ static struct mail_index_view_vfuncs view_vfuncs = { view_lookup_uid, view_lookup_seq_range, view_lookup_first, + view_lookup_keywords, view_lookup_ext_full, view_get_header_ext, view_ext_get_reset_id diff --git a/src/lib-storage/index/index-mail.c b/src/lib-storage/index/index-mail.c index 7c440ae76c..65bac036ae 100644 --- a/src/lib-storage/index/index-mail.c +++ b/src/lib-storage/index/index-mail.c @@ -122,12 +122,17 @@ bool index_mail_get_cached_uoff_t(struct index_mail *mail, enum mail_flags index_mail_get_flags(struct mail *_mail) { struct index_mail *mail = (struct index_mail *)_mail; - struct index_mail_data *data = &mail->data; + const struct mail_index_record *rec; + enum mail_flags flags; + + rec = mail_index_lookup(mail->trans->trans_view, _mail->seq); + flags = rec->flags & (MAIL_FLAGS_NONRECENT | + MAIL_INDEX_MAIL_FLAG_BACKEND); if (index_mailbox_is_recent(mail->ibox, _mail->uid)) - data->flags |= MAIL_RECENT; + flags |= MAIL_RECENT; - return data->flags; + return flags; } uint64_t index_mail_get_modseq(struct mail *_mail) @@ -180,7 +185,8 @@ index_mail_get_keyword_indexes(struct mail *_mail) if (!array_is_created(&data->keyword_indexes)) { p_array_init(&data->keyword_indexes, mail->data_pool, 32); - mail_index_lookup_keywords(mail->ibox->view, mail->data.seq, + mail_index_lookup_keywords(mail->trans->trans_view, + mail->data.seq, &data->keyword_indexes); } return &data->keyword_indexes; @@ -1176,7 +1182,6 @@ void index_mail_set_seq(struct mail *_mail, uint32_t seq) struct index_mail_data *data = &mail->data; struct mail_cache_field *cache_fields = mail->ibox->cache_fields; struct mail_cache_view *cache_view = mail->trans->cache_view; - const struct mail_index_record *rec; struct istream *input; if (data->seq == seq) @@ -1184,13 +1189,11 @@ void index_mail_set_seq(struct mail *_mail, uint32_t seq) index_mail_reset(mail); - rec = mail_index_lookup(mail->trans->trans_view, seq); data->seq = seq; - data->flags = rec->flags & (MAIL_FLAGS_NONRECENT | - MAIL_INDEX_MAIL_FLAG_BACKEND); mail->mail.mail.seq = seq; - mail->mail.mail.uid = rec->uid; + mail_index_lookup_uid(mail->trans->trans_view, seq, + &mail->mail.mail.uid); if (mail_index_view_is_inconsistent(mail->trans->trans_view)) { mail_set_expunged(&mail->mail.mail); @@ -1395,6 +1398,18 @@ void index_mail_update_keywords(struct mail *mail, enum modify_type modify_type, { struct index_mail *imail = (struct index_mail *)mail; + if (array_is_created(&imail->data.keyword_indexes)) + array_free(&imail->data.keyword_indexes); + if (array_is_created(&imail->data.keywords)) { + /* clear the keywords array so the next mail_get_keywords() + returns the updated keywords. don't free the array, because + then any existing mail_get_keywords() return values would + point to broken data. this won't leak memory because the + array is allocated from mail's memory pool. */ + memset(&imail->data.keywords, 0, + sizeof(imail->data.keywords)); + } + mail_index_update_keywords(imail->trans->trans, mail->seq, modify_type, keywords); } diff --git a/src/lib-storage/index/index-mail.h b/src/lib-storage/index/index-mail.h index 141782376b..d63cc9d8ce 100644 --- a/src/lib-storage/index/index-mail.h +++ b/src/lib-storage/index/index-mail.h @@ -69,7 +69,6 @@ struct index_mail_line { struct message_header_line; struct index_mail_data { - enum mail_flags flags; time_t date, received_date, save_date; uoff_t virtual_size, physical_size; diff --git a/src/plugins/virtual/virtual-mail.c b/src/plugins/virtual/virtual-mail.c index 1b132a8c52..234bdf5d49 100644 --- a/src/plugins/virtual/virtual-mail.c +++ b/src/plugins/virtual/virtual-mail.c @@ -83,7 +83,6 @@ static void virtual_mail_set_seq(struct mail *mail, uint32_t seq) struct mailbox_transaction_context *backend_trans; struct mailbox_header_lookup_ctx *backend_headers; const struct virtual_mail_index_record *vrec; - const struct mail_index_record *rec; const void *data; bool expunged; @@ -112,12 +111,9 @@ static void virtual_mail_set_seq(struct mail *mail, uint32_t seq) memset(&vmail->imail.data, 0, sizeof(vmail->imail.data)); p_clear(vmail->imail.data_pool); - rec = mail_index_lookup(mbox->ibox.view, seq); vmail->imail.data.seq = seq; - vmail->imail.data.flags = rec->flags & MAIL_FLAGS_NONRECENT; - mail->seq = seq; - mail->uid = rec->uid; + mail_index_lookup_uid(mbox->ibox.view, seq, &mail->uid); mail->expunged = vmail->backend_mail->expunged; mail->has_nuls = vmail->backend_mail->has_nuls;