mail-index-sync-update.c revision 56f45b3f3ae20e5c933701f4657dda5ef1916855
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (C) 2004 Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "buffer.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "file-set-size.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mmap-util.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-index-view-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-index-sync-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-transaction-log.h"
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen#include "mail-transaction-util.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenstatic void
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenmail_index_header_update_counts(struct mail_index_header *hdr,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen uint8_t old_flags, uint8_t new_flags)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen if (((old_flags ^ new_flags) & MAIL_RECENT) != 0) {
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen /* different recent-flag */
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen if ((old_flags & MAIL_RECENT) == 0)
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen hdr->recent_messages_count++;
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen else if (--hdr->recent_messages_count == 0)
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen hdr->first_recent_uid_lowwater = hdr->next_uid;
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen }
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (((old_flags ^ new_flags) & MAIL_SEEN) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* different seen-flag */
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen if ((old_flags & MAIL_SEEN) != 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hdr->seen_messages_count--;
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen else if (++hdr->seen_messages_count == hdr->messages_count)
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen hdr->first_unseen_uid_lowwater = hdr->next_uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (((old_flags ^ new_flags) & MAIL_DELETED) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* different deleted-flag */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((old_flags & MAIL_DELETED) == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hdr->deleted_messages_count++;
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen else if (--hdr->deleted_messages_count == 0)
d482b35af87f5fd872bad007da0475813a401a49Timo Sirainen hdr->first_deleted_uid_lowwater = hdr->next_uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenstatic void
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenmail_index_header_update_lowwaters(struct mail_index_header *hdr,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen const struct mail_index_record *rec)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((rec->flags & MAIL_RECENT) != 0 &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen rec->uid < hdr->first_recent_uid_lowwater)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hdr->first_recent_uid_lowwater = rec->uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((rec->flags & MAIL_SEEN) == 0 &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen rec->uid < hdr->first_unseen_uid_lowwater)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hdr->first_unseen_uid_lowwater = rec->uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((rec->flags & MAIL_DELETED) != 0 &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen rec->uid < hdr->first_deleted_uid_lowwater)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hdr->first_deleted_uid_lowwater = rec->uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
53238473bf77147660aa6db9daa68a8a685e9381Timo Sirainenstatic int sync_expunge(const struct mail_transaction_expunge *e, void *context)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
53238473bf77147660aa6db9daa68a8a685e9381Timo Sirainen struct mail_index_view *view = context;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen struct mail_index *index = view->index;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen struct mail_index_map *map = view->map;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen struct mail_index_header *hdr = &map->hdr_copy;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_index_record *rec;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen uint32_t count, seq, seq1, seq2;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen int ret;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen i_assert(MAIL_INDEX_MAP_IS_IN_MEMORY(map));
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen ret = mail_index_lookup_uid_range(view, e->uid1, e->uid2, &seq1, &seq2);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen i_assert(ret == 0);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (seq1 == 0)
53238473bf77147660aa6db9daa68a8a685e9381Timo Sirainen return 1;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen for (seq = seq1; seq <= seq2; seq++) {
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen rec = MAIL_INDEX_MAP_IDX(index, map, seq-1);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen mail_index_header_update_counts(hdr, rec->flags, 0);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen }
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen /* @UNSAFE */
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen count = seq2 - seq1 + 1;
53238473bf77147660aa6db9daa68a8a685e9381Timo Sirainen memmove(MAIL_INDEX_MAP_IDX(index, map, seq1-1),
53238473bf77147660aa6db9daa68a8a685e9381Timo Sirainen MAIL_INDEX_MAP_IDX(index, map, seq2),
53238473bf77147660aa6db9daa68a8a685e9381Timo Sirainen (map->records_count - seq2) * view->index->record_size);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen map->records_count -= count;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen hdr->messages_count -= count;
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen view->messages_count -= count;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (map->buffer != NULL) {
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen buffer_set_used_size(map->buffer, map->records_count *
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen view->index->record_size);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen map->records = buffer_get_modifyable_data(map->buffer, NULL);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen }
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen return 1;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenstatic int sync_append(const struct mail_index_record *rec, void *context)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen{
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen struct mail_index_view *view = context;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen struct mail_index *index = view->index;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen struct mail_index_map *map = view->map;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (rec->uid < map->hdr_copy.next_uid) {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen mail_transaction_log_view_set_corrupted(view->log_view,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen "Append with UID %u, but next_uid = %u",
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen rec->uid, map->hdr_copy.next_uid);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen return -1;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen }
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (MAIL_INDEX_MAP_IS_IN_MEMORY(map)) {
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen i_assert(map->records_count * index->record_size ==
ace3c14e47a5a865df8aeea2fabc993b609dd163Timo Sirainen buffer_get_used_size(map->buffer));
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen buffer_append(map->buffer, rec, index->record_size);
ace3c14e47a5a865df8aeea2fabc993b609dd163Timo Sirainen map->records = buffer_get_modifyable_data(map->buffer, NULL);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen } else {
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen i_assert((map->records_count+1) * index->record_size <=
ace3c14e47a5a865df8aeea2fabc993b609dd163Timo Sirainen map->mmap_size);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen memcpy(MAIL_INDEX_MAP_IDX(index, map, map->records_count),
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen rec, index->record_size);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen }
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen map->hdr_copy.messages_count++;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen map->hdr_copy.next_uid = rec->uid+1;
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen view->messages_count++;
ace3c14e47a5a865df8aeea2fabc993b609dd163Timo Sirainen map->records_count++;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
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 Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenstatic int sync_flag_update(const struct mail_transaction_flag_update *u,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen void *context)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen struct mail_index_view *view = context;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen struct mail_index_record *rec;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen struct mail_index_header *hdr;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint8_t flag_mask, old_flags;
d8b77aef97e89f1ccc5cbdaef77be9052279e35fTimo Sirainen keywords_mask_t keyword_mask;
46ba60afe16f39d49100ee79f45cd8b70e0e857cTimo Sirainen uint32_t i, idx, seq1, seq2;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen int update_keywords, ret;
659fe5d24825b160cae512538088020d97a60239Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen ret = mail_index_lookup_uid_range(view, u->uid1, u->uid2, &seq1, &seq2);
659fe5d24825b160cae512538088020d97a60239Timo Sirainen i_assert(ret == 0);
659fe5d24825b160cae512538088020d97a60239Timo Sirainen
659fe5d24825b160cae512538088020d97a60239Timo Sirainen if (seq1 == 0)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen hdr = &view->map->hdr_copy;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if ((u->add_flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen hdr->flags |= MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen
d8b77aef97e89f1ccc5cbdaef77be9052279e35fTimo Sirainen update_keywords = FALSE;
d8b77aef97e89f1ccc5cbdaef77be9052279e35fTimo Sirainen for (i = 0; i < INDEX_KEYWORDS_BYTE_COUNT; i++) {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (u->add_keywords[i] != 0 ||
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen u->remove_keywords[i] != 0)
d8b77aef97e89f1ccc5cbdaef77be9052279e35fTimo Sirainen update_keywords = TRUE;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen keyword_mask[i] = ~u->remove_keywords[i];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen flag_mask = ~u->remove_flags;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
46ba60afe16f39d49100ee79f45cd8b70e0e857cTimo Sirainen for (idx = seq1-1; idx < seq2; idx++) {
46ba60afe16f39d49100ee79f45cd8b70e0e857cTimo Sirainen rec = MAIL_INDEX_MAP_IDX(view->index, view->map, idx);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen old_flags = rec->flags;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen rec->flags = (rec->flags & flag_mask) | u->add_flags;
d8b77aef97e89f1ccc5cbdaef77be9052279e35fTimo Sirainen if (update_keywords) {
d8b77aef97e89f1ccc5cbdaef77be9052279e35fTimo Sirainen for (i = 0; i < INDEX_KEYWORDS_BYTE_COUNT; i++) {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen rec->keywords[i] = u->add_keywords[i] |
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen (rec->keywords[i] & keyword_mask[i]);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen mail_index_header_update_counts(hdr, old_flags, rec->flags);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen mail_index_header_update_lowwaters(hdr, rec);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen return 1;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen}
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainenstatic int sync_cache_reset(const struct mail_transaction_cache_reset *u,
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen void *context)
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen{
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen struct mail_index_view *view = context;
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen uint32_t i;
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen view->map->hdr_copy.cache_file_seq = u->new_file_seq;
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen for (i = 0; i < view->messages_count; i++)
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen MAIL_INDEX_MAP_IDX(view->index, view->map, i)->cache_offset = 0;
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen return 1;
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen}
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenstatic int sync_cache_update(const struct mail_transaction_cache_update *u,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen void *context)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen{
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen struct mail_index_view *view = context;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen uint32_t seq;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen int ret;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen ret = mail_index_lookup_uid_range(view, u->uid, u->uid,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen &seq, &seq);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen i_assert(ret == 0);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen if (seq != 0) {
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen MAIL_INDEX_MAP_IDX(view->index, view->map, seq-1)->
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen cache_offset = u->cache_offset;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen }
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen return 1;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen}
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenstatic int sync_header_update(const struct mail_transaction_header_update *u,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen void *context)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen{
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen struct mail_index_view *view = context;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen void *data;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen data = PTR_OFFSET(&view->map->hdr_copy, u->offset);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen memcpy(data, u->data, u->size);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainenstatic int
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainensync_extra_rec_update(const struct mail_transaction_extra_rec_header *hdr,
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen const struct mail_transaction_extra_rec_update *u,
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen void *context)
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen{
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen struct mail_index_view *view = context;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen struct mail_index_record *rec;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen uint32_t seq;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen uint16_t offset, size;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen int ret;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen /* FIXME: do data_id mapping conversion */
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen ret = mail_index_lookup_uid_range(view, u->uid, u->uid,
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen &seq, &seq);
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen i_assert(ret == 0);
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen if (seq != 0) {
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen offset = view->index->extra_records[hdr->idx].offset;
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen size = view->index->extra_records[hdr->idx].size;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen rec = MAIL_INDEX_MAP_IDX(view->index, view->map, seq-1);
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen memcpy(PTR_OFFSET(rec, offset), u->data, size);
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen }
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen return 1;
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen}
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenstatic int mail_index_grow(struct mail_index *index, struct mail_index_map *map,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen unsigned int count)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen size_t size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6a675eda973195f8c00c101519521b788781ba37Timo Sirainen if (MAIL_INDEX_MAP_IS_IN_MEMORY(map))
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen return 0;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen i_assert(map == index->map);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen size = map->hdr->header_size +
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen (map->records_count + count) * index->record_size;
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen if (size <= map->mmap_size)
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen return 0;
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen
690af4a90eaf8611c2573d34126bb7a852c50a44Timo Sirainen /* when we grow fast, do it exponentially */
690af4a90eaf8611c2573d34126bb7a852c50a44Timo Sirainen if (count < index->last_grow_count)
690af4a90eaf8611c2573d34126bb7a852c50a44Timo Sirainen count = index->last_grow_count;
e4fb5bfcdff32d337d054cce36e00e1cdfaae9f8Timo Sirainen if (count < MAIL_INDEX_MAX_POWER_GROW)
e4fb5bfcdff32d337d054cce36e00e1cdfaae9f8Timo Sirainen count = nearest_power(count);
690af4a90eaf8611c2573d34126bb7a852c50a44Timo Sirainen index->last_grow_count = count;
690af4a90eaf8611c2573d34126bb7a852c50a44Timo Sirainen
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen size = map->hdr->header_size +
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen (map->records_count + count) * index->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()");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (mail_index_map(index, TRUE) <= 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen i_assert(map->mmap_size >= size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenint mail_index_sync_update_index(struct mail_index_sync_ctx *sync_ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_index *index = sync_ctx->index;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen struct mail_index_view *view = sync_ctx->view;
215daa7d5bf9a849849586490fd6fdd28a724dd8Timo Sirainen struct mail_index_map *map;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen const struct mail_transaction_header *hdr;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen const void *data;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen unsigned int lock_id, count;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen uint32_t seq, i;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen uoff_t offset;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen int ret, had_dirty, skipped;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
5c1a8aee989af87bddefd71e2aa83aa2bd695155Timo Sirainen if (mail_index_lock_exclusive(index, &lock_id) < 0)
5c1a8aee989af87bddefd71e2aa83aa2bd695155Timo Sirainen return -1;
5c1a8aee989af87bddefd71e2aa83aa2bd695155Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen /* NOTE: locking may change index->map so make sure assignment
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen after locking */
215daa7d5bf9a849849586490fd6fdd28a724dd8Timo Sirainen map = index->map;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (MAIL_INDEX_MAP_IS_IN_MEMORY(map))
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen map->write_to_disk = TRUE;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen map->hdr_copy = *map->hdr;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen map->hdr = &map->hdr_copy;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen mail_index_unmap(index, view->map);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen view->map = map;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen view->map->refcount++;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen had_dirty = (map->hdr_copy.flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) != 0;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (had_dirty)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen map->hdr_copy.flags &= ~MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen while ((ret = mail_transaction_log_view_next(view->log_view, &hdr,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen &data, &skipped)) > 0) {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) != 0 &&
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen !map->write_to_disk) {
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 */
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen map = mail_index_map_to_memory(index, map);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen mail_index_unmap(index, view->map);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen view->map = map;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen view->map->refcount++;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen mail_index_unmap(index, index->map);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen index->map = map;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen index->hdr = map->hdr;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen map->write_to_disk = TRUE;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen }
659fe5d24825b160cae512538088020d97a60239Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_APPEND) != 0) {
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen count = hdr->size / index->record_size;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (mail_index_grow(index, view->map, count) < 0)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen return -1;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen if (mail_transaction_map(index, hdr, data,
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen &mail_index_map_sync_funcs,
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen view) < 0) {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen ret = -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if (ret < 0)
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen mail_transaction_log_get_head(index->log, &seq, &offset);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen map->hdr_copy.log_file_seq = seq;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen map->hdr_copy.log_file_offset = offset;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen if ((map->hdr_copy.flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) == 0 &&
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen had_dirty) {
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen /* do we have dirty flags anymore? */
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen const struct mail_index_record *rec;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen for (i = 0; i < map->records_count; i++) {
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen rec = MAIL_INDEX_MAP_IDX(index, map, i);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen if ((rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen map->hdr_copy.flags |=
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen break;
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen }
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen }
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen }
b35f7104715edee0cfac6d46ab0b342033867eb7Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen if (!MAIL_INDEX_MAP_IS_IN_MEMORY(map)) {
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen map->mmap_used_size = index->hdr->header_size +
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen map->records_count * index->record_size;
b2105c78f0fd58281317e6d777ded860f33153a3Timo Sirainen
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()");
5c1a8aee989af87bddefd71e2aa83aa2bd695155Timo Sirainen ret = -1;
5c1a8aee989af87bddefd71e2aa83aa2bd695155Timo Sirainen }
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen map->hdr = map->mmap_base;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
5c1a8aee989af87bddefd71e2aa83aa2bd695155Timo Sirainen mail_index_unlock(index, lock_id);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainenstruct mail_transaction_map_functions mail_index_map_sync_funcs = {
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen sync_expunge, sync_append, sync_flag_update,
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen sync_cache_reset, sync_cache_update, sync_header_update,
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen sync_extra_rec_update
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen};