mail-index-sync-update.c revision 3a78329166819e06f2929ce44e360514c6a80a8e
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen/* Copyright (c) 2004-2017 Dovecot authors, see the included COPYING file */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen/* If we have less than this many bytes to sync from log file, don't bother
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen reading the main index */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen#define MAIL_INDEX_SYNC_MIN_READ_INDEX_SIZE 2048
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenmail_index_sync_update_log_offset(struct mail_index_sync_map_ctx *ctx,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_transaction_log_view_get_prev_pos(ctx->view->log_view,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* handling lost changes in view syncing */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (prev_offset == ctx->ext_intro_end_offset &&
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* previous transaction was an extension introduction.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen we probably came here from
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_sync_ext_reset(). if there are any more
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen views which want to continue syncing it needs the
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen intro. so back up a bit more.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen don't do this in case the last transaction in the
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen log is the extension intro, so we don't keep trying
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen to sync it over and over again. */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen i_assert(ctx->view->index->log->head->hdr.file_seq == prev_seq);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenstatic void mail_index_sync_replace_map(struct mail_index_sync_map_ctx *ctx,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_sync_update_log_offset(ctx, view->map, FALSE);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (ctx->type != MAIL_INDEX_SYNC_HANDLER_VIEW)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_modseq_sync_map_replaced(ctx->modseq_ctx);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenmail_index_sync_move_to_private_memory(struct mail_index_sync_map_ctx *ctx)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (!MAIL_INDEX_MAP_IS_IN_MEMORY(ctx->view->map))
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_map_move_to_memory(ctx->view->map);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_modseq_sync_map_replaced(ctx->modseq_ctx);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenmail_index_sync_get_atomic_map(struct mail_index_sync_map_ctx *ctx)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen (void)mail_index_sync_move_to_private_memory(ctx);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_record_map_move_to_private(ctx->view->map);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_modseq_sync_map_replaced(ctx->modseq_ctx);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenmail_index_header_update_counts(struct mail_index_header *hdr,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen const char **error_r)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (((old_flags ^ new_flags) & MAIL_SEEN) != 0) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* different seen-flag */
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen if (hdr->seen_messages_count >= hdr->messages_count) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (++hdr->seen_messages_count == hdr->messages_count)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen hdr->first_unseen_uid_lowwater = hdr->next_uid;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (((old_flags ^ new_flags) & MAIL_DELETED) != 0) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* different deleted-flag */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (hdr->deleted_messages_count > hdr->messages_count) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen hdr->deleted_messages_count > hdr->messages_count) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen hdr->first_deleted_uid_lowwater = hdr->next_uid;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenmail_index_sync_header_update_counts_all(struct mail_index_sync_map_ctx *ctx,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen unsigned int i, count;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen maps = array_get(&ctx->view->map->rec_map->maps, &count);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen for (i = 0; i < count; i++) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (mail_index_header_update_counts(&maps[i]->hdr,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_sync_set_corrupted(ctx, "%s", error);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenmail_index_sync_header_update_counts(struct mail_index_sync_map_ctx *ctx,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_sync_set_corrupted(ctx, "uid %u >= next_uid %u",
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (mail_index_header_update_counts(&ctx->view->map->hdr,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_sync_set_corrupted(ctx, "%s", error);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenmail_index_header_update_lowwaters(struct mail_index_sync_map_ctx *ctx,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen unsigned int i, count;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen maps = array_get(&ctx->view->map->rec_map->maps, &count);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen for (i = 0; i < count; i++) {
2498b8003eb181001b0c4fd45763c462b45493d1Timo Sirainen uid < maps[i]->hdr.first_deleted_uid_lowwater)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen maps[i]->hdr.first_deleted_uid_lowwater = uid;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainensync_expunge_call_handlers(struct mail_index_sync_map_ctx *ctx,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen rec = MAIL_INDEX_REC_AT_SEQ(ctx->view->map, seq);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* FIXME: does expunge handler's return value matter?
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen we probably shouldn't disallow expunges if the
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen handler returns failure.. should it be just changed
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen to return void? */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainensync_expunge_handlers_init(struct mail_index_sync_map_ctx *ctx)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* call expunge handlers only when syncing index file */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (ctx->type != MAIL_INDEX_SYNC_HANDLER_FILE)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (!array_is_created(&ctx->expunge_handlers))
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainensync_expunge_range(struct mail_index_sync_map_ctx *ctx, const ARRAY_TYPE(seq_range) *seqs)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen unsigned int i, count;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen uint32_t dest_seq1, prev_seq2, orig_rec_count;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* call the expunge handlers first */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen for (i = 0; i < count; i++) {
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen for (i = 0; i < count; i++) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_sync_header_update_counts(ctx, rec->uid, rec->flags, 0);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* @UNSAFE: move (prev_seq2+1) .. (seq1-1) to its
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen final location in the map if necessary */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen uint32_t move_count = (seq1-1) - (prev_seq2+1) + 1;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen memmove(MAIL_INDEX_REC_AT_SEQ(map, dest_seq1),
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_modseq_expunge(ctx->modseq_ctx, seq1, seq2);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* Final stragglers */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen uint32_t final_move_count = orig_rec_count - prev_seq2;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen memmove(MAIL_INDEX_REC_AT_SEQ(map, dest_seq1),
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenstatic void *sync_append_record(struct mail_index_map *map)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen append_pos = map->rec_map->records_count * map->hdr.record_size;
1d3f7c1278168d5b1cbfa9a2cc9929a0909056b4Timo Sirainen ret = buffer_get_space_unsafe(map->rec_map->buffer, append_pos,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen buffer_get_modifiable_data(map->rec_map->buffer, NULL);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenstatic bool sync_update_ignored_change(struct mail_index_sync_map_ctx *ctx)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen struct mail_index_transaction_commit_result *result =
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen uoff_t prev_log_offset, trans_start_offset, trans_end_offset;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* we'll return TRUE if this modseq change was written within the
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen transaction that was just committed */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_transaction_log_view_get_prev_pos(ctx->view->log_view,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen trans_start_offset = trans_end_offset - result->commit_size;
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainensync_modseq_update(struct mail_index_sync_map_ctx *ctx,
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen const struct mail_transaction_modseq_update *u,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen unsigned int size)
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen const struct mail_transaction_modseq_update *end;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen for (; u < end; u++) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (u->uid == 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen else if (!mail_index_lookup_seq(view, u->uid, &seq))
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen min_modseq = ((uint64_t)u->modseq_high32 << 32) |
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen "modseqs updated before they were enabled");
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if (ret == 0 && sync_update_ignored_change(ctx))
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen view->index->sync_commit_result->ignored_modseq_changes++;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenstatic int sync_append(const struct mail_index_record *rec,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen "Append with UID %u, but next_uid = %u",
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen /* move to memory. the mapping is written when unlocking so we don't
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen waste time re-mmap()ing multiple times or waste space growing index
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen file too large */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen map = mail_index_sync_move_to_private_memory(ctx);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (rec->uid <= map->rec_map->last_appended_uid) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen i_assert(map->hdr.messages_count < map->rec_map->records_count);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* the flags may have changed since it was added to map.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen use the updated flags already, so flag counters won't get
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen old_rec = MAIL_INDEX_MAP_IDX(map, map->hdr.messages_count);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen /* don't rely on buffer->used being at the correct position.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen at least expunges can move it */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if ((new_flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0 &&
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen (view->index->flags & MAIL_INDEX_OPEN_FLAG_NO_DIRTY) == 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen map->hdr.flags |= MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_header_update_lowwaters(ctx, rec->uid, new_flags);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_sync_header_update_counts(ctx, rec->uid, 0, new_flags);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic int sync_flag_update(const struct mail_transaction_flag_update *u,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (!mail_index_lookup_seq_range(view, u->uid1, u->uid2, &seq1, &seq2))
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (!MAIL_TRANSACTION_FLAG_UPDATE_IS_INTERNAL(u)) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_modseq_update_flags(ctx->modseq_ctx,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if ((u->add_flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0 &&
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen (view->index->flags & MAIL_INDEX_OPEN_FLAG_NO_DIRTY) == 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen view->map->hdr.flags |= MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* we're not modifying any counted/lowwatered flags */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen rec->flags = (rec->flags & flag_mask) | u->add_flags;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen rec->flags = (rec->flags & flag_mask) | u->add_flags;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_header_update_lowwaters(ctx, rec->uid,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_index_sync_header_update_counts_all(ctx, rec->uid,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenstatic int sync_header_update(const struct mail_transaction_header_update *u,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen#define MAIL_INDEX_HEADER_UPDATE_FIELD_IN_RANGE(u, field) \
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen ((u)->offset <= offsetof(struct mail_index_header, field) && \
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen (u)->offset + (u)->size > offsetof(struct mail_index_header, field))
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen uint32_t orig_log_file_tail_offset = map->hdr.log_file_tail_offset;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen u->offset + u->size > map->hdr.base_header_size) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen "Header update outside range: %u + %u > %u",
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen u->offset, u->size, map->hdr.base_header_size);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen buffer_write(map->hdr_copy_buf, u->offset, u + 1, u->size);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen i_assert(map->hdr_copy_buf->used == map->hdr.header_size);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen /* @UNSAFE */
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if ((uint32_t)(u->offset + u->size) <= sizeof(map->hdr)) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* next_uid update tried to shrink its value. this can happen
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen in some race conditions with e.g. with dsync, so just
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen silently ignore it. */
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen /* the tail offset updates are intended for internal transaction
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen log handling. we'll update the offset in the header only when
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen the sync is finished. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen map->hdr.log_file_tail_offset = orig_log_file_tail_offset;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainenmail_index_sync_record_real(struct mail_index_sync_map_ctx *ctx,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen case MAIL_TRANSACTION_EXPUNGE|MAIL_TRANSACTION_EXPUNGE_PROT: {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen const struct mail_transaction_expunge *rec = data, *end;
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* this is simply a request for expunge */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen case MAIL_TRANSACTION_EXPUNGE_GUID|MAIL_TRANSACTION_EXPUNGE_PROT: {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen const struct mail_transaction_expunge_guid *rec = data, *end;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) {
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen /* this is simply a request for expunge */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (mail_index_lookup_seq(ctx->view, rec->uid, &seq))
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen const struct mail_transaction_flag_update *rec, *end;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen const struct mail_transaction_header_update *rec;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen unsigned int i;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if ((i % 4) != 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen const struct mail_transaction_ext_intro *rec = data;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen unsigned int i;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_transaction_log_view_get_prev_pos(ctx->view->log_view,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* should be just extra padding */
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen /* name_size checked by _log_view_next() */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_assert(i + sizeof(*rec) + rec->name_size <= hdr->size);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if ((i % 4) != 0)
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* old versions have only new_reset_id */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "ext reset: invalid record size");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen memcpy(&rec, data, I_MIN(hdr->size, sizeof(rec)));
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen const struct mail_transaction_ext_hdr_update *rec;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen unsigned int i;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "ext hdr update: invalid record size");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = mail_index_sync_ext_hdr_update(ctx, rec->offset,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if ((i % 4) != 0)
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen const struct mail_transaction_ext_hdr_update32 *rec;
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen unsigned int i;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "ext hdr update: invalid record size");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = mail_index_sync_ext_hdr_update(ctx, rec->offset,
8e57335924f5ff57cbd1929ec99764dc267c3312Timo Sirainen if ((i % 4) != 0)
8e57335924f5ff57cbd1929ec99764dc267c3312Timo Sirainen const struct mail_transaction_ext_rec_update *rec;
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen unsigned int i, record_size;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen "Extension record updated "
5c7aa03f959b8b9cab3eba8a585a90f4b50a4cdfTimo Sirainen "without intro prefix");
5c7aa03f959b8b9cab3eba8a585a90f4b50a4cdfTimo Sirainen /* the record is padded to 32bits in the transaction log */
5c7aa03f959b8b9cab3eba8a585a90f4b50a4cdfTimo Sirainen record_size = (sizeof(*rec) + ctx->cur_ext_record_size + 3) & ~3;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen for (i = 0; i < hdr->size; i += record_size) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "ext rec update: invalid record size");
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ret = mail_index_sync_ext_rec_update(ctx, rec);
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen const struct mail_transaction_ext_atomic_inc *rec, *end;
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen "Extension record updated "
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen "without intro prefix");
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen ret = mail_index_sync_ext_atomic_inc(ctx, rec);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen const struct mail_transaction_keyword_update *rec = data;
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen ret = mail_index_sync_keywords(ctx, hdr, rec);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen const struct mail_transaction_keyword_reset *rec = data;
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen ret = mail_index_sync_keywords_reset(ctx, hdr, rec);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen const struct mail_transaction_modseq_update *rec = data;
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen ret = sync_modseq_update(ctx, rec, hdr->size);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) {
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen /* next sync finishes the deletion */
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen ctx->view->index->index_delete_requested = TRUE;
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen /* transaction log reading handles this */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ctx->view->index->index_delete_requested = FALSE;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen "Unknown transaction record type 0x%x",
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainenint mail_index_sync_record(struct mail_index_sync_map_ctx *ctx,
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen ret = mail_index_sync_record_real(ctx, hdr, data);
bf91bed88d4e294b4577ba2a3b14d87cf35ae135Timo Sirainenvoid mail_index_sync_map_init(struct mail_index_sync_map_ctx *sync_map_ctx,
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen sync_map_ctx->modseq_ctx = mail_index_modseq_sync_begin(sync_map_ctx);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainenvoid mail_index_sync_map_deinit(struct mail_index_sync_map_ctx *sync_map_ctx)
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen buffer_free(&sync_map_ctx->unknown_extensions);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen mail_index_sync_deinit_expunge_handlers(sync_map_ctx);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen mail_index_sync_deinit_handlers(sync_map_ctx);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainenstatic void mail_index_sync_update_hdr_dirty_flag(struct mail_index_map *map)
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if ((map->hdr.flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) != 0 ||
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen (map->index->flags & MAIL_INDEX_OPEN_FLAG_NO_DIRTY) != 0)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* do we have dirty flags anymore? */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen for (seq = 1; seq <= map->rec_map->records_count; seq++) {
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen if ((rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen map->hdr.flags |= MAIL_INDEX_HDR_FLAG_HAVE_DIRTY;
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainenvoid mail_index_map_check(struct mail_index_map *map)
19779377be72c9fe8365bb9ba7a2e0d06dc99c3bTimo Sirainen const struct mail_index_header *hdr = &map->hdr;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_assert(hdr->messages_count <= map->rec_map->records_count);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen for (seq = 1; seq <= hdr->messages_count; seq++) {
19779377be72c9fe8365bb9ba7a2e0d06dc99c3bTimo Sirainen i_assert(rec->uid >= hdr->first_deleted_uid_lowwater);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen i_assert(rec->uid >= hdr->first_unseen_uid_lowwater);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainenint mail_index_sync_map(struct mail_index_map **_map,
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen enum mail_index_sync_handler_type type, bool force,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_assert(index->map == map || type == MAIL_INDEX_SYNC_HANDLER_VIEW);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen start_offset = type == MAIL_INDEX_SYNC_HANDLER_FILE ?
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen map->hdr.log_file_tail_offset : map->hdr.log_file_head_offset;
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen if (!force && (index->flags & MAIL_INDEX_OPEN_FLAG_MMAP_DISABLE) == 0) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* see if we'd prefer to reopen the index file instead of
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen syncing the current map from the transaction log.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen don't check this if mmap is disabled, because reopening
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index causes sync to get lost. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* we don't know the index's size, so use the
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen smallest index size we're willing to read */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index_size = MAIL_INDEX_SYNC_MIN_READ_INDEX_SIZE;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* this isn't necessary correct currently, but it should be
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen close enough */
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen view = mail_index_view_open_with_map(index, map);
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen ret = mail_transaction_log_view_set(view->log_view,
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen /* if we failed because of a syscall error, make sure
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen we return a failure. */
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen /* the seq/offset is probably broken */
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen mail_index_set_error(index, "Index %s: Lost log for "
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen "(initial_mapped=%d, reason=%s)", index->filepath,
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* can't use it. sync by re-reading index. */
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen mail_transaction_log_get_head(index->log, &prev_seq, &prev_offset);
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen index->optimization_set.index.rewrite_min_log_bytes) {
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen /* we're reading more from log than we would have preferred.
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen remember that we probably want to rewrite index soon. */
if (had_dirty)
if (reset) {
&tdata)) > 0) {
if (had_dirty)
#ifdef DEBUG