mail-index-sync.c revision e86d0d34fe365da4c7ca4312d575bfcbf3a01c0e
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn/* Copyright (C) 2003-2004 Timo Sirainen */
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser#include "lib.h"
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser#include "buffer.h"
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn#include "mail-index-view-private.h"
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn#include "mail-index-sync-private.h"
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn#include "mail-transaction-log.h"
acbb59f50d5196facde837ea377f70e98ce1e6f8Serge Hallyn#include "mail-transaction-util.h"
acbb59f50d5196facde837ea377f70e98ce1e6f8Serge Hallyn#include "mail-cache.h"
acbb59f50d5196facde837ea377f70e98ce1e6f8Serge Hallyn
acbb59f50d5196facde837ea377f70e98ce1e6f8Serge Hallyn#include <stdlib.h>
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
acbb59f50d5196facde837ea377f70e98ce1e6f8Serge Hallynstatic void
acbb59f50d5196facde837ea377f70e98ce1e6f8Serge Hallynmail_index_sync_sort_flags(buffer_t *dest_buf,
acbb59f50d5196facde837ea377f70e98ce1e6f8Serge Hallyn const struct mail_transaction_flag_update *src,
acbb59f50d5196facde837ea377f70e98ce1e6f8Serge Hallyn size_t src_size)
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn{
acbb59f50d5196facde837ea377f70e98ce1e6f8Serge Hallyn const struct mail_transaction_flag_update *src_end;
acbb59f50d5196facde837ea377f70e98ce1e6f8Serge Hallyn struct mail_transaction_flag_update *dest;
acbb59f50d5196facde837ea377f70e98ce1e6f8Serge Hallyn struct mail_transaction_flag_update new_update, tmp_update;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn size_t i, dest_count;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn int j;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser dest = buffer_get_modifyable_data(dest_buf, &dest_count);
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser dest_count /= sizeof(*dest);
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser if (dest_count == 0) {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn buffer_append(dest_buf, src, src_size);
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn return;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn }
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn src_end = PTR_OFFSET(src, src_size);
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn for (i = 0; src != src_end; src++) {
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn new_update = *src;
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn /* insert it into buffer, split and merge it with existing
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn updates if needed. */
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn for (; i < dest_count; i++) {
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn if (new_update.uid1 > dest[i].uid2)
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn continue;
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn if (new_update.uid2 < dest[i].uid1)
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn break;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn /* at least partially overlapping */
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn if (new_update.uid1 < dest[i].uid1) {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn /* { 5..6 } + { 1..5 } -> { 1..4 } + { 5..6 } */
42ff5f0f8767114d060f5031055038a1a1c3759aSerge Hallyn tmp_update = new_update;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn tmp_update.uid2 = dest[i].uid1-1;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn new_update.uid1 = dest[i].uid1;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn buffer_insert(dest_buf, i * sizeof(tmp_update),
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn &tmp_update, sizeof(tmp_update));
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn dest = buffer_get_modifyable_data(dest_buf,
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn NULL);
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn dest_count++; i++;
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn } else if (new_update.uid1 > dest[i].uid1) {
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn /* { 5..7 } + { 6..6 } ->
daaf41b36790bdaae855048e56ed090b17a77c97Stéphane Graber split old to { 5..5 } + { 6..7 } */
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn tmp_update = dest[i];
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn tmp_update.uid2 = new_update.uid1-1;
1881820ae4ff9004beef1bf7f04553580840441dSerge Hallyn dest[i].uid1 = new_update.uid1;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn buffer_insert(dest_buf, i * sizeof(tmp_update),
daaf41b36790bdaae855048e56ed090b17a77c97Stéphane Graber &tmp_update, sizeof(tmp_update));
daaf41b36790bdaae855048e56ed090b17a77c97Stéphane Graber dest = buffer_get_modifyable_data(dest_buf,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn NULL);
daaf41b36790bdaae855048e56ed090b17a77c97Stéphane Graber dest_count++; i++;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn }
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn i_assert(new_update.uid1 == dest[i].uid1);
daaf41b36790bdaae855048e56ed090b17a77c97Stéphane Graber
daaf41b36790bdaae855048e56ed090b17a77c97Stéphane Graber if (new_update.uid2 < dest[i].uid2) {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn /* { 5..7 } + { 5..6 } -> { 5..6 } + { 7..7 } */
eee3ba81c88e64b8a732694fc4843a39d5bde491Serge Hallyn tmp_update = dest[i];
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn tmp_update.uid1 = new_update.uid2+1;
f02ce27d4b1a9d01b88d0ffaf626e5bafa671bf0Stéphane Graber dest[i].uid2 = new_update.uid2;
f02ce27d4b1a9d01b88d0ffaf626e5bafa671bf0Stéphane Graber buffer_insert(dest_buf,
9313e1e628160ca64f9e7fcec6500056c9a0725fStéphane Graber (i+1) * sizeof(tmp_update),
b85ab7989ebe24629267048cb269b278eeb50490Serge Hallyn &tmp_update, sizeof(tmp_update));
b85ab7989ebe24629267048cb269b278eeb50490Serge Hallyn dest = buffer_get_modifyable_data(dest_buf,
b85ab7989ebe24629267048cb269b278eeb50490Serge Hallyn NULL);
f02ce27d4b1a9d01b88d0ffaf626e5bafa671bf0Stéphane Graber dest_count++;
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser new_update.uid2 = 0;
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn } else {
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser /* full match, or continues. */
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn new_update.uid1 = dest[i].uid2+1;
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn }
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn /* dest[i] now contains the overlapping area.
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn merge them - new_update overrides old changes. */
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn dest[i].add_flags |= new_update.add_flags;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn dest[i].add_flags &= ~new_update.remove_flags;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn dest[i].remove_flags |= new_update.remove_flags;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn dest[i].remove_flags &= ~new_update.add_flags;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn for (j = 0; j < INDEX_KEYWORDS_BYTE_COUNT; j++) {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn dest[i].add_keywords[j] |=
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn new_update.add_keywords[j];
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn dest[i].add_keywords[j] &=
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn ~new_update.remove_keywords[j];
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn dest[i].remove_keywords[j] |=
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn new_update.remove_keywords[j];
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn dest[i].remove_keywords[j] &=
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn ~new_update.add_keywords[j];
eee3ba81c88e64b8a732694fc4843a39d5bde491Serge Hallyn }
a2abaa9ec60a8967611e8c8905698bd01bde5861Stéphane Graber }
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
a2abaa9ec60a8967611e8c8905698bd01bde5861Stéphane Graber if (new_update.uid1 <= new_update.uid2) {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn buffer_insert(dest_buf, i * sizeof(new_update),
a2abaa9ec60a8967611e8c8905698bd01bde5861Stéphane Graber &new_update, sizeof(new_update));
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn dest = buffer_get_modifyable_data(dest_buf, NULL);
a2abaa9ec60a8967611e8c8905698bd01bde5861Stéphane Graber dest_count++;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn }
a2abaa9ec60a8967611e8c8905698bd01bde5861Stéphane Graber }
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn}
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallynstatic void mail_index_sync_sort_transaction(struct mail_index_sync_ctx *ctx)
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn{
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn switch (ctx->hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
80a881b232b8955b85b360d4def99e6e680ff61bSerge Hallyn case MAIL_TRANSACTION_EXPUNGE:
80a881b232b8955b85b360d4def99e6e680ff61bSerge Hallyn mail_transaction_log_sort_expunges(ctx->expunges_buf,
d59feca3be9651b0ec38a57a8614cc2f3c51ca45Stéphane Graber ctx->data, ctx->hdr->size);
d59feca3be9651b0ec38a57a8614cc2f3c51ca45Stéphane Graber break;
d59feca3be9651b0ec38a57a8614cc2f3c51ca45Stéphane Graber case MAIL_TRANSACTION_FLAG_UPDATE:
4d7bcfb638c5c4907e8539aa09d41bb1de08a097Serge Hallyn mail_index_sync_sort_flags(ctx->updates_buf, ctx->data,
bf7d76cf3ae180820c0a29e0bfbaa97c20ce6a3dSerge Hallyn ctx->hdr->size);
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn break;
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn case MAIL_TRANSACTION_APPEND: {
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn const struct mail_index_record *rec = ctx->data;
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn if (ctx->append_uid_first == 0 ||
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn rec->uid < ctx->append_uid_first)
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn ctx->append_uid_first = rec->uid;
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn rec = CONST_PTR_OFFSET(ctx->data,
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn ctx->hdr->size - sizeof(*rec));
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn if (rec->uid > ctx->append_uid_last)
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn ctx->append_uid_last = rec->uid;
542939c31bb73bab55f2fd71243b98f5559597d1Stéphane Graber
42ff5f0f8767114d060f5031055038a1a1c3759aSerge Hallyn ctx->sync_appends = TRUE;
42ff5f0f8767114d060f5031055038a1a1c3759aSerge Hallyn break;
42ff5f0f8767114d060f5031055038a1a1c3759aSerge Hallyn }
5ff337745e4a705293b056ab58f6ea7a92cabbc8Stéphane Graber }
542939c31bb73bab55f2fd71243b98f5559597d1Stéphane Graber}
5ff337745e4a705293b056ab58f6ea7a92cabbc8Stéphane Graber
42ff5f0f8767114d060f5031055038a1a1c3759aSerge Hallynstatic int mail_index_sync_add_dirty_updates(struct mail_index_sync_ctx *ctx)
42ff5f0f8767114d060f5031055038a1a1c3759aSerge Hallyn{
42ff5f0f8767114d060f5031055038a1a1c3759aSerge Hallyn struct mail_transaction_flag_update update;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn const struct mail_index_record *rec;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn uint32_t seq, messages_count;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn int i;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn memset(&update, 0, sizeof(update));
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn messages_count = mail_index_view_get_message_count(ctx->view);
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn for (seq = 1; seq <= messages_count; seq++) {
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn if (mail_index_lookup(ctx->view, seq, &rec) < 0)
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn return -1;
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn
840295ff4cf11da0938a19f99fef8a1525de8106Stéphane Graber if ((rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) == 0)
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn continue;
52c8f624b5f9ef665f33a7aa80e0aa18b91daa4aSerge Hallyn
427bffc7a10c9015dc78ef52543f7b8cb9414359Serge Hallyn update.uid1 = update.uid2 = rec->uid;
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn update.add_flags = rec->flags;
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser update.remove_flags = ~update.add_flags;
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser memcpy(update.add_keywords, rec->keywords,
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser INDEX_KEYWORDS_BYTE_COUNT);
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn for (i = 0; i < INDEX_KEYWORDS_BYTE_COUNT; i++)
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn update.remove_keywords[i] = ~update.add_keywords[i];
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn mail_index_sync_sort_flags(ctx->updates_buf,
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn &update, sizeof(update));
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn }
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn return 0;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn}
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallynstatic int mail_index_sync_add_recent_updates(struct mail_index_sync_ctx *ctx)
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn{
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn struct mail_transaction_flag_update update;
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser const struct mail_index_record *rec;
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser uint32_t seq, messages_count;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn memset(&update, 0, sizeof(update));
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser messages_count = mail_index_view_get_message_count(ctx->view);
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser for (seq = 1; seq <= messages_count; seq++) {
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser if (mail_index_lookup(ctx->view, seq, &rec) < 0)
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser return -1;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn if ((rec->flags & MAIL_RECENT) == 0) {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn if (update.uid1 != 0) {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn mail_index_sync_sort_flags(ctx->updates_buf,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn &update,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn sizeof(update));
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn update.uid1 = 0;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn }
ed4616b1cfbc84dd01caa8546d813e8c5d482921Christian Bühler continue;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn }
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn /* group updates together as much as possible */
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn if (update.uid1 == 0)
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn update.uid1 = rec->uid;
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn update.uid2 = rec->uid;
b8bced69a80a8be95fdbbb6b4e9ad7fa85464b1eSerge Hallyn }
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn if (update.uid1 != 0) {
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber mail_index_sync_sort_flags(ctx->updates_buf,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn &update, sizeof(update));
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn }
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn return 0;
52c8f624b5f9ef665f33a7aa80e0aa18b91daa4aSerge Hallyn}
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallynstatic int
4759162d078d86628956cae4846c6efccf548e67Serge Hallynmail_index_sync_read_and_sort(struct mail_index_sync_ctx *ctx, int sync_recent,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn int *seen_external_r)
427bffc7a10c9015dc78ef52543f7b8cb9414359Serge Hallyn{
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser size_t size;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn int ret;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn *seen_external_r = FALSE;
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn if ((ctx->view->map->hdr.flags & MAIL_INDEX_HDR_FLAG_HAVE_DIRTY) &&
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn ctx->sync_dirty) {
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn /* show dirty flags as flag updates */
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn if (mail_index_sync_add_dirty_updates(ctx) < 0)
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn return -1;
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn }
52c8f624b5f9ef665f33a7aa80e0aa18b91daa4aSerge Hallyn
427bffc7a10c9015dc78ef52543f7b8cb9414359Serge Hallyn if (sync_recent) {
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser if (mail_index_sync_add_recent_updates(ctx) < 0)
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser return -1;
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser }
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser while ((ret = mail_transaction_log_view_next(ctx->view->log_view,
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser &ctx->hdr,
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn &ctx->data, NULL)) > 0) {
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn if ((ctx->hdr->type & MAIL_TRANSACTION_EXTERNAL) != 0)
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn *seen_external_r = TRUE;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn else
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn mail_index_sync_sort_transaction(ctx);
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn }
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser ctx->expunges = buffer_get_data(ctx->expunges_buf, &size);
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser ctx->expunges_count = size / sizeof(*ctx->expunges);
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn ctx->updates = buffer_get_data(ctx->updates_buf, &size);
52c8f624b5f9ef665f33a7aa80e0aa18b91daa4aSerge Hallyn ctx->updates_count = size / sizeof(*ctx->updates);
52c8f624b5f9ef665f33a7aa80e0aa18b91daa4aSerge Hallyn
52c8f624b5f9ef665f33a7aa80e0aa18b91daa4aSerge Hallyn return ret;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn}
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallynstatic int mail_index_need_lock(struct mail_index *index, int sync_recent,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn uint32_t log_file_seq, uoff_t log_file_offset)
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber{
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber if (sync_recent && index->hdr->recent_messages_count > 0)
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn return 1;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn if (index->hdr->log_file_seq > log_file_seq ||
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber (index->hdr->log_file_seq == log_file_seq &&
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber index->hdr->log_file_int_offset >= log_file_offset &&
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber index->hdr->log_file_ext_offset >= log_file_offset)) {
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber /* already synced */
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber return mail_cache_need_compress(index->cache);
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber }
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber return 1;
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber}
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graberstatic int mail_index_sync_commit_external(struct mail_index_sync_ctx *ctx,
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber uint32_t seq, uoff_t offset)
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber{
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber int ret;
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber while ((ret = mail_transaction_log_view_next(ctx->view->log_view,
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber &ctx->hdr, &ctx->data,
8a63c0a9d9089e6365e5a696455476febed39d6aStéphane Graber NULL)) > 0) {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn if ((ctx->hdr->type & MAIL_TRANSACTION_EXTERNAL) != 0)
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn break;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn }
427bffc7a10c9015dc78ef52543f7b8cb9414359Serge Hallyn if (ret < 0)
427bffc7a10c9015dc78ef52543f7b8cb9414359Serge Hallyn return -1;
427bffc7a10c9015dc78ef52543f7b8cb9414359Serge Hallyn
427bffc7a10c9015dc78ef52543f7b8cb9414359Serge Hallyn if (ret > 0) {
427bffc7a10c9015dc78ef52543f7b8cb9414359Serge Hallyn if (mail_transaction_log_view_set(ctx->view->log_view,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn ctx->index->hdr->log_file_seq,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn ctx->index->hdr->log_file_ext_offset,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn seq, offset, MAIL_TRANSACTION_TYPE_MASK) < 0)
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn return -1;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn if (mail_index_sync_update_index(ctx, TRUE) < 0)
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn return -1;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn }
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn return 0;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn}
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
1881820ae4ff9004beef1bf7f04553580840441dSerge Hallynint mail_index_sync_begin(struct mail_index *index,
1881820ae4ff9004beef1bf7f04553580840441dSerge Hallyn struct mail_index_sync_ctx **ctx_r,
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn struct mail_index_view **view_r,
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn uint32_t log_file_seq, uoff_t log_file_offset,
853d58fdf5af0960b7b6edc9dea0fadddb8535f1Elan Ruusamäe int sync_recent, int sync_dirty)
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn{
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn struct mail_index_sync_ctx *ctx;
1897e3bcd36af9f3fe6d3649910a9adb93e5e988Serge Hallyn uint32_t seq;
1881820ae4ff9004beef1bf7f04553580840441dSerge Hallyn uoff_t offset;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn unsigned int lock_id;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn int seen_external;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn if (mail_transaction_log_sync_lock(index->log, &seq, &offset) < 0)
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn return -1;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser if (mail_index_lock_shared(index, TRUE, &lock_id) < 0) {
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn mail_transaction_log_sync_unlock(index->log);
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn return -1;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn }
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn if (index->mmap_disable) {
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn if (index->sync_log_file_seq != seq ||
b942e67226af9e690bd63ac440b99aedb6becbb3Scott Moser index->sync_log_file_offset != offset) {
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn /* we may have synced our internal view more than what
b942e67226af9e690bd63ac440b99aedb6becbb3Scott Moser is synced in index. re-read the whole index if our
b942e67226af9e690bd63ac440b99aedb6becbb3Scott Moser sync seq/offset doesn't match what is in index's
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn header. */
4759162d078d86628956cae4846c6efccf548e67Serge Hallyn if (mail_index_map(index, TRUE) <= 0) {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn mail_transaction_log_sync_unlock(index->log);
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn mail_index_unlock(index, lock_id);
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn return -1;
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn }
b942e67226af9e690bd63ac440b99aedb6becbb3Scott Moser } else {
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn /* the whole log file is synced already. */
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn i_assert(index->map->hdr.log_file_seq == seq);
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn i_assert(index->map->hdr.log_file_ext_offset == offset);
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn }
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn } else {
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn if (mail_index_map(index, FALSE) <= 0) {
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn mail_transaction_log_sync_unlock(index->log);
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn mail_index_unlock(index, lock_id);
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn return -1;
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn }
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn }
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn if (!mail_index_need_lock(index, sync_recent,
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn log_file_seq, log_file_offset)) {
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn mail_index_unlock(index, lock_id);
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn mail_transaction_log_sync_unlock(index->log);
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn return 0;
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn }
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn
edd3810e951ec1b20af761955e6100ab75a66534Serge Hallyn ctx = i_new(struct mail_index_sync_ctx, 1);
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn ctx->index = index;
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn ctx->lock_id = lock_id;
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn ctx->sync_dirty = sync_dirty;
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn ctx->view = mail_index_view_open(index);
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn if (mail_transaction_log_view_set(ctx->view->log_view,
9c3bc32c5789b76b8c42b75d7625377d61e052c1Stéphane Graber index->hdr->log_file_seq,
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn index->hdr->log_file_int_offset,
9c3bc32c5789b76b8c42b75d7625377d61e052c1Stéphane Graber seq, offset,
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn MAIL_TRANSACTION_TYPE_MASK) < 0) {
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn mail_index_sync_rollback(ctx);
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn return -1;
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn }
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn /* See if there are some external transactions which were
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn written to transaction log, but weren't yet committed to
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn index. commit them first to avoid conflicts with another
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn external sync.
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn This is mostly needed to make sure there won't be multiple
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn appends with same UIDs, because those would cause
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn transaction log to be marked corrupted.
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn Note that any internal transactions must not be committed
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn yet. They need to be synced with the real mailbox first. */
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn if (seq != index->hdr->log_file_seq ||
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn offset != index->hdr->log_file_ext_offset) {
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn if (mail_index_sync_commit_external(ctx, seq, offset) < 0) {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn mail_index_sync_rollback(ctx);
b942e67226af9e690bd63ac440b99aedb6becbb3Scott Moser return -1;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn }
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn if (mail_transaction_log_view_set(ctx->view->log_view,
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn index->hdr->log_file_seq,
f1ccde27c038e7fb7e538913505248b36ddd9e65Serge Hallyn index->hdr->log_file_int_offset,
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn seq, offset,
3eecde703e9ac3af788ac17357f378d6b6d7c658Serge Hallyn MAIL_TRANSACTION_TYPE_MASK) < 0) {
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn mail_index_sync_rollback(ctx);
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn return -1;
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn }
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn }
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn /* we need to have all the transactions sorted to optimize
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn caller's mailbox access patterns */
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn ctx->expunges_buf = buffer_create_dynamic(default_pool, 1024);
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn ctx->updates_buf = buffer_create_dynamic(default_pool, 1024);
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn if (mail_index_sync_read_and_sort(ctx, sync_recent,
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn &seen_external) < 0) {
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn mail_index_sync_rollback(ctx);
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser return -1;
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn }
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn *ctx_r = ctx;
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser *view_r = ctx->view;
1aad9e44d65e7c20dabc4c99f57bcf532db66c68Serge Hallyn return 1;
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallyn}
42ff5f0f8767114d060f5031055038a1a1c3759aSerge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallynvoid
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Mosermail_index_sync_get_expunge(struct mail_index_sync_rec *rec,
65d8ae9c4a66f5ca85289c02dc06d63261c84619Scott Moser const struct mail_transaction_expunge *exp)
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn{
c01c25fcdd1e0cacad8075bcfcef4c8e8d4b8cb6Stéphane Graber rec->type = MAIL_INDEX_SYNC_TYPE_EXPUNGE;
c01c25fcdd1e0cacad8075bcfcef4c8e8d4b8cb6Stéphane Graber rec->uid1 = exp->uid1;
c01c25fcdd1e0cacad8075bcfcef4c8e8d4b8cb6Stéphane Graber rec->uid2 = exp->uid2;
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn}
57d116ab501594c2e50ab45f1cf2fae48c5eab09Serge Hallyn
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallynvoid
d1458ac8d13880f83fa2d1e08623b97c50d311d7Serge Hallynmail_index_sync_get_update(struct mail_index_sync_rec *rec,
b942e67226af9e690bd63ac440b99aedb6becbb3Scott Moser const struct mail_transaction_flag_update *update)
b942e67226af9e690bd63ac440b99aedb6becbb3Scott Moser{
rec->type = MAIL_INDEX_SYNC_TYPE_FLAGS;
rec->uid1 = update->uid1;
rec->uid2 = update->uid2;
rec->add_flags = update->add_flags;
memcpy(rec->add_keywords, update->add_keywords,
sizeof(rec->add_keywords));
rec->remove_flags = update->remove_flags;
memcpy(rec->remove_keywords, update->remove_keywords,
sizeof(rec->remove_keywords));
}
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:
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 FALSE;
}
break;
case MAIL_INDEX_SYNC_TYPE_APPEND:
break;
}
return TRUE;
}
int mail_index_sync_next(struct mail_index_sync_ctx *ctx,
struct mail_index_sync_rec *sync_rec)
{
const struct mail_transaction_expunge *next_exp;
const struct mail_transaction_flag_update *next_update;
next_exp = ctx->expunge_idx == ctx->expunges_count ? NULL :
&ctx->expunges[ctx->expunge_idx];
next_update = ctx->update_idx == ctx->updates_count ? NULL :
&ctx->updates[ctx->update_idx];
if (next_update != NULL &&
(next_exp == NULL || next_update->uid1 < next_exp->uid1)) {
mail_index_sync_get_update(sync_rec, next_update);
if (next_exp != NULL && next_exp->uid1 <= next_update->uid2) {
/* it's overlapping with next expunge */
sync_rec->uid2 = next_exp->uid1-1;
}
if (sync_rec->uid1 < ctx->next_uid) {
/* overlapping with previous expunge */
if (ctx->next_uid > sync_rec->uid2) {
/* hide this update completely */
ctx->update_idx++;
return mail_index_sync_next(ctx, sync_rec);
}
sync_rec->uid1 = ctx->next_uid;
}
i_assert(sync_rec->uid1 <= sync_rec->uid2);
ctx->update_idx++;
return mail_index_sync_rec_check(ctx->view, sync_rec);
}
if (next_exp != NULL) {
mail_index_sync_get_expunge(sync_rec, next_exp);
if (mail_index_sync_rec_check(ctx->view, sync_rec) < 0)
return -1;
ctx->expunge_idx++;
ctx->next_uid = next_exp->uid2+1;
return 1;
}
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;
}
int mail_index_sync_have_more(struct mail_index_sync_ctx *ctx)
{
return (ctx->update_idx != ctx->updates_count) ||
(ctx->expunge_idx != ctx->expunges_count) ||
ctx->sync_appends;
}
static void mail_index_sync_end(struct mail_index_sync_ctx *ctx)
{
mail_index_unlock(ctx->index, ctx->lock_id);
i_assert(!ctx->index->map->write_to_disk);
mail_transaction_log_sync_unlock(ctx->index->log);
mail_index_view_close(ctx->view);
if (ctx->expunges_buf != NULL)
buffer_free(ctx->expunges_buf);
if (ctx->updates_buf != NULL)
buffer_free(ctx->updates_buf);
i_free(ctx);
}
int mail_index_sync_commit(struct mail_index_sync_ctx *ctx)
{
struct mail_index *index = ctx->index;
const struct mail_index_header *hdr;
uint32_t seq, seq2;
uoff_t offset, offset2;
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)) {
if (mail_transaction_log_view_set(ctx->view->log_view,
hdr->log_file_seq, hdr->log_file_int_offset,
seq, offset, MAIL_TRANSACTION_TYPE_MASK) < 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 (mail_cache_compress(index->cache, ctx->view) < 0)
ret = -1;
else {
/* cache_offsets have changed, sync them */
mail_transaction_log_get_head(index->log,
&seq2, &offset2);
if (mail_transaction_log_view_set(ctx->view->log_view,
seq, offset, seq2, offset2,
MAIL_TRANSACTION_TYPE_MASK) < 0)
ret = -1;
else if (mail_index_sync_update_index(ctx, FALSE) < 0)
ret = -1;
}
}
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, keywords_mask_t keywords)
{
int i;
i_assert(sync_rec->type == MAIL_INDEX_SYNC_TYPE_FLAGS);
*flags = (*flags & ~sync_rec->remove_flags) | sync_rec->add_flags;
for (i = 0; i < INDEX_KEYWORDS_BYTE_COUNT; i++) {
keywords[i] = (keywords[i] & ~sync_rec->remove_keywords[i]) |
sync_rec->add_keywords[i];
}
}