mail-index-sync.c revision 77f386273491b3a20b49b2a5a9db4b6e360615f9
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin/* Copyright (C) 2003-2004 Timo Sirainen */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#include "lib.h"
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#include "array.h"
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#include "buffer.h"
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#include "mail-index-view-private.h"
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#include "mail-index-sync-private.h"
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#include "mail-index-transaction-private.h"
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#include "mail-transaction-log-private.h"
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#include "mail-transaction-util.h"
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#include "mail-cache.h"
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#include <stdlib.h>
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinstatic void mail_index_sync_add_expunge(struct mail_index_sync_ctx *ctx)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin const struct mail_transaction_expunge *e = ctx->data;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin size_t i, size = ctx->hdr->size / sizeof(*e);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin uint32_t uid;
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin for (i = 0; i < size; i++) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin for (uid = e[i].uid1; uid <= e[i].uid2; uid++)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_index_expunge(ctx->trans, uid);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
250b1eec71b074acdff1c5f6b5a1f0d7d2c20b77Stéphane Graber}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
8ec981fc8b0105da5f071e40811e0c2472a6c3c9Stéphane Graberstatic void mail_index_sync_add_flag_update(struct mail_index_sync_ctx *ctx)
c63c04fcaf1c3a78c70500eae253d72fa9c8358aTAMUKI Shoichi{
c63c04fcaf1c3a78c70500eae253d72fa9c8358aTAMUKI Shoichi const struct mail_transaction_flag_update *u = ctx->data;
c63c04fcaf1c3a78c70500eae253d72fa9c8358aTAMUKI Shoichi size_t i, size = ctx->hdr->size / sizeof(*u);
8ec981fc8b0105da5f071e40811e0c2472a6c3c9Stéphane Graber
8ec981fc8b0105da5f071e40811e0c2472a6c3c9Stéphane Graber for (i = 0; i < size; i++) {
8ec981fc8b0105da5f071e40811e0c2472a6c3c9Stéphane Graber if (u[i].add_flags != 0) {
8ec981fc8b0105da5f071e40811e0c2472a6c3c9Stéphane Graber mail_index_update_flags_range(ctx->trans,
8ec981fc8b0105da5f071e40811e0c2472a6c3c9Stéphane Graber u[i].uid1, u[i].uid2,
8ec981fc8b0105da5f071e40811e0c2472a6c3c9Stéphane Graber MODIFY_ADD,
207bf0e475f1dc6e9a2dac2cee3a209b56427855Stéphane Graber u[i].add_flags);
207bf0e475f1dc6e9a2dac2cee3a209b56427855Stéphane Graber }
207bf0e475f1dc6e9a2dac2cee3a209b56427855Stéphane Graber if (u[i].remove_flags != 0) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_index_update_flags_range(ctx->trans,
ed4616b1cfbc84dd01caa8546d813e8c5d482921Christian Bühler u[i].uid1, u[i].uid2,
e29bf450cafa2ce2564aeb0b64d2014c17228407Dwight Engen MODIFY_REMOVE,
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin u[i].remove_flags);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinstatic void mail_index_sync_add_keyword_update(struct mail_index_sync_ctx *ctx)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin const struct mail_transaction_keyword_update *u = ctx->data;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin const char *keyword_names[2];
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin struct mail_keywords *keywords;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin const uint32_t *uids;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin uint32_t uid;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin size_t uidset_offset, i, size;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin uidset_offset = sizeof(*u) + u->name_size;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if ((uidset_offset % 4) != 0)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin uidset_offset += 4 - (uidset_offset % 4);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin uids = CONST_PTR_OFFSET(u, uidset_offset);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin t_push();
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin keyword_names[0] = t_strndup(u + 1, u->name_size);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin keyword_names[1] = NULL;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin keywords = mail_index_keywords_create(ctx->trans, keyword_names);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin size = (ctx->hdr->size - uidset_offset) / sizeof(uint32_t);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin for (i = 0; i < size; i += 2) {
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin /* FIXME: mail_index_update_keywords_range() */
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin for (uid = uids[i]; uid <= uids[i+1]; uid++) {
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_index_update_keywords(ctx->trans, uid,
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin u->modify_type, keywords);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin }
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin }
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_index_keywords_free(&keywords);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin t_pop();
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin}
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalinstatic void mail_index_sync_add_keyword_reset(struct mail_index_sync_ctx *ctx)
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin{
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin const struct mail_transaction_keyword_reset *u = ctx->data;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin size_t i, size = ctx->hdr->size / sizeof(*u);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin struct mail_keywords *keywords;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin uint32_t uid;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin keywords = mail_index_keywords_create(ctx->trans, NULL);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin for (i = 0; i < size; i++) {
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin for (uid = u[i].uid1; uid <= u[i].uid2; uid++) {
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_index_update_keywords(ctx->trans, uid,
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin MODIFY_REPLACE, keywords);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_index_keywords_free(&keywords);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinstatic void mail_index_sync_add_append(struct mail_index_sync_ctx *ctx)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin const struct mail_index_record *rec = ctx->data;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (ctx->append_uid_first == 0 || rec->uid < ctx->append_uid_first)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin ctx->append_uid_first = rec->uid;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin rec = CONST_PTR_OFFSET(ctx->data, ctx->hdr->size - sizeof(*rec));
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin if (rec->uid > ctx->append_uid_last)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin ctx->append_uid_last = rec->uid;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin ctx->sync_appends = TRUE;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinstatic void mail_index_sync_add_transaction(struct mail_index_sync_ctx *ctx)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin switch (ctx->hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin case MAIL_TRANSACTION_EXPUNGE:
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_index_sync_add_expunge(ctx);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin break;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin case MAIL_TRANSACTION_FLAG_UPDATE:
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_index_sync_add_flag_update(ctx);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin break;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin case MAIL_TRANSACTION_KEYWORD_UPDATE:
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_index_sync_add_keyword_update(ctx);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin break;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin case MAIL_TRANSACTION_KEYWORD_RESET:
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_index_sync_add_keyword_reset(ctx);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin break;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin case MAIL_TRANSACTION_APPEND:
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_index_sync_add_append(ctx);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin break;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinstatic int mail_index_sync_add_dirty_updates(struct mail_index_sync_ctx *ctx)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin struct mail_transaction_flag_update update;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin const struct mail_index_record *rec;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin uint32_t seq, messages_count;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin memset(&update, 0, sizeof(update));
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin messages_count = mail_index_view_get_messages_count(ctx->view);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin for (seq = 1; seq <= messages_count; seq++) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (mail_index_lookup(ctx->view, seq, &rec) < 0)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return -1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if ((rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) == 0)
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin continue;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_index_update_flags(ctx->trans, rec->uid,
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin MODIFY_REPLACE, rec->flags);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin }
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin return 0;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinstatic int mail_index_sync_add_recent_updates(struct mail_index_sync_ctx *ctx)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin const struct mail_index_record *rec;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin uint32_t seq, messages_count;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin bool seen_recent = FALSE;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin messages_count = mail_index_view_get_messages_count(ctx->view);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin for (seq = 1; seq <= messages_count; seq++) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (mail_index_lookup(ctx->view, seq, &rec) < 0)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return -1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if ((rec->flags & MAIL_RECENT) != 0) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin seen_recent = TRUE;
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber mail_index_update_flags(ctx->trans, rec->uid,
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber MODIFY_REMOVE, MAIL_RECENT);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (!seen_recent) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin /* no recent messages, drop the sync_recent flag so we
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin don't scan through the message again */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin ctx->sync_recent = FALSE;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return 0;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinstatic int
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Grabermail_index_sync_read_and_sort(struct mail_index_sync_ctx *ctx,
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber bool *seen_external_r)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin struct mail_index_sync_list *synclist;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin const struct mail_index_transaction_keyword_update *keyword_updates;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin unsigned int i, keyword_count;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin int ret;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin *seen_external_r = FALSE;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if ((ctx->view->map->hdr.flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) &&
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin ctx->sync_dirty) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin /* show dirty flags as flag updates */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (mail_index_sync_add_dirty_updates(ctx) < 0)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return -1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (ctx->sync_recent) {
44d397891e691ab994a69766cc72e57265b62da1Serge Hallyn if (mail_index_sync_add_recent_updates(ctx) < 0)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return -1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin /* read all transactions from log into a transaction in memory */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin while ((ret = mail_transaction_log_view_next(ctx->view->log_view,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin &ctx->hdr,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin &ctx->data, NULL)) > 0) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if ((ctx->hdr->type & MAIL_TRANSACTION_EXTERNAL) != 0)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin *seen_external_r = TRUE;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin else
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_index_sync_add_transaction(ctx);
e29bf450cafa2ce2564aeb0b64d2014c17228407Dwight Engen }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
17abf2784de1047fb2904ff130ee5efe4ea7b598Elan Ruusamäe /* create an array containing all expunge, flag and keyword update
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber arrays so we can easily go through all of the changes. */
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber keyword_count = !array_is_created(&ctx->trans->keyword_updates) ? 0 :
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber array_count(&ctx->trans->keyword_updates);
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber i_array_init(&ctx->sync_list, keyword_count + 2);
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber if (array_is_created(&ctx->trans->expunges)) {
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber synclist = array_append_space(&ctx->sync_list);
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber synclist->array = (void *)&ctx->trans->expunges;
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber }
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber if (array_is_created(&ctx->trans->updates)) {
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber synclist = array_append_space(&ctx->sync_list);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin synclist->array = (void *)&ctx->trans->updates;
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber /* we must return resets before keyword additions or they get lost */
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber if (array_is_created(&ctx->trans->keyword_resets)) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin synclist = array_append_space(&ctx->sync_list);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin synclist->array = (void *)&ctx->trans->keyword_resets;
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber }
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber keyword_updates = keyword_count == 0 ? NULL :
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber array_idx(&ctx->trans->keyword_updates, 0);
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber for (i = 0; i < keyword_count; i++) {
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber if (array_is_created(&keyword_updates[i].add_seq)) {
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber synclist = array_append_space(&ctx->sync_list);
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber synclist->array = (void *)&keyword_updates[i].add_seq;
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber synclist->keyword_idx = i;
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber }
17abf2784de1047fb2904ff130ee5efe4ea7b598Elan Ruusamäe if (array_is_created(&keyword_updates[i].remove_seq)) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin synclist = array_append_space(&ctx->sync_list);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin synclist->array =
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin (void *)&keyword_updates[i].remove_seq;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin synclist->keyword_idx = i;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin synclist->keyword_remove = TRUE;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
1881820ae4ff9004beef1bf7f04553580840441dSerge Hallyn return ret;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinstatic int mail_index_need_lock(struct mail_index *index, bool sync_recent,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin uint32_t log_file_seq, uoff_t log_file_offset)
eba7df9ee0a1963984ef212e7ddfc0e0835af288Stéphane Graber{
eee3ba81c88e64b8a732694fc4843a39d5bde491Serge Hallyn if (sync_recent && index->hdr->recent_messages_count > 0)
f02ce27d4b1a9d01b88d0ffaf626e5bafa671bf0Stéphane Graber return 1;
f02ce27d4b1a9d01b88d0ffaf626e5bafa671bf0Stéphane Graber
f02ce27d4b1a9d01b88d0ffaf626e5bafa671bf0Stéphane Graber if (index->hdr->log_file_seq > log_file_seq ||
f02ce27d4b1a9d01b88d0ffaf626e5bafa671bf0Stéphane Graber (index->hdr->log_file_seq == log_file_seq &&
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin index->hdr->log_file_int_offset >= log_file_offset &&
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin index->hdr->log_file_ext_offset >= log_file_offset)) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin /* already synced */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return mail_cache_need_compress(index->cache);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin return 1;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin}
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalinstatic int
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalinmail_index_sync_set_log_view(struct mail_index_view *view,
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin uint32_t start_file_seq, uoff_t start_file_offset)
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin{
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin uint32_t log_seq;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin uoff_t log_offset;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin int ret;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_transaction_log_get_head(view->index->log, &log_seq, &log_offset);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin ret = mail_transaction_log_view_set(view->log_view,
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin start_file_seq, start_file_offset,
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin log_seq, log_offset,
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin MAIL_TRANSACTION_TYPE_MASK);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin if (ret <= 0) {
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin /* either corrupted or the file was deleted for
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin some reason. either way, we can't go forward */
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_index_set_error(view->index,
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin "Unexpected transaction log desync with index %s",
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin view->index->filepath);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_index_set_inconsistent(view->index);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return -1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return 0;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinstatic int mail_index_sync_commit_external(struct mail_index_sync_ctx *ctx)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin int ret;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin /* find the first external transaction, if there are any */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin while ((ret = mail_transaction_log_view_next(ctx->view->log_view,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin &ctx->hdr, &ctx->data,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin NULL)) > 0) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if ((ctx->hdr->type & MAIL_TRANSACTION_EXTERNAL) != 0)
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin break;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (ret < 0)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return -1;
44b430e2c5a11f792e21d3774b530f410ff5af75Serge Logvinov
44b430e2c5a11f792e21d3774b530f410ff5af75Serge Logvinov if (ret > 0) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin uint32_t seq;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin uoff_t offset;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber /* found it. update log view's range to begin from it and
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber write all external transactions to index. */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_view_get_prev_pos(ctx->view->log_view,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin &seq, &offset);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (mail_index_sync_set_log_view(ctx->view, seq, offset) < 0)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return -1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (mail_index_sync_update_index(ctx, TRUE) < 0)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return -1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return 0;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin}
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin#define MAIL_INDEX_IS_SYNCS_SAME(index) \
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin ((index)->hdr != NULL && \
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin (index)->sync_log_file_seq == (index)->hdr->log_file_seq && \
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin (index)->sync_log_file_offset == (index)->hdr->log_file_ext_offset)
17abf2784de1047fb2904ff130ee5efe4ea7b598Elan Ruusamäe
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graberint mail_index_sync_begin(struct mail_index *index,
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber struct mail_index_sync_ctx **ctx_r,
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber struct mail_index_view **view_r,
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber uint32_t log_file_seq, uoff_t log_file_offset,
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber bool sync_recent, bool sync_dirty)
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber{
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber struct mail_index_sync_ctx *ctx;
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber struct mail_index_view *dummy_view;
17abf2784de1047fb2904ff130ee5efe4ea7b598Elan Ruusamäe uint32_t seq;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin uoff_t offset;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin unsigned int lock_id = 0;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin bool seen_external;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (mail_transaction_log_sync_lock(index->log, &seq, &offset) < 0)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return -1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (!index->mmap_disable || !MAIL_INDEX_IS_SYNCS_SAME(index) ||
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin index->sync_log_file_seq != seq ||
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin index->sync_log_file_offset != offset) {
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn /* make sure we have the latest file mapped */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (mail_index_lock_shared(index, TRUE, &lock_id) < 0) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_sync_unlock(index->log);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return -1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
e29bf450cafa2ce2564aeb0b64d2014c17228407Dwight Engen /* with mmap_disable the force parameter has somewhat special
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin meaning, it syncs exactly to the log seq/offset in index
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin file's header. */
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin if (mail_index_map(index, index->mmap_disable) <= 0) {
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_transaction_log_sync_unlock(index->log);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_index_unlock(index, lock_id);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin return -1;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn if ((index->hdr->flags & MAIL_INDEX_HDR_FLAG_FSCK) != 0) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (mail_index_fsck(index) <= 0) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_index_unlock(index, lock_id);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_sync_unlock(index->log);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return -1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (!mail_index_need_lock(index, sync_recent,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin log_file_seq, log_file_offset)) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_index_unlock(index, lock_id);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_sync_unlock(index->log);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return 0;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (index->hdr->log_file_int_offset > index->hdr->log_file_ext_offset ||
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber (index->hdr->log_file_seq == seq &&
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber index->hdr->log_file_ext_offset > offset) ||
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn (index->hdr->log_file_seq != seq &&
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber !mail_transaction_log_is_head_prev(index->log,
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber index->hdr->log_file_seq,
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber index->hdr->log_file_ext_offset))) {
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber /* broken sync positions. fix them. */
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber mail_index_set_error(index, "broken sync positions");
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber if (mail_index_fsck(index) <= 0) {
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber mail_index_unlock(index, lock_id);
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber mail_transaction_log_sync_unlock(index->log);
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber return -1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin ctx = i_new(struct mail_index_sync_ctx, 1);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin ctx->index = index;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin ctx->lock_id = lock_id;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin ctx->sync_recent = sync_recent;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin ctx->sync_dirty = sync_dirty;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin ctx->view = mail_index_view_open(index);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin dummy_view = mail_index_dummy_view_open(index);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin ctx->trans = mail_index_transaction_begin(dummy_view, FALSE, TRUE);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_index_view_close(&dummy_view);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (mail_index_sync_set_log_view(ctx->view,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin index->hdr->log_file_seq,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin index->hdr->log_file_int_offset) < 0) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_index_sync_rollback(&ctx);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return -1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin /* See if there are some external transactions which were
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin written to transaction log, but weren't yet committed to
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin index. commit them first to avoid conflicts with another
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin external sync.
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin This is mostly needed to make sure there won't be multiple
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin appends with same UIDs, because those would cause
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin transaction log to be marked corrupted.
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin Note that any internal transactions must not be committed
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin yet. They need to be synced with the real mailbox first. */
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin if (seq != index->hdr->log_file_seq ||
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin offset != index->hdr->log_file_ext_offset) {
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin if (mail_index_sync_commit_external(ctx) < 0) {
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_index_sync_rollback(&ctx);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin return -1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_index_view_close(&ctx->view);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin ctx->view = mail_index_view_open(index);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn if (mail_index_sync_set_log_view(ctx->view,
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn index->hdr->log_file_seq,
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn index->hdr->log_file_int_offset) < 0)
853d58fdf5af0960b7b6edc9dea0fadddb8535f1Elan Ruusamäe return -1;
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn }
44b430e2c5a11f792e21d3774b530f410ff5af75Serge Logvinov
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn /* we need to have all the transactions sorted to optimize
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn caller's mailbox access patterns */
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn if (mail_index_sync_read_and_sort(ctx, &seen_external) < 0) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_index_sync_rollback(&ctx);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return -1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin }
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin ctx->view->index_sync_view = TRUE;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin *ctx_r = ctx;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin *view_r = ctx->view;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin return 1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinstatic void
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinmail_index_sync_get_expunge(struct mail_index_sync_rec *rec,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin const struct mail_transaction_expunge *exp)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin rec->type = MAIL_INDEX_SYNC_TYPE_EXPUNGE;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin rec->uid1 = exp->uid1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin rec->uid2 = exp->uid2;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinstatic void
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinmail_index_sync_get_update(struct mail_index_sync_rec *rec,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin const struct mail_transaction_flag_update *update)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin{
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin rec->type = MAIL_INDEX_SYNC_TYPE_FLAGS;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin rec->uid1 = update->uid1;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin rec->uid2 = update->uid2;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin rec->add_flags = update->add_flags;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin rec->remove_flags = update->remove_flags;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin}
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin
eba7df9ee0a1963984ef212e7ddfc0e0835af288Stéphane Graberstatic void
mail_index_sync_get_keyword_update(struct mail_index_sync_rec *rec,
const struct uid_range *range,
struct mail_index_sync_list *sync_list)
{
rec->type = !sync_list->keyword_remove ?
MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD :
MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE;
rec->uid1 = range->uid1;
rec->uid2 = range->uid2;
rec->keyword_idx = sync_list->keyword_idx;
}
static void mail_index_sync_get_keyword_reset(struct mail_index_sync_rec *rec,
const struct uid_range *range)
{
rec->type = MAIL_INDEX_SYNC_TYPE_KEYWORD_RESET;
rec->uid1 = range->uid1;
rec->uid2 = range->uid2;
}
static int mail_index_sync_rec_check(struct mail_index_view *view,
struct mail_index_sync_rec *rec)
{
switch (rec->type) {
case MAIL_INDEX_SYNC_TYPE_EXPUNGE:
case MAIL_INDEX_SYNC_TYPE_FLAGS:
case MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD:
case MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE:
case MAIL_INDEX_SYNC_TYPE_KEYWORD_RESET:
if (rec->uid1 > rec->uid2 || rec->uid1 == 0) {
mail_transaction_log_view_set_corrupted(view->log_view,
"Broken UID range: %u..%u (type 0x%x)",
rec->uid1, rec->uid2, rec->type);
return -1;
}
break;
case MAIL_INDEX_SYNC_TYPE_APPEND:
break;
}
return 0;
}
int mail_index_sync_next(struct mail_index_sync_ctx *ctx,
struct mail_index_sync_rec *sync_rec)
{
struct mail_index_sync_list *sync_list;
const struct uid_range *uid_range = NULL;
unsigned int i, count, next_i;
uint32_t next_found_uid;
next_i = (unsigned int)-1;
next_found_uid = (uint32_t)-1;
/* FIXME: replace with a priority queue so we don't have to go
through the whole list constantly. and remember to make sure that
keyword resets are sent before adds! */
sync_list = array_get_modifiable(&ctx->sync_list, &count);
for (i = 0; i < count; i++) {
if (!array_is_created(sync_list[i].array) ||
sync_list[i].idx == array_count(sync_list[i].array))
continue;
uid_range = array_idx(sync_list[i].array, sync_list[i].idx);
if (uid_range->uid1 == ctx->next_uid) {
/* use this one. */
break;
}
if (uid_range->uid1 < next_found_uid) {
next_i = i;
next_found_uid = uid_range->uid1;
}
}
if (i == count) {
if (next_i == (unsigned int)-1) {
/* nothing left in sync_list */
if (ctx->sync_appends) {
ctx->sync_appends = FALSE;
sync_rec->type = MAIL_INDEX_SYNC_TYPE_APPEND;
sync_rec->uid1 = ctx->append_uid_first;
sync_rec->uid2 = ctx->append_uid_last;
return 1;
}
return 0;
}
ctx->next_uid = next_found_uid;
i = next_i;
uid_range = array_idx(sync_list[i].array, sync_list[i].idx);
}
if (sync_list[i].array == (void *)&ctx->trans->expunges) {
mail_index_sync_get_expunge(sync_rec,
(const struct mail_transaction_expunge *)uid_range);
} else if (sync_list[i].array == (void *)&ctx->trans->updates) {
mail_index_sync_get_update(sync_rec,
(const struct mail_transaction_flag_update *)uid_range);
} else if (sync_list[i].array == (void *)&ctx->trans->keyword_resets) {
mail_index_sync_get_keyword_reset(sync_rec, uid_range);
} else {
mail_index_sync_get_keyword_update(sync_rec, uid_range,
&sync_list[i]);
}
sync_list[i].idx++;
if (mail_index_sync_rec_check(ctx->view, sync_rec) < 0)
return -1;
return 1;
}
bool mail_index_sync_have_more(struct mail_index_sync_ctx *ctx)
{
const struct mail_index_sync_list *sync_list;
unsigned int i, count;
if (ctx->sync_appends)
return TRUE;
sync_list = array_get(&ctx->sync_list, &count);
for (i = 0; i < count; i++) {
if (array_is_created(sync_list[i].array) &&
sync_list[i].idx != array_count(sync_list[i].array))
return TRUE;
}
return FALSE;
}
void mail_index_sync_reset(struct mail_index_sync_ctx *ctx)
{
struct mail_index_sync_list *sync_list;
unsigned int i, count;
ctx->next_uid = 0;
sync_list = array_get_modifiable(&ctx->sync_list, &count);
for (i = 0; i < count; i++)
sync_list[i].idx = 0;
}
static void mail_index_sync_end(struct mail_index_sync_ctx **_ctx)
{
struct mail_index_sync_ctx *ctx = *_ctx;
*_ctx = NULL;
mail_index_unlock(ctx->index, ctx->lock_id);
i_assert(ctx->index->map == NULL ||
!ctx->index->map->write_to_disk);
mail_transaction_log_sync_unlock(ctx->index->log);
mail_index_view_close(&ctx->view);
mail_index_transaction_rollback(&ctx->trans);
if (array_is_created(&ctx->sync_list))
array_free(&ctx->sync_list);
i_free(ctx);
}
int mail_index_sync_commit(struct mail_index_sync_ctx **_ctx)
{
struct mail_index_sync_ctx *ctx = *_ctx;
struct mail_index *index = ctx->index;
const struct mail_index_header *hdr;
uint32_t seq;
uoff_t offset;
int ret = 0;
if (mail_transaction_log_view_is_corrupted(ctx->view->log_view))
ret = -1;
/* we have had the transaction log locked since the beginning of sync,
so only external changes could have been committed. write them to
the index here as well. */
mail_transaction_log_get_head(index->log, &seq, &offset);
hdr = index->hdr;
if (ret == 0 && (hdr->log_file_seq != seq ||
hdr->log_file_int_offset != offset ||
hdr->log_file_ext_offset != offset ||
ctx->sync_recent)) {
/* write all pending changes to index. */
if (mail_index_sync_set_log_view(ctx->view,
hdr->log_file_seq,
hdr->log_file_int_offset) < 0)
ret = -1;
else if (mail_index_sync_update_index(ctx, FALSE) < 0)
ret = -1;
}
if (ret == 0 && mail_cache_need_compress(index->cache)) {
/* if cache compression fails, we don't really care */
if (mail_cache_compress(index->cache, ctx->view) == 0) {
/* cache_offsets have changed, sync them */
if (mail_index_sync_set_log_view(ctx->view,
seq, offset) < 0)
ret = -1;
else if (mail_index_sync_update_index(ctx, FALSE) < 0)
ret = -1;
}
}
if (ret == 0) {
index->sync_log_file_seq = index->map->hdr.log_file_seq;
index->sync_log_file_offset =
index->map->hdr.log_file_int_offset;
}
mail_index_sync_end(_ctx);
return ret;
}
void mail_index_sync_rollback(struct mail_index_sync_ctx **ctx)
{
mail_index_sync_end(ctx);
}
void mail_index_sync_flags_apply(const struct mail_index_sync_rec *sync_rec,
uint8_t *flags)
{
i_assert(sync_rec->type == MAIL_INDEX_SYNC_TYPE_FLAGS);
*flags = (*flags & ~sync_rec->remove_flags) | sync_rec->add_flags;
}
bool mail_index_sync_keywords_apply(const struct mail_index_sync_rec *sync_rec,
ARRAY_TYPE(keyword_indexes) *keywords)
{
const unsigned int *keyword_indexes;
unsigned int idx = sync_rec->keyword_idx;
unsigned int i, count;
keyword_indexes = array_get(keywords, &count);
switch (sync_rec->type) {
case MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD:
for (i = 0; i < count; i++) {
if (keyword_indexes[i] == idx)
return FALSE;
}
array_append(keywords, &idx, 1);
return TRUE;
case MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE:
for (i = 0; i < count; i++) {
if (keyword_indexes[i] == idx) {
array_delete(keywords, i, 1);
return TRUE;
}
}
return FALSE;
case MAIL_INDEX_SYNC_TYPE_KEYWORD_RESET:
if (array_count(keywords) == 0)
return FALSE;
array_clear(keywords);
return TRUE;
default:
i_unreached();
return FALSE;
}
}
void mail_index_sync_set_corrupted(struct mail_index_sync_map_ctx *ctx,
const char *fmt, ...)
{
const char *error;
va_list va;
va_start(va, fmt);
t_push();
error = t_strdup_vprintf(fmt, va);
if (ctx->type == MAIL_INDEX_SYNC_HANDLER_FILE) {
mail_transaction_log_view_set_corrupted(ctx->view->log_view,
"%s", error);
} else {
mail_index_set_error(ctx->view->index,
"View synchronization from transaction log failed: %s",
error);
}
t_pop();
va_end(va);
}