mail-index-sync-update.c revision d12f05c7c391786d0d9795ec3aa4377280bbfaea
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield/* Copyright (C) 2004 Timo Sirainen */
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield#include "mail-transaction-log-private.h"
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield/* If we have less than this many bytes to sync from log file, don't bother
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield reading the main index */
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield#define MAIL_INDEX_SYNC_MIN_READ_INDEX_SIZE 2048
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfieldmail_index_sync_update_log_offset(struct mail_index_sync_map_ctx *ctx,
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield mail_transaction_log_view_get_prev_pos(ctx->view->log_view,
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if (prev_offset == ctx->ext_intro_end_offset &&
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield /* previous transaction was an extension introduction.
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield we probably came here from
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield mail_index_sync_ext_reset(). if there are any more
826cde7c2100e1f4419a54b5c930c0854e01e87eMichael H. Warfield views which want to continue syncing it needs the
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield intro. so back up a bit more.
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield don't do this in case the last transaction in the
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield log is the extension intro, so we don't keep trying
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield to sync it over and over again. */
ec64264d78d4ed608553842ce9e1f07eeab2a032Veres Lajos i_assert(ctx->view->index->log->head->hdr.file_seq == prev_seq);
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield map->hdr.log_file_head_offset = prev_offset;
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfieldstatic void mail_index_sync_replace_map(struct mail_index_sync_map_ctx *ctx,
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield struct mail_index_view *view = ctx->view;
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield mail_index_sync_update_log_offset(ctx, view->map, FALSE);
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield if (ctx->type != MAIL_INDEX_SYNC_HANDLER_VIEW)
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfieldvoid mail_index_sync_move_to_private(struct mail_index_sync_map_ctx *ctx)
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield struct mail_index_map *map = ctx->view->map;
826cde7c2100e1f4419a54b5c930c0854e01e87eMichael H. Warfield i_assert(MAIL_INDEX_MAP_IS_IN_MEMORY(map) ||
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfieldmail_index_sync_move_to_private_memory(struct mail_index_sync_map_ctx *ctx)
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if (!MAIL_INDEX_MAP_IS_IN_MEMORY(ctx->view->map))
8ec981fc8b0105da5f071e40811e0c2472a6c3c9Stéphane Graber mail_index_map_move_to_memory(ctx->view->map);
8ec981fc8b0105da5f071e40811e0c2472a6c3c9Stéphane Grabermail_index_sync_get_atomic_map(struct mail_index_sync_map_ctx *ctx)
8ec981fc8b0105da5f071e40811e0c2472a6c3c9Stéphane Graber mail_index_sync_move_to_private_memory(ctx);
207bf0e475f1dc6e9a2dac2cee3a209b56427855Stéphane Grabermail_index_header_update_counts(struct mail_index_header *hdr,
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if (((old_flags ^ new_flags) & MAIL_SEEN) != 0) {
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield /* different seen-flag */
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if (hdr->seen_messages_count >= hdr->messages_count) {
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if (++hdr->seen_messages_count == hdr->messages_count)
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield hdr->first_unseen_uid_lowwater = hdr->next_uid;
c6df5ca4603c630a7189cdb1653c96bd2808c7e5Michael H. Warfield if (((old_flags ^ new_flags) & MAIL_DELETED) != 0) {
c6df5ca4603c630a7189cdb1653c96bd2808c7e5Michael H. Warfield /* different deleted-flag */
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if (hdr->deleted_messages_count > hdr->messages_count) {
c6df5ca4603c630a7189cdb1653c96bd2808c7e5Michael H. Warfield hdr->deleted_messages_count > hdr->messages_count) {
c6df5ca4603c630a7189cdb1653c96bd2808c7e5Michael H. Warfield hdr->first_deleted_uid_lowwater = hdr->next_uid;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfieldmail_index_sync_header_update_counts_all(struct mail_index_sync_map_ctx *ctx,
c6df5ca4603c630a7189cdb1653c96bd2808c7e5Michael H. Warfield unsigned int i, count;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield maps = array_get(&ctx->view->map->rec_map->maps, &count);
c6df5ca4603c630a7189cdb1653c96bd2808c7e5Michael H. Warfield for (i = 0; i < count; i++) {
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if (mail_index_header_update_counts(&maps[i]->hdr,
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield mail_index_sync_set_corrupted(ctx, "%s", error);
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfieldmail_index_sync_header_update_counts(struct mail_index_sync_map_ctx *ctx,
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield mail_index_sync_header_update_counts_all(ctx, old_flags,
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if (mail_index_header_update_counts(&ctx->view->map->hdr,
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield mail_index_sync_set_corrupted(ctx, "%s", error);
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfieldmail_index_header_update_lowwaters(struct mail_index_sync_map_ctx *ctx,
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield unsigned int i, count;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield maps = array_get(&ctx->view->map->rec_map->maps, &count);
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield for (i = 0; i < count; i++) {
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield rec->uid < maps[i]->hdr.first_unseen_uid_lowwater)
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield maps[i]->hdr.first_unseen_uid_lowwater = rec->uid;
c6df5ca4603c630a7189cdb1653c96bd2808c7e5Michael H. Warfield rec->uid < maps[i]->hdr.first_deleted_uid_lowwater)
c6df5ca4603c630a7189cdb1653c96bd2808c7e5Michael H. Warfield maps[i]->hdr.first_deleted_uid_lowwater = rec->uid;
c6df5ca4603c630a7189cdb1653c96bd2808c7e5Michael H. Warfieldsync_expunge_call_handlers(struct mail_index_sync_map_ctx *ctx,
c6df5ca4603c630a7189cdb1653c96bd2808c7e5Michael H. Warfield const struct mail_index_expunge_handler *eh;
c6df5ca4603c630a7189cdb1653c96bd2808c7e5Michael H. Warfield unsigned int i, count;
c6df5ca4603c630a7189cdb1653c96bd2808c7e5Michael H. Warfield /* call expunge handlers only when syncing index file */
c6df5ca4603c630a7189cdb1653c96bd2808c7e5Michael H. Warfield if (ctx->type != MAIL_INDEX_SYNC_HANDLER_FILE)
c6df5ca4603c630a7189cdb1653c96bd2808c7e5Michael H. Warfield mail_index_sync_init_expunge_handlers(ctx);
c6df5ca4603c630a7189cdb1653c96bd2808c7e5Michael H. Warfield if (!array_is_created(&ctx->expunge_handlers))
c6df5ca4603c630a7189cdb1653c96bd2808c7e5Michael H. Warfield eh = array_get(&ctx->expunge_handlers, &count);
f5067ecbcc1e97052c33269b4afa6375073a91a1Michael H. Warfield rec = MAIL_INDEX_MAP_IDX(ctx->view->map, seq1-1);
99c2fb07d74c20d0eec38c05c4ac64e5782d8e7dMichael H. Warfieldsync_expunge(const struct mail_transaction_expunge *e, unsigned int count,
99c2fb07d74c20d0eec38c05c4ac64e5782d8e7dMichael H. Warfield struct mail_index_map *map = ctx->view->map;
99c2fb07d74c20d0eec38c05c4ac64e5782d8e7dMichael H. Warfield unsigned int i;
99c2fb07d74c20d0eec38c05c4ac64e5782d8e7dMichael H. Warfield for (i = 0; i < count; i++, e++) {
99c2fb07d74c20d0eec38c05c4ac64e5782d8e7dMichael H. Warfield if (mail_index_lookup_uid_range(ctx->view, e->uid1, e->uid2,
99c2fb07d74c20d0eec38c05c4ac64e5782d8e7dMichael H. Warfield /* everything expunged already */
99c2fb07d74c20d0eec38c05c4ac64e5782d8e7dMichael H. Warfield map = mail_index_sync_get_atomic_map(ctx);
99c2fb07d74c20d0eec38c05c4ac64e5782d8e7dMichael H. Warfield mail_index_sync_header_update_counts(ctx,
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if (sync_expunge_call_handlers(ctx, seq1, seq2) < 0)
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield memmove(MAIL_INDEX_MAP_IDX(map, seq1-1),
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield map->rec_map->records_count -= seq_count;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfieldvoid mail_index_sync_write_seq_update(struct mail_index_sync_map_ctx *ctx,
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield struct mail_index_map *map = ctx->view->map;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if (map->rec_map->write_seq_first == 0 ||
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if (map->rec_map->write_seq_last < seq2)
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfieldstatic int sync_append(const struct mail_index_record *rec,
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield struct mail_index_view *view = ctx->view;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield "Append with UID %u, but next_uid = %u",
a79df22733c48898aaeb600cc073278236d4b489Stéphane Graber /* move to memory. the mapping is written when unlocking so we don't
a79df22733c48898aaeb600cc073278236d4b489Stéphane Graber waste time re-mmap()ing multiple times or waste space growing index
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield file too large */
a79df22733c48898aaeb600cc073278236d4b489Stéphane Graber mail_index_sync_move_to_private_memory(ctx);
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield /* don't rely on buffer->used being at the correct position.
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield at least expunges can move it */
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield append_pos = map->rec_map->records_count * map->hdr.record_size;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield dest = buffer_get_space_unsafe(map->rec_map->buffer, append_pos,
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield buffer_get_modifiable_data(map->rec_map->buffer, NULL);
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield memset(PTR_OFFSET(dest, sizeof(*rec)), 0,
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield mail_index_sync_write_seq_update(ctx, map->hdr.messages_count,
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if ((rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0)
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield map->hdr.flags |= MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield mail_index_header_update_lowwaters(ctx, rec);
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield mail_index_sync_header_update_counts(ctx, 0, rec->flags, FALSE);
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfieldstatic int sync_flag_update(const struct mail_transaction_flag_update *u,
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield struct mail_index_view *view = ctx->view;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if (mail_index_lookup_uid_range(view, u->uid1, u->uid2,
1ecee40b7dcb933d2c9910f07ed26c6a55e18206Michael H. Warfield mail_index_sync_write_seq_update(ctx, seq1, seq2);
1ecee40b7dcb933d2c9910f07ed26c6a55e18206Michael H. Warfield if ((u->add_flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0)
1ecee40b7dcb933d2c9910f07ed26c6a55e18206Michael H. Warfield view->map->hdr.flags |= MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
1ecee40b7dcb933d2c9910f07ed26c6a55e18206Michael H. Warfield /* we're not modifying any counted/lowwatered flags */
7edae51efcb3cb3a05e7fe850905dc836d120512Claudio Alarcon-Reyes rec = MAIL_INDEX_MAP_IDX(view->map, idx);
7edae51efcb3cb3a05e7fe850905dc836d120512Claudio Alarcon-Reyes rec->flags = (rec->flags & flag_mask) | u->add_flags;
7edae51efcb3cb3a05e7fe850905dc836d120512Claudio Alarcon-Reyes for (idx = seq1-1; idx < seq2; idx++) {
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield rec = MAIL_INDEX_MAP_IDX(view->map, idx);
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield rec->flags = (rec->flags & flag_mask) | u->add_flags;
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield mail_index_header_update_lowwaters(ctx, rec);
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield mail_index_sync_header_update_counts(ctx, old_flags,
826cde7c2100e1f4419a54b5c930c0854e01e87eMichael H. Warfieldstatic int sync_header_update(const struct mail_transaction_header_update *u,
826cde7c2100e1f4419a54b5c930c0854e01e87eMichael H. Warfield struct mail_index_map *map = ctx->view->map;
826cde7c2100e1f4419a54b5c930c0854e01e87eMichael H. Warfield uint32_t orig_log_file_tail_offset = map->hdr.log_file_tail_offset;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if (u->offset >= map->hdr.base_header_size ||
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield u->offset + u->size > map->hdr.base_header_size) {
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield "Header update outside range: %u + %u > %u",
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield u->offset, u->size, map->hdr.base_header_size);
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield buffer_write(map->hdr_copy_buf, u->offset, u + 1, u->size);
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield map->hdr_base = map->hdr_copy_buf->data;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if ((uint32_t)(u->offset + u->size) <= sizeof(map->hdr)) {
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield memcpy(PTR_OFFSET(&map->hdr, u->offset),
779b47fdca6975f70541fbc7c25a34393ec5c24bMichael H. Warfield } else if (u->offset < sizeof(map->hdr)) {
779b47fdca6975f70541fbc7c25a34393ec5c24bMichael H. Warfield memcpy(PTR_OFFSET(&map->hdr, u->offset),
779b47fdca6975f70541fbc7c25a34393ec5c24bMichael H. Warfield /* the tail offset updates are intended for internal transaction
779b47fdca6975f70541fbc7c25a34393ec5c24bMichael H. Warfield log handling. we'll update the offset in the header only when
779b47fdca6975f70541fbc7c25a34393ec5c24bMichael H. Warfield the sync is finished. */
779b47fdca6975f70541fbc7c25a34393ec5c24bMichael H. Warfield map->hdr.log_file_tail_offset = orig_log_file_tail_offset;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfieldint mail_index_sync_record(struct mail_index_sync_map_ctx *ctx,
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield const struct mail_transaction_header *hdr,
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield const struct mail_index_record *rec, *end;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield end = CONST_PTR_OFFSET(data, hdr->size);
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield case MAIL_TRANSACTION_EXPUNGE|MAIL_TRANSACTION_EXPUNGE_PROT: {
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield const struct mail_transaction_expunge *rec = data, *end;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) {
3a6ef65aa29206b2f2061fdb020c32118f6d74f2Harald Dunkel /* this is simply a request for expunge */
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield const struct mail_transaction_flag_update *rec, *end;
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield end = CONST_PTR_OFFSET(data, hdr->size);
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield const struct mail_transaction_header_update *rec;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield unsigned int i;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if ((i % 4) != 0)
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield const struct mail_transaction_ext_intro *rec = data;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield unsigned int i;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield mail_transaction_log_view_get_prev_pos(ctx->view->log_view,
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield /* should be just extra padding */
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if (i + sizeof(*rec) + rec->name_size > hdr->size) {
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield "ext intro: name_size too large");
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield ret = mail_index_sync_ext_intro(ctx, rec);
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if ((i % 4) != 0)
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield const struct mail_transaction_ext_reset *rec = data;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield "ext reset: invalid record size");
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield ret = mail_index_sync_ext_reset(ctx, rec);
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield const struct mail_transaction_ext_hdr_update *rec = data;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield unsigned int i;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield i + sizeof(*rec) + rec->size > hdr->size) {
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield "ext hdr update: invalid record size");
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield ret = mail_index_sync_ext_hdr_update(ctx, rec);
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if ((i % 4) != 0)
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield const struct mail_transaction_ext_rec_update *rec;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield unsigned int i, record_size;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield "Extension record updated "
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield "without intro prefix");
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield ext = array_idx(&ctx->view->map->extensions, ctx->cur_ext_id);
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield /* the record is padded to 32bits in the transaction log */
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield record_size = (sizeof(*rec) + ext->record_size + 3) & ~3;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield for (i = 0; i < hdr->size; i += record_size) {
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield "ext rec update: invalid record size");
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield ret = mail_index_sync_ext_rec_update(ctx, rec);
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield const struct mail_transaction_keyword_update *rec = data;
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield ret = mail_index_sync_keywords(ctx, hdr, rec);
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield const struct mail_transaction_keyword_reset *rec = data;
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield ret = mail_index_sync_keywords_reset(ctx, hdr, rec);
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield i_assert(ctx->view->map->rec_map->records_count ==
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfieldvoid mail_index_sync_map_init(struct mail_index_sync_map_ctx *sync_map_ctx,
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield memset(sync_map_ctx, 0, sizeof(*sync_map_ctx));
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield sync_map_ctx->cur_ext_id = (uint32_t)-1;
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield /* make sure we re-read it in case it has changed */
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield sync_map_ctx->view->map->keywords_read = FALSE;
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield mail_index_sync_init_handlers(sync_map_ctx);
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfieldvoid mail_index_sync_map_deinit(struct mail_index_sync_map_ctx *sync_map_ctx)
1ecee40b7dcb933d2c9910f07ed26c6a55e18206Michael H. Warfield if (sync_map_ctx->expunge_handlers_used)
1ecee40b7dcb933d2c9910f07ed26c6a55e18206Michael H. Warfield mail_index_sync_deinit_expunge_handlers(sync_map_ctx);
1ecee40b7dcb933d2c9910f07ed26c6a55e18206Michael H. Warfield mail_index_sync_deinit_handlers(sync_map_ctx);
1ecee40b7dcb933d2c9910f07ed26c6a55e18206Michael H. Warfieldstatic void mail_index_sync_update_hdr_dirty_flag(struct mail_index_map *map)
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield unsigned int i;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if ((map->hdr.flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) != 0)
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield /* do we have dirty flags anymore? */
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield for (i = 0; i < map->rec_map->records_count; i++) {
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if ((rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield map->hdr.flags |= MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfieldvoid mail_index_map_check(struct mail_index_map *map)
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield const struct mail_index_header *hdr = &map->hdr;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield i_assert(hdr->messages_count <= map->rec_map->records_count);
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield for (i = 0; i < hdr->messages_count; i++) {
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield i_assert(rec->uid >= hdr->first_deleted_uid_lowwater);
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield i_assert(rec->uid >= hdr->first_unseen_uid_lowwater);
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield i_assert(del == hdr->deleted_messages_count);
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield i_assert(seen == hdr->seen_messages_count);
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfieldint mail_index_sync_map(struct mail_index_map **_map,
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield enum mail_index_sync_handler_type type, bool force)
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield struct mail_index_sync_map_ctx sync_map_ctx;
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield const struct mail_transaction_header *thdr;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield i_assert(index->map == map || type == MAIL_INDEX_SYNC_HANDLER_VIEW);
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield /* see if we'd prefer to reopen the index file instead of
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield syncing the current map from the transaction log */
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield index->log->head->hdr.prev_file_seq != 0) {
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield /* we don't know the index's size, so use the
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield smallest index size we're willing to read */
3a6ef65aa29206b2f2061fdb020c32118f6d74f2Harald Dunkel index_size = MAIL_INDEX_SYNC_MIN_READ_INDEX_SIZE;
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield /* this isn't necessary correct currently, but it should be
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield close enough */
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if (log_size > map->hdr.log_file_tail_offset &&
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield log_size - map->hdr.log_file_tail_offset > index_size)
6976826fed04d006608f87ba902a8517358c15ecMichael Adam start_offset = type == MAIL_INDEX_SYNC_HANDLER_FILE ?
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield map->hdr.log_file_tail_offset : map->hdr.log_file_head_offset;
2ae8252a4f046a8839a70da6a2271e20e8216b99Michael Adam view = mail_index_view_open_with_map(index, map);
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield ret = mail_transaction_log_view_set(view->log_view,
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield /* the seq/offset is probably broken */
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield /* can't use it. sync by re-reading index. */
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield /* view referenced the map. avoid unnecessary map cloning by
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield unreferencing the map while view exists. */
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield had_dirty = (map->hdr.flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) != 0;
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield map->hdr.flags &= ~MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield if (map->hdr_base != map->hdr_copy_buf->data) {
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield /* if syncing updates the header, it updates hdr_copy_buf
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield and updates hdr_base to hdr_copy_buf. so the buffer must
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield initially contain a valid header or we'll break it when
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield writing it. */
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield buffer_append(map->hdr_copy_buf, map->hdr_base,
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield map->hdr_base = map->hdr_copy_buf->data;
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield mail_index_sync_map_init(&sync_map_ctx, view, type);
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield /* Reset the entire index. Leave only indexid and
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield log_file_seq. */
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield mail_transaction_log_view_get_prev_pos(view->log_view,
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield mail_index_sync_replace_map(&sync_map_ctx, map);
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield /* FIXME: when transaction sync lock is removed, we'll need to handle
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield the case when a transaction is committed while mailbox is being
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield synced ([synced transactions][new transaction][ext transaction]).
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield this means int_offset contains [synced] and ext_offset contains
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield while ((ret = mail_transaction_log_view_next(view->log_view, &thdr,
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield mail_transaction_log_view_get_prev_pos(view->log_view,
08754f305b580801ae800df32ace5dc7b9b191d9Michael H. Warfield if (LOG_IS_BEFORE(prev_seq, prev_offset,
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield /* this has been synced already. we're here only to call
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield expunge handlers and extension update handlers. */
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield i_assert(type == MAIL_INDEX_SYNC_HANDLER_FILE);
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield if ((thdr->type & MAIL_TRANSACTION_EXTERNAL) != 0)
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield if ((thdr->type & MAIL_TRANSACTION_EXT_MASK) == 0)
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield /* we'll just skip over broken entries */
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield (void)mail_index_sync_record(&sync_map_ctx, thdr, tdata);
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield mail_index_sync_update_hdr_dirty_flag(map);
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield mail_index_sync_update_log_offset(&sync_map_ctx, view->map, TRUE);
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield i_assert(map->hdr.indexid == index->indexid);
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield /* transaction log tracks internally the current tail offset.
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield besides using header updates, it also updates the offset to skip
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield over following external transactions to avoid extra unneeded log
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield map->hdr.log_file_tail_offset = index->log->head->max_tail_offset;
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield buffer_write(map->hdr_copy_buf, 0, &map->hdr, sizeof(map->hdr));
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if (!MAIL_INDEX_MAP_IS_IN_MEMORY(map)) {
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield memcpy(map->rec_map->mmap_base, map->hdr_copy_buf->data,
b4f7af7a520b23c873e404562ec518a576e63d4cMichael H. Warfield /* avoid the same syncing errors the next time */
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield /* restore refcount before closing the view. this is necessary also
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield if map got cloned, because view closing would otherwise destroy it */
164105f6563d98b832f603e28e506dbabed22cf3Michael H. Warfield mail_index_sync_map_deinit(&sync_map_ctx);