mail-index-sync.c revision 77f386273491b3a20b49b2a5a9db4b6e360615f9
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin/* Copyright (C) 2003-2004 Timo Sirainen */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinstatic void mail_index_sync_add_expunge(struct mail_index_sync_ctx *ctx)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin const struct mail_transaction_expunge *e = ctx->data;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin size_t i, size = ctx->hdr->size / sizeof(*e);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin for (i = 0; i < size; i++) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin for (uid = e[i].uid1; uid <= e[i].uid2; uid++)
8ec981fc8b0105da5f071e40811e0c2472a6c3c9Stéphane Graberstatic void mail_index_sync_add_flag_update(struct mail_index_sync_ctx *ctx)
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 for (i = 0; i < size; i++) {
8ec981fc8b0105da5f071e40811e0c2472a6c3c9Stéphane Graber if (u[i].add_flags != 0) {
207bf0e475f1dc6e9a2dac2cee3a209b56427855Stéphane Graber if (u[i].remove_flags != 0) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinstatic void mail_index_sync_add_keyword_update(struct mail_index_sync_ctx *ctx)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin const struct mail_transaction_keyword_update *u = ctx->data;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin keyword_names[0] = t_strndup(u + 1, u->name_size);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin keywords = mail_index_keywords_create(ctx->trans, keyword_names);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin size = (ctx->hdr->size - uidset_offset) / sizeof(uint32_t);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin /* FIXME: mail_index_update_keywords_range() */
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin for (uid = uids[i]; uid <= uids[i+1]; uid++) {
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalinstatic void mail_index_sync_add_keyword_reset(struct mail_index_sync_ctx *ctx)
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin const struct mail_transaction_keyword_reset *u = ctx->data;
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin size_t i, size = ctx->hdr->size / sizeof(*u);
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++) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinstatic void mail_index_sync_add_append(struct mail_index_sync_ctx *ctx)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin const struct mail_index_record *rec = ctx->data;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (ctx->append_uid_first == 0 || rec->uid < ctx->append_uid_first)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin rec = CONST_PTR_OFFSET(ctx->data, ctx->hdr->size - sizeof(*rec));
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinstatic void mail_index_sync_add_transaction(struct mail_index_sync_ctx *ctx)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin switch (ctx->hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinstatic int mail_index_sync_add_dirty_updates(struct mail_index_sync_ctx *ctx)
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 if ((rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) == 0)
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin mail_index_update_flags(ctx->trans, rec->uid,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinstatic int mail_index_sync_add_recent_updates(struct mail_index_sync_ctx *ctx)
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)
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber mail_index_update_flags(ctx->trans, rec->uid,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin /* no recent messages, drop the sync_recent flag so we
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin don't scan through the message again */
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Grabermail_index_sync_read_and_sort(struct mail_index_sync_ctx *ctx,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin const struct mail_index_transaction_keyword_update *keyword_updates;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin unsigned int i, keyword_count;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if ((ctx->view->map->hdr.flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) &&
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin /* show dirty flags as flag updates */
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (mail_index_sync_add_dirty_updates(ctx) < 0)
44d397891e691ab994a69766cc72e57265b62da1Serge Hallyn if (mail_index_sync_add_recent_updates(ctx) < 0)
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 if ((ctx->hdr->type & MAIL_TRANSACTION_EXTERNAL) != 0)
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 i_array_init(&ctx->sync_list, keyword_count + 2);
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 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 /* 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 keyword_updates = keyword_count == 0 ? NULL :
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;
17abf2784de1047fb2904ff130ee5efe4ea7b598Elan Ruusamäe if (array_is_created(&keyword_updates[i].remove_seq)) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin synclist = array_append_space(&ctx->sync_list);
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)
eee3ba81c88e64b8a732694fc4843a39d5bde491Serge Hallyn if (sync_recent && index->hdr->recent_messages_count > 0)
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 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 mail_transaction_log_get_head(view->index->log, &log_seq, &log_offset);
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin ret = mail_transaction_log_view_set(view->log_view,
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin /* either corrupted or the file was deleted for
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin some reason. either way, we can't go forward */
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin "Unexpected transaction log desync with index %s",
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinstatic int mail_index_sync_commit_external(struct mail_index_sync_ctx *ctx)
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 if ((ctx->hdr->type & MAIL_TRANSACTION_EXTERNAL) != 0)
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 if (mail_index_sync_set_log_view(ctx->view, seq, offset) < 0)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (mail_index_sync_update_index(ctx, TRUE) < 0)
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)
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graberint mail_index_sync_begin(struct mail_index *index,
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber uint32_t log_file_seq, uoff_t log_file_offset,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin unsigned int lock_id = 0;
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (mail_transaction_log_sync_lock(index->log, &seq, &offset) < 0)
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (!index->mmap_disable || !MAIL_INDEX_IS_SYNCS_SAME(index) ||
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);
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);
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn if ((index->hdr->flags & MAIL_INDEX_HDR_FLAG_FSCK) != 0) {
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_sync_unlock(index->log);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (!mail_index_need_lock(index, sync_recent,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin mail_transaction_log_sync_unlock(index->log);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin if (index->hdr->log_file_int_offset > index->hdr->log_file_ext_offset ||
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber index->hdr->log_file_ext_offset > offset) ||
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber !mail_transaction_log_is_head_prev(index->log,
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber /* broken sync positions. fix them. */
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber mail_index_set_error(index, "broken sync positions");
14d9c0f09d1a55d124ef210a4b4e205c9fe7596cStéphane Graber mail_transaction_log_sync_unlock(index->log);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin dummy_view = mail_index_dummy_view_open(index);
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin ctx->trans = mail_index_transaction_begin(dummy_view, FALSE, TRUE);
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 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 Note that any internal transactions must not be committed
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin yet. They need to be synced with the real mailbox first. */
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin offset != index->hdr->log_file_ext_offset) {
b031f0d2ca1b40eab86286b82d3c5e8b379122e6Alexey Shabalin if (mail_index_sync_commit_external(ctx) < 0) {
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 Shabalinmail_index_sync_get_expunge(struct mail_index_sync_rec *rec,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalinmail_index_sync_get_update(struct mail_index_sync_rec *rec,
262f4e48a51a55ad9cee06abbcfe4a6ad6166f49Alexey Shabalin const struct mail_transaction_flag_update *update)
for (i = 0; i < count; i++) {
next_i = i;
if (i == count) {
i = next_i;
&sync_list[i]);
unsigned int i, count;
return TRUE;
for (i = 0; i < count; i++) {
return TRUE;
return FALSE;
unsigned int i, count;
for (i = 0; i < count; i++)
int ret = 0;
if (ret == 0) {
return ret;
const unsigned int *keyword_indexes;
unsigned int i, count;
for (i = 0; i < count; i++) {
return FALSE;
return TRUE;
for (i = 0; i < count; i++) {
return TRUE;
return FALSE;
return FALSE;
return TRUE;
i_unreached();
return FALSE;
const char *fmt, ...)
const char *error;
t_push();
error);
t_pop();