mail-index-sync-update.c revision 72cbf33ae81fde08384d30c779ff540752d9256c
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2004 Timo Sirainen */
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenmail_index_header_update_counts(struct mail_index_header *hdr,
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen if (((old_flags ^ new_flags) & MAIL_RECENT) != 0) {
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen /* different recent-flag */
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen hdr->first_recent_uid_lowwater = hdr->next_uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (((old_flags ^ new_flags) & MAIL_SEEN) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* different seen-flag */
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen else if (++hdr->seen_messages_count == hdr->messages_count)
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen hdr->first_unseen_uid_lowwater = hdr->next_uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (((old_flags ^ new_flags) & MAIL_DELETED) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* different deleted-flag */
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen hdr->first_deleted_uid_lowwater = hdr->next_uid;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenmail_index_header_update_lowwaters(struct mail_index_header *hdr,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainenstatic void mail_index_sync_cache_expunge(struct mail_index_sync_ctx *sync_ctx,
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen if (mail_cache_lock(sync_ctx->view->index->cache) <= 0)
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen (void)mail_cache_delete(sync_ctx->index->cache, cache_offset);
53238473bf77147660aa6db9daa68a8a685e9381Timo Sirainenstatic int sync_expunge(const struct mail_transaction_expunge *e, void *context)
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen struct mail_index_sync_ctx *sync_ctx = context;
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen struct mail_index_view *view = sync_ctx->view;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen struct mail_index_header *hdr = &map->hdr_copy;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen ret = mail_index_lookup_uid_range(view, e->uid1, e->uid2, &seq1, &seq2);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen mail_index_header_update_counts(hdr, rec->flags, 0);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen /* @UNSAFE */
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen memmove(MAIL_INDEX_MAP_IDX(map, seq1-1), MAIL_INDEX_MAP_IDX(map, seq2),
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen (map->records_count - seq2) * map->hdr->record_size);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen buffer_set_used_size(map->buffer, map->records_count *
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen map->records = buffer_get_modifyable_data(map->buffer, NULL);
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainenstatic int sync_append(const struct mail_transaction_append_header *hdr,
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen const struct mail_index_record *rec, void *context)
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen struct mail_index_sync_ctx *sync_ctx = context;
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen struct mail_index_view *view = sync_ctx->view;
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen i_assert(hdr->record_size <= map->hdr->record_size);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen mail_transaction_log_view_set_corrupted(view->log_view,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen "Append with UID %u, but next_uid = %u",
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen i_assert(map->records_count * map->hdr->record_size ==
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen dest = buffer_append_space_unsafe(map->buffer,
ace3c14e47a5a865df8aeea2fabc993b609dd163Timo Sirainen map->records = buffer_get_modifyable_data(map->buffer, NULL);
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen i_assert((map->records_count+1) * map->hdr->record_size <=
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen dest = MAIL_INDEX_MAP_IDX(map, map->records_count);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen mail_index_header_update_counts(&map->hdr_copy, 0, rec->flags);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen mail_index_header_update_lowwaters(&map->hdr_copy, rec);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenstatic int sync_flag_update(const struct mail_transaction_flag_update *u,
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen struct mail_index_sync_ctx *sync_ctx = context;
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen struct mail_index_view *view = sync_ctx->view;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen ret = mail_index_lookup_uid_range(view, u->uid1, u->uid2, &seq1, &seq2);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if ((u->add_flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0)
d8b77aef97e89f1ccc5cbdaef77be9052279e35fTimo Sirainen for (i = 0; i < INDEX_KEYWORDS_BYTE_COUNT; i++) {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (u->add_keywords[i] != 0 ||
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen rec->flags = (rec->flags & flag_mask) | u->add_flags;
d8b77aef97e89f1ccc5cbdaef77be9052279e35fTimo Sirainen for (i = 0; i < INDEX_KEYWORDS_BYTE_COUNT; i++) {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen mail_index_header_update_counts(hdr, old_flags, rec->flags);
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainenstatic int sync_cache_reset(const struct mail_transaction_cache_reset *u,
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen struct mail_index_sync_ctx *sync_ctx = context;
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen struct mail_index_view *view = sync_ctx->view;
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen view->map->hdr_copy.cache_file_seq = u->new_file_seq;
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen MAIL_INDEX_MAP_IDX(view->map, i)->cache_offset = 0;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenstatic int sync_cache_update(const struct mail_transaction_cache_update *u,
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen struct mail_index_sync_ctx *sync_ctx = context;
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen struct mail_index_view *view = sync_ctx->view;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen ret = mail_index_lookup_uid_range(view, u->uid, u->uid,
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen /* already expunged */
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen /* we'll need to link the old and new cache records */
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenstatic int sync_header_update(const struct mail_transaction_header_update *u,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen data = PTR_OFFSET(&view->map->hdr_copy, u->offset);
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainensync_extra_rec_update(const struct mail_transaction_extra_rec_header *hdr,
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen const struct mail_transaction_extra_rec_update *u,
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen /* FIXME: do data_id mapping conversion */
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen ret = mail_index_lookup_uid_range(view, u->uid, u->uid,
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen offset = view->index->extra_records[hdr->idx].offset;
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen size = view->index->extra_records[hdr->idx].size;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen memcpy(PTR_OFFSET(rec, offset), u->data, size);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenstatic int mail_index_grow(struct mail_index *index, struct mail_index_map *map,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen unsigned int count)
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen (map->records_count + count) * map->hdr->record_size;
690af4a90eaf8611c2573d34126bb7a852c50a44Timo Sirainen /* when we grow fast, do it exponentially */
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen (map->records_count + count) * map->hdr->record_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (file_set_size(index->fd, (off_t)size) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return mail_index_set_syscall_error(index, "file_set_size()");
ea546eaab672d441e180b7619d4750be813c08d8Timo Sirainen /* we only wish to grow the file, but mail_index_map() updates the
ea546eaab672d441e180b7619d4750be813c08d8Timo Sirainen headers as well and may break our modified hdr_copy. so, take
ea546eaab672d441e180b7619d4750be813c08d8Timo Sirainen a backup of it and put it back afterwards */
d9e49848cb4a08f140892d76c2b54afabb9e675aTimo Sirainen map->records_count = map->hdr->messages_count;
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainenstatic void mail_index_sync_replace_map(struct mail_index_view *view,
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen mail_index_unmap(view->index, view->index->map);
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainenmail_index_update_day_headers(struct mail_index_header *hdr, uint32_t uid)
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen sizeof(hdr->day_first_uid) / sizeof(hdr->day_first_uid[0]);
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen /* get beginning of today */
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen /* get number of days since last message */
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen /* @UNSAFE: move days forward and fill the missing days with old
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen day_first_uid[0]. */
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen hdr->day_first_uid[i] = hdr->day_first_uid[0];
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenint mail_index_sync_update_index(struct mail_index_sync_ctx *sync_ctx)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen struct mail_index_view *view = sync_ctx->view;
fec0e90484c5f2c9da9cdc62c0897408023d4c6eTimo Sirainen /* we'll have to update view->lock_id to avoid mail_index_view_lock()
fec0e90484c5f2c9da9cdc62c0897408023d4c6eTimo Sirainen trying to update the file later. */
ea546eaab672d441e180b7619d4750be813c08d8Timo Sirainen if (mail_index_lock_exclusive(index, &view->lock_id) < 0)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen /* NOTE: locking may change index->map so make sure assignment
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen after locking */
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen had_dirty = (map->hdr_copy.flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) != 0;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen map->hdr_copy.flags &= ~MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen while ((ret = mail_transaction_log_view_next(view->log_view, &hdr,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) != 0 &&
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen /* expunges have to be atomic. so we'll have to copy
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen the mapping, do the changes there and then finally
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen replace the whole index file. to avoid extra disk
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen I/O we copy the index into memory rather than to
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen temporary file */
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_APPEND) != 0) {
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen const struct mail_transaction_append_header *append_hdr;
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen rec = CONST_PTR_OFFSET(data, sizeof(*append_hdr));
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen if (append_hdr->record_size > map->hdr->record_size) {
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen /* we have to grow our record size */
fec0e90484c5f2c9da9cdc62c0897408023d4c6eTimo Sirainen if (mail_index_grow(index, view->map, count) < 0) {
ea546eaab672d441e180b7619d4750be813c08d8Timo Sirainen i_assert(map->records_count == map->hdr->messages_count);
ea546eaab672d441e180b7619d4750be813c08d8Timo Sirainen i_assert(view->messages_count == map->hdr->messages_count);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen mail_transaction_log_get_head(index->log, &seq, &offset);
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen mail_index_update_day_headers(&map->hdr_copy, first_append_uid);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if ((map->hdr_copy.flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) == 0 &&
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen /* do we have dirty flags anymore? */
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen if ((rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen map->mmap_used_size = index->hdr->header_size +
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen memcpy(map->mmap_base, &map->hdr_copy, sizeof(map->hdr_copy));
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen if (msync(map->mmap_base, map->mmap_used_size, MS_SYNC) < 0) {
5c1a8aee989af87bddefd71e2aa83aa2bd695155Timo Sirainen mail_index_set_syscall_error(index, "msync()");
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenstruct mail_transaction_map_functions mail_index_map_sync_funcs = {