mail-index-sync-update.c revision e06c0b65c16ccce69bbee009ead14d7d3d17a256
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen/* Copyright (C) 2004 Timo Sirainen */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen#include "lib.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "buffer.h"
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen#include "file-set-size.h"
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen#include "mmap-util.h"
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen#include "mail-index-view-private.h"
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen#include "mail-index-sync-private.h"
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen#include "mail-transaction-log.h"
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen#include "mail-transaction-util.h"
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainenstatic void
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenmail_index_header_update_counts(struct mail_index_header *hdr,
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen uint8_t old_flags, uint8_t new_flags)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (((old_flags ^ new_flags) & MAIL_RECENT) != 0) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* different recent-flag */
190237ce467d2389dfb809874b0fec86d3c7968dTimo Sirainen if ((old_flags & MAIL_RECENT) == 0)
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen hdr->recent_messages_count++;
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen else if (--hdr->recent_messages_count == 0)
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen hdr->first_recent_uid_lowwater = hdr->next_uid;
8f7b00599e73fe71b1d2c6c65f8ae98aac1b23fbTimo Sirainen }
8f7b00599e73fe71b1d2c6c65f8ae98aac1b23fbTimo Sirainen
8f7b00599e73fe71b1d2c6c65f8ae98aac1b23fbTimo Sirainen if (((old_flags ^ new_flags) & MAIL_SEEN) != 0) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* different seen-flag */
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if ((old_flags & MAIL_SEEN) != 0)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen hdr->seen_messages_count--;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen else if (++hdr->seen_messages_count == hdr->messages_count)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen hdr->first_unseen_uid_lowwater = hdr->next_uid;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (((old_flags ^ new_flags) & MAIL_DELETED) != 0) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* different deleted-flag */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if ((old_flags & MAIL_DELETED) == 0)
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen hdr->deleted_messages_count++;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen else if (--hdr->deleted_messages_count == 0)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen hdr->first_deleted_uid_lowwater = hdr->next_uid;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenstatic void
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenmail_index_header_update_lowwaters(struct mail_index_header *hdr,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const struct mail_index_record *rec)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if ((rec->flags & MAIL_RECENT) != 0 &&
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen rec->uid < hdr->first_recent_uid_lowwater)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen hdr->first_recent_uid_lowwater = rec->uid;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if ((rec->flags & MAIL_SEEN) == 0 &&
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen rec->uid < hdr->first_unseen_uid_lowwater)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen hdr->first_unseen_uid_lowwater = rec->uid;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if ((rec->flags & MAIL_DELETED) != 0 &&
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen rec->uid < hdr->first_deleted_uid_lowwater)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen hdr->first_deleted_uid_lowwater = rec->uid;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenvoid mail_index_sync_expunge(struct mail_index_view *view,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const struct mail_transaction_expunge *e)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct mail_index_map *map = view->map;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct mail_index_header *hdr = &map->hdr_copy;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct mail_index_record *rec;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen uint32_t count, seq, seq1, seq2;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen int ret;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen i_assert(MAIL_INDEX_MAP_IS_IN_MEMORY(map));
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen ret = mail_index_lookup_uid_range(view, e->uid1, e->uid2, &seq1, &seq2);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen i_assert(ret == 0);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (seq1 == 0)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen rec = &map->records[seq1-1];
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen for (seq = seq1; seq <= seq2; seq++, rec++)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen mail_index_header_update_counts(hdr, rec->flags, 0);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* @UNSAFE */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen count = seq2 - seq1 + 1;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen memcpy(map->records + (seq1-1), map->records + seq2,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen (map->records_count - seq2) * sizeof(*map->records));
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen map->records_count -= count;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen hdr->messages_count -= count;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (map->buffer != NULL) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen buffer_set_used_size(map->buffer, map->records_count);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen map->records = buffer_get_modifyable_data(map->buffer, NULL);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenstatic int sync_expunge(const struct mail_transaction_expunge *e, void *context)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct mail_index_view *view = context;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen mail_index_sync_expunge(view, e);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return 1;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenstatic int sync_append(const struct mail_index_record *rec, void *context)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct mail_index_view *view = context;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct mail_index_map *map = view->map;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (rec->uid < map->hdr_copy.next_uid) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen mail_transaction_log_view_set_corrupted(view->log_view,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen "Append with UID %u, but next_uid = %u",
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen rec->uid, map->hdr_copy.next_uid);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return -1;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen if (MAIL_INDEX_MAP_IS_IN_MEMORY(map)) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (map->records_count * sizeof(*rec) >
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen buffer_get_used_size(map->buffer)) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen (void)buffer_append_space_unsafe(map->buffer,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen sizeof(*rec));
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen map->records =
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen buffer_get_modifyable_data(map->buffer, NULL);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen } else {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen i_assert(map->records_count * sizeof(*rec) <= map->mmap_size);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen map->records[map->records_count++] = *rec;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen map->hdr_copy.messages_count++;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen map->hdr_copy.next_uid = rec->uid+1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
055a42c6987f93fb88291f64813dfceb1b25895dTimo Sirainen mail_index_header_update_counts(&map->hdr_copy, 0, rec->flags);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen mail_index_header_update_lowwaters(&map->hdr_copy, rec);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return 1;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen}
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainenstatic int sync_flag_update(const struct mail_transaction_flag_update *u,
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen void *context)
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct mail_index_view *view = context;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct mail_index_record *rec, *end;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct mail_index_header *hdr;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen uint8_t flag_mask, old_flags;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen keywords_mask_t keyword_mask;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen uint32_t seq1, seq2;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen int i, update_keywords, ret;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen ret = mail_index_lookup_uid_range(view, u->uid1, u->uid2, &seq1, &seq2);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen i_assert(ret == 0);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (seq1 == 0)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return 1;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen hdr = &view->map->hdr_copy;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if ((u->add_flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen hdr->flags |= MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
bf045aa2e9c3846ecde84db303db6588b173bbaeTimo Sirainen update_keywords = FALSE;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen for (i = 0; i < INDEX_KEYWORDS_BYTE_COUNT; i++) {
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen if (u->add_keywords[i] != 0 ||
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen u->remove_keywords[i] != 0)
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen update_keywords = TRUE;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen keyword_mask[i] = ~u->remove_keywords[i];
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen flag_mask = ~u->remove_flags;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen rec = &view->map->records[seq1-1];
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen end = rec + (seq2 - seq1) + 1;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen for (; rec != end; rec++) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen old_flags = rec->flags;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen rec->flags = (rec->flags & flag_mask) | u->add_flags;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (update_keywords) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen for (i = 0; i < INDEX_KEYWORDS_BYTE_COUNT; i++) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen rec->keywords[i] = u->add_keywords[i] |
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen (rec->keywords[i] & keyword_mask[i]);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen mail_index_header_update_counts(hdr, old_flags, rec->flags);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen mail_index_header_update_lowwaters(hdr, rec);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return 1;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenstatic int sync_cache_update(const struct mail_transaction_cache_update *u,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen void *context)
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct mail_index_view *view = context;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen uint32_t seq;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen int ret;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen ret = mail_index_lookup_uid_range(view, u->uid, u->uid,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen &seq, &seq);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen i_assert(ret == 0);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen if (seq != 0)
190237ce467d2389dfb809874b0fec86d3c7968dTimo Sirainen view->map->records[seq-1].cache_offset = u->cache_offset;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return 1;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenstatic int sync_header_update(const struct mail_transaction_header_update *u,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen void *context)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen struct mail_index_view *view = context;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen void *data;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen data = PTR_OFFSET(&view->map->hdr_copy, u->offset);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen memcpy(data, u->data, u->size);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen return 1;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainenstatic int mail_index_grow(struct mail_index *index, struct mail_index_map *map,
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen unsigned int count)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen size_t size;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (MAIL_INDEX_MAP_IS_IN_MEMORY(map)) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen (void)buffer_append_space_unsafe(map->buffer,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen count * sizeof(struct mail_index_record));
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen map->records = buffer_get_modifyable_data(map->buffer, NULL);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 0;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
41bb0aa8e357876bc9a1916a37c9e3e78e5f8185Timo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen i_assert(map == index->map);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen size = map->hdr->header_size +
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen (map->records_count + count) * sizeof(struct mail_index_record);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen if (size <= map->mmap_size)
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen return 0;
8f7b00599e73fe71b1d2c6c65f8ae98aac1b23fbTimo Sirainen
8f7b00599e73fe71b1d2c6c65f8ae98aac1b23fbTimo Sirainen /* when we grow fast, do it exponentially */
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen if (count < index->last_grow_count)
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen count = index->last_grow_count;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen if (count < MAIL_INDEX_MAX_POWER_GROW)
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen count = nearest_power(count);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen index->last_grow_count = count;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen size = map->hdr->header_size +
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen (map->records_count + count) * sizeof(struct mail_index_record);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen if (file_set_size(index->fd, (off_t)size) < 0)
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen return mail_index_set_syscall_error(index, "file_set_size()");
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen if (mail_index_map(index, TRUE) <= 0)
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen return -1;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen i_assert(map->mmap_size >= size);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen return 0;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen}
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenint mail_index_sync_update_index(struct mail_index_sync_ctx *sync_ctx)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct mail_index *index = sync_ctx->index;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct mail_index_view *view = sync_ctx->view;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct mail_index_map *map;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const struct mail_transaction_header *hdr;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const void *data;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen unsigned int lock_id, count;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen uint32_t seq, i;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen uoff_t offset;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen int ret, had_dirty, skipped;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen if (mail_index_lock_exclusive(index, &lock_id) < 0)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return -1;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen /* NOTE: locking may change index->map so make sure assignment
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen after locking */
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen map = index->map;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen if (MAIL_INDEX_MAP_IS_IN_MEMORY(map))
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen map->write_to_disk = TRUE;
9887c39c5ba429169389153ca99de49e084a73f0Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen map->hdr_copy = *map->hdr;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen map->hdr = &map->hdr_copy;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen mail_index_unmap(index, view->map);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen view->map = map;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen view->map->refcount++;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen had_dirty = (map->hdr_copy.flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) != 0;
9887c39c5ba429169389153ca99de49e084a73f0Timo Sirainen if (had_dirty)
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen map->hdr_copy.flags &= ~MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen while ((ret = mail_transaction_log_view_next(view->log_view, &hdr,
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen &data, &skipped)) > 0) {
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXPUNGE) != 0 &&
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen !map->write_to_disk) {
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen /* expunges have to be atomic. so we'll have to copy
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen the mapping, do the changes there and then finally
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen replace the whole index file. to avoid extra disk
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen I/O we copy the index into memory rather than to
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen temporary file */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen map = mail_index_map_to_memory(map);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen mail_index_unmap(index, view->map);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen view->map = map;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen view->map->refcount++;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen mail_index_unmap(index, index->map);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen index->map = map;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen index->hdr = map->hdr;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen map->write_to_disk = TRUE;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen if ((hdr->type & MAIL_TRANSACTION_APPEND) != 0) {
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen count = hdr->size / sizeof(struct mail_index_record);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen if (mail_index_grow(index, view->map, count) < 0)
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen return -1;
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen }
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen
190237ce467d2389dfb809874b0fec86d3c7968dTimo Sirainen if (mail_transaction_map(hdr, data, &mail_index_map_sync_funcs,
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen view) < 0) {
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen ret = -1;
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen break;
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen }
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen if (ret < 0)
9887c39c5ba429169389153ca99de49e084a73f0Timo Sirainen return -1;
9887c39c5ba429169389153ca99de49e084a73f0Timo Sirainen
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen mail_transaction_log_get_head(index->log, &seq, &offset);
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen map->hdr_copy.log_file_seq = seq;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen map->hdr_copy.log_file_offset = offset;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if ((map->hdr_copy.flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) == 0 &&
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen had_dirty) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* do we have dirty flags anymore? */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen for (i = 0; i < map->records_count; i++) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if ((map->records[i].flags &
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen map->hdr_copy.flags |=
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen break;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen }
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen }
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen }
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen if (!MAIL_INDEX_MAP_IS_IN_MEMORY(map)) {
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen map->mmap_used_size = index->hdr->header_size +
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen map->records_count * sizeof(struct mail_index_record);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen memcpy(map->mmap_base, &map->hdr_copy, sizeof(map->hdr_copy));
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen if (msync(map->mmap_base, map->mmap_used_size, MS_SYNC) < 0) {
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen mail_index_set_syscall_error(index, "msync()");
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen ret = -1;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen }
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen map->hdr = map->mmap_base;
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen }
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen mail_index_unlock(index, lock_id);
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen return ret;
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen}
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainenstruct mail_transaction_map_functions mail_index_map_sync_funcs = {
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen sync_expunge, sync_append, sync_flag_update,
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen sync_cache_update, sync_header_update
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen};
faed8babca9914257f34fb2e603d74016d563b2dTimo Sirainen