bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
de3175adb4094086dc8ba13132a39567f9c42e54Timo Sirainenns_mailbox_try_alloc(struct dsync_brain *brain, struct mail_namespace *ns,
de3175adb4094086dc8ba13132a39567f9c42e54Timo Sirainen const guid_128_t guid, struct mailbox **box_r,
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainen const char **errstr_r, enum mail_error *error_r)
de3175adb4094086dc8ba13132a39567f9c42e54Timo Sirainen /* make sure mailbox isn't modified */
de3175adb4094086dc8ba13132a39567f9c42e54Timo Sirainen box = mailbox_alloc_guid(ns->list, guid, flags);
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi *errstr_r = mailbox_get_last_internal_error(box, error_r);
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainen *errstr_r = existence == MAILBOX_EXISTENCE_NONE ?
ec047a9c54a02338e85fb1767120b0923f6d4148Timo Sirainen "Mailbox was already deleted" :
ec047a9c54a02338e85fb1767120b0923f6d4148Timo Sirainen "Mailbox is no longer selectable";
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenint dsync_brain_mailbox_alloc(struct dsync_brain *brain, const guid_128_t guid,
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainen struct mailbox **box_r, const char **errstr_r,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (ns = brain->user->namespaces; ns != NULL; ns = ns->next) {
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainen if ((ret = ns_mailbox_try_alloc(brain, ns, guid, box_r,
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainendsync_mailbox_cache_field_dup(ARRAY_TYPE(mailbox_cache_field) *dest,
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen dest_field->name = p_strdup(pool, src_field->name);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic const struct dsync_mailbox_state *
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_state_find(struct dsync_brain *brain,
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen return hash_table_lookup(brain->mailbox_states, guid_p);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_state_remove(struct dsync_brain *brain,
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen if (hash_table_lookup(brain->mailbox_states, guid_p) != NULL)
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen hash_table_remove(brain->mailbox_states, guid_p);
e83126866761632b437e532dfdc30be01d14039dTimo Sirainenvoid dsync_brain_sync_init_box_states(struct dsync_brain *brain)
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen /* we have an exporter, but no importer. */
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen brain->box_send_state = DSYNC_BOX_STATE_ATTRIBUTES;
887a9fbbb2ca6afd53365ba2ccae0ef8728d6948Timo Sirainen brain->box_recv_state = brain->mail_requests ?
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen /* we have an importer, but no exporter */
887a9fbbb2ca6afd53365ba2ccae0ef8728d6948Timo Sirainen brain->box_send_state = brain->mail_requests ?
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen brain->box_recv_state = DSYNC_BOX_STATE_ATTRIBUTES;
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen brain->box_send_state = DSYNC_BOX_STATE_ATTRIBUTES;
55d33f807765482eb47374aaaced1fe714e0b256Timo Sirainen brain->box_recv_state = DSYNC_BOX_STATE_ATTRIBUTES;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_brain_sync_mailbox_init(struct dsync_brain *brain,
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen brain->box_send_state = DSYNC_BOX_STATE_MAILBOX;
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen brain->box_recv_state = DSYNC_BOX_STATE_MAILBOX;
33bd898e7756b289e65f43133312d9637afc1371Timo Sirainen pool_alloconly_create(MEMPOOL_GROWING"dsync brain box pool", 2048);
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen dsync_mailbox_cache_field_dup(&brain->local_dsync_box.cache_fields,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen state = dsync_mailbox_state_find(brain, local_dsync_box->mailbox_guid);
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainendsync_brain_sync_mailbox_init_remote(struct dsync_brain *brain,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen enum dsync_mailbox_import_flags import_flags = 0;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen uint64_t last_common_modseq, last_common_pvt_modseq;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(memcmp(brain->local_dsync_box.mailbox_guid,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen sizeof(remote_dsync_box->mailbox_guid)) == 0);
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen dsync_mailbox_cache_field_dup(&brain->remote_dsync_box.cache_fields,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen state = dsync_mailbox_state_find(brain, remote_dsync_box->mailbox_guid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen last_common_modseq = state->last_common_modseq;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen last_common_pvt_modseq = state->last_common_pvt_modseq;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen import_flags |= DSYNC_MAILBOX_IMPORT_FLAG_WANT_MAIL_REQUESTS;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen import_flags |= DSYNC_MAILBOX_IMPORT_FLAG_MASTER_BRAIN;
36723cf206a7b64b9d972ab0719bbfaacc9316faTimo Sirainen if (brain->backup_recv && !brain->no_backup_overwrite)
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen import_flags |= DSYNC_MAILBOX_IMPORT_FLAG_REVERT_LOCAL_CHANGES;
307ec6c2c319e3335ddb1a7aca2d2884fe17fae0Timo Sirainen import_flags |= DSYNC_MAILBOX_IMPORT_FLAG_DEBUG;
14f6fe5d6c4834f273ca573c23c0659a93123363Timo Sirainen (brain->backup_recv && remote_dsync_box->have_guids)))
975a784c2e02ecdcb56efb7a1db5e4769c7756d8Timo Sirainen import_flags |= DSYNC_MAILBOX_IMPORT_FLAG_MAILS_HAVE_GUIDS;
d1e843e77f4760e303c53d9fce10123fc8d230a1Timo Sirainen if (brain->local_dsync_box.have_only_guid128 ||
d1e843e77f4760e303c53d9fce10123fc8d230a1Timo Sirainen import_flags |= DSYNC_MAILBOX_IMPORT_FLAG_MAILS_USE_GUID128;
14b1d2a2634e75b988078baee1e8ad678de28a04Timo Sirainen import_flags |= DSYNC_MAILBOX_IMPORT_FLAG_NO_NOTIFY;
afd6d387ea65843b59fb6051fb567719d2a5279cAki Tuomi import_flags |= DSYNC_MAILBOX_IMPORT_FLAG_EMPTY_HDR_WORKAROUND;
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen brain->box_importer = brain->backup_send ? NULL :
70df8f39fb3db7c49b18c855178f8172176a037aTimo Sirainen dsync_mailbox_import_init(brain->box, brain->virtual_all_box,
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainenint dsync_brain_sync_mailbox_open(struct dsync_brain *brain,
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen enum dsync_mailbox_exporter_flags exporter_flags = 0;
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen uint64_t last_common_modseq, last_common_pvt_modseq;
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen last_common_uid = brain->mailbox_state.last_common_uid;
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen last_common_modseq = brain->mailbox_state.last_common_modseq;
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen last_common_pvt_modseq = brain->mailbox_state.last_common_pvt_modseq;
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainen ret = dsync_transaction_log_scan_init(brain->box->view,
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen i_error("Failed to read transaction log for mailbox %s",
328ac493fb40b35a6e1d618bd87ffa0e02f4764fTimo Sirainen mailbox_get_open_status(brain->box, STATUS_UIDNEXT |
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi "Private modseq %"PRIu64" no longer in transaction log "
328ac493fb40b35a6e1d618bd87ffa0e02f4764fTimo Sirainen "(highest=%"PRIu64", last_common_uid=%u, nextuid=%u)",
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi "Modseq %"PRIu64" no longer in transaction log "
328ac493fb40b35a6e1d618bd87ffa0e02f4764fTimo Sirainen "(highest=%"PRIu64", last_common_uid=%u, nextuid=%u)",
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen /* if last_common_* is higher than our current ones it means
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen that the incremental sync state is stale and we need to do
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen a full resync */
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen desync_reason = t_strdup_printf("uidnext %u < %u",
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen } else if (status.highest_modseq < last_common_modseq) {
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi desync_reason = t_strdup_printf("highest_modseq %"PRIu64" < %"PRIu64,
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi status.highest_modseq, last_common_modseq);
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen } else if (status.highest_pvt_modseq < last_common_pvt_modseq) {
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi desync_reason = t_strdup_printf("highest_pvt_modseq %"PRIu64" < %"PRIu64,
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi status.highest_pvt_modseq, last_common_pvt_modseq);
464e82904c6670bd6c96b8793ceb294d776d6f44Timo Sirainen i_warning("Failed to do incremental sync for mailbox %s, "
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen "retry with a full sync (%s)",
70058d29cf8c77501741ddbc39178cfc87ca459eTimo Sirainen mailbox_get_vname(brain->box), desync_reason);
4f7951e71128c120d8a502d6406cc603fcc8eb0bTimo Sirainen dsync_brain_set_changes_during_sync(brain, t_strdup_printf(
4f7951e71128c120d8a502d6406cc603fcc8eb0bTimo Sirainen "Incremental sync failed: %s", desync_reason));
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen exporter_flags |= DSYNC_MAILBOX_EXPORTER_FLAG_AUTO_EXPORT_MAILS;
14f6fe5d6c4834f273ca573c23c0659a93123363Timo Sirainen (brain->backup_send && brain->local_dsync_box.have_guids)))
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen exporter_flags |= DSYNC_MAILBOX_EXPORTER_FLAG_MAILS_HAVE_GUIDS;
d519a0449d0e536a32db93305516fdbd7db6773dTimo Sirainen exporter_flags |= DSYNC_MAILBOX_EXPORTER_FLAG_MINIMAL_DMAIL_FILL;
3561c7bb472a78af74d755219cc0fc71c85ff5c2Timo Sirainen exporter_flags |= DSYNC_MAILBOX_EXPORTER_FLAG_TIMESTAMPS;
ae949831f1f668b5501b4b125e7f7b1767fb109bTimo Sirainen exporter_flags |= DSYNC_MAILBOX_EXPORTER_FLAG_VSIZES;
03af8e5325a7b4fec36414ac35949457bc426c0bTimo Sirainen /* remote mailbox is empty - we don't really need to export
03af8e5325a7b4fec36414ac35949457bc426c0bTimo Sirainen header hashes since they're not going to match anything
03af8e5325a7b4fec36414ac35949457bc426c0bTimo Sirainen exporter_flags |= DSYNC_MAILBOX_EXPORTER_FLAG_NO_HDR_HASHES;
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen brain->box_exporter = brain->backup_recv ? NULL :
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen dsync_mailbox_export_init(brain->box, brain->log_scan,
979d89c147520f2934c14c31aeb9310fd2d62a46Timo Sirainen dsync_brain_sync_mailbox_init_remote(brain, remote_dsync_box);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenvoid dsync_brain_sync_mailbox_deinit(struct dsync_brain *brain)
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen array_append(&brain->remote_mailbox_states, &brain->mailbox_state, 1);
f43ce62fa945f597e8a48e09c53d46dcc95445d4Timo Sirainen i_assert(brain->failed || brain->require_full_resync ||
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen brain->sync_type == DSYNC_BRAIN_SYNC_TYPE_CHANGED);
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainen if (dsync_mailbox_export_deinit(&brain->box_exporter,
7d315281ae13a66e13da2b1ad006bdb883018278Timo Sirainen uint32_t last_common_uid, last_messages_count;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen uint64_t last_common_modseq, last_common_pvt_modseq;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen (void)dsync_mailbox_import_deinit(&brain->box_importer,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_transaction_log_scan_deinit(&brain->log_scan);
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainenstatic int dsync_box_get(struct mailbox *box, struct dsync_mailbox *dsync_box_r,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const enum mailbox_status_items status_items =
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen STATUS_UIDVALIDITY | STATUS_UIDNEXT | STATUS_MESSAGES |
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen STATUS_FIRST_RECENT_UID | STATUS_HIGHESTMODSEQ |
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const enum mailbox_metadata_items metadata_items =
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen MAILBOX_METADATA_CACHE_FIELDS | MAILBOX_METADATA_GUID;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* get metadata first, since it may autocreate the mailbox */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mailbox_get_metadata(box, metadata_items, &metadata) < 0 ||
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_get_status(box, status_items, &status) < 0) {
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi errstr = mailbox_get_last_internal_error(box, &error);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* Mailbox isn't selectable, try the next one. We
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen should have already caught \Noselect mailboxes, but
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen check them anyway here. The NOTPOSSIBLE check is
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mainly for invalid mbox files. */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(status.uidvalidity != 0 || status.messages == 0);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen memcpy(dsync_box_r->mailbox_guid, metadata.guid,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_box_r->uid_validity = status.uidvalidity;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_box_r->messages_count = status.messages;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_box_r->first_recent_uid = status.first_recent_uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_box_r->highest_modseq = status.highest_modseq;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen dsync_box_r->highest_pvt_modseq = status.highest_pvt_modseq;
9f240e2ce97176146b63506a8ee04034f712cf45Timo Sirainen dsync_mailbox_cache_field_dup(&dsync_box_r->cache_fields,
14f6fe5d6c4834f273ca573c23c0659a93123363Timo Sirainen dsync_box_r->have_save_guids = status.have_save_guids;
cce2c665bb24537bb691f6cad6a36f8080e4a552Timo Sirainen dsync_box_r->have_only_guid128 = status.have_only_guid128;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_brain_has_mailbox_state_changed(struct dsync_brain *brain,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (brain->sync_type != DSYNC_BRAIN_SYNC_TYPE_STATE)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen state = dsync_mailbox_state_find(brain, dsync_box->mailbox_guid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen state->last_uidvalidity != dsync_box->uid_validity ||
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen state->last_common_uid+1 != dsync_box->uid_next ||
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen state->last_common_modseq != dsync_box->highest_modseq ||
7d315281ae13a66e13da2b1ad006bdb883018278Timo Sirainen state->last_common_pvt_modseq != dsync_box->highest_pvt_modseq ||
7d315281ae13a66e13da2b1ad006bdb883018278Timo Sirainen state->last_messages_count != dsync_box->messages_count;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_brain_try_next_mailbox(struct dsync_brain *brain, struct mailbox **box_r,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen while (dsync_mailbox_tree_iter_next(brain->local_tree_iter, &vname, &node)) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (node->existence == DSYNC_MAILBOX_NODE_EXISTS &&
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* no more mailboxes */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_tree_iter_deinit(&brain->local_tree_iter);
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen /* make sure mailbox isn't modified */
e83126866761632b437e532dfdc30be01d14039dTimo Sirainen box = mailbox_alloc(node->ns->list, vname, flags);
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainen if ((ret = dsync_box_get(box, &dsync_box, &error)) <= 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* if mailbox's last_common_* state equals the current state,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen we can skip the mailbox */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (!dsync_brain_has_mailbox_state_changed(brain, &dsync_box)) {
e475db821baf0c4680dec4441d033697ecebfe06Timo Sirainen i_debug("brain %c: Skipping mailbox %s with unchanged state "
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi "uidvalidity=%u uidnext=%u highestmodseq=%"PRIu64" highestpvtmodseq=%"PRIu64" messages=%u",
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* ok, the mailbox really changed */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* mailbox appears to have changed. do a full sync here and get the
c864fdd520b0c3f10a4b9bc5373368f4ae8faaffTimo Sirainen state again. Lock before syncing. */
c864fdd520b0c3f10a4b9bc5373368f4ae8faaffTimo Sirainen if (dsync_mailbox_lock(brain, box, &lock) < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) {
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, &brain->mail_error));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_brain_next_mailbox(struct dsync_brain *brain, struct mailbox **box_r,
c864fdd520b0c3f10a4b9bc5373368f4ae8faaffTimo Sirainen while ((ret = dsync_brain_try_next_mailbox(brain, box_r, lock_r, dsync_box_r)) == 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenvoid dsync_brain_master_send_mailbox(struct dsync_brain *brain)
c864fdd520b0c3f10a4b9bc5373368f4ae8faaffTimo Sirainen if (!dsync_brain_next_mailbox(brain, &box, &lock, &dsync_box)) {
b8e6e314eb2f9f1fc8ce2999034321bfeb7a2269Timo Sirainen dsync_ibc_send_end_of_list(brain->ibc, DSYNC_IBC_EOL_MAILBOX);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* start exporting this mailbox (wait for remote to start importing) */
a85473f7c11c8734bdee9c2cbe4b767f144a18aaTimo Sirainen dsync_ibc_send_mailbox(brain->ibc, &dsync_box);
c864fdd520b0c3f10a4b9bc5373368f4ae8faaffTimo Sirainen dsync_brain_sync_mailbox_init(brain, box, lock, &dsync_box, TRUE);
f48fdb57185ca68e8c079e174f3e04da36646880Timo Sirainenbool dsync_boxes_need_sync(struct dsync_brain *brain,
f48fdb57185ca68e8c079e174f3e04da36646880Timo Sirainen if (brain->sync_type != DSYNC_BRAIN_SYNC_TYPE_CHANGED)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return box1->highest_modseq != box2->highest_modseq ||
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen box1->highest_pvt_modseq != box2->highest_pvt_modseq ||
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen box1->messages_count != box2->messages_count ||
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen box1->first_recent_uid != box2->first_recent_uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenmailbox_cache_field_name_cmp(const struct mailbox_cache_field *f1,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_cache_fields_update(const struct dsync_mailbox *local_box,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ARRAY_TYPE(mailbox_cache_field) local_sorted, remote_sorted, changes;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct mailbox_cache_field *local_fields, *remote_fields;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int li, ri, local_count, remote_count;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (array_count(&remote_box->cache_fields) == 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* remote has no cached fields. there's nothing to update. */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen t_array_init(&local_sorted, array_count(&local_box->cache_fields));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen t_array_init(&remote_sorted, array_count(&remote_box->cache_fields));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_append_array(&local_sorted, &local_box->cache_fields);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_append_array(&remote_sorted, &remote_box->cache_fields);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_sort(&local_sorted, mailbox_cache_field_name_cmp);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_sort(&remote_sorted, mailbox_cache_field_name_cmp);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* local has no cached fields. set them to same as remote. */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen update->cache_updates = array_idx(&remote_sorted, 0);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* figure out what to change */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen local_fields = array_get(&local_sorted, &local_count);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen remote_fields = array_get(&remote_sorted, &remote_count);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen t_array_init(&changes, local_count + remote_count);
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen box->index->optimization_set.cache.unaccessed_field_drop_secs;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (li = ri = 0; li < local_count || ri < remote_count; ) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen strcmp(local_fields[li].name, remote_fields[ri].name);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* field exists in both local and remote */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct mailbox_cache_field *lf = &local_fields[li];
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct mailbox_cache_field *rf = &remote_fields[ri];
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* use local decision and timestamp */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else if (ret < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* remote field doesn't exist */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* local field doesn't exist */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (remote_fields[ri].last_used < drop_older_timestamp) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* field hasn't be used for a long time, remote
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen will probably drop this soon as well */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_append(&changes, &remote_fields[ri], 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(li == local_count && ri == remote_count);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen update->cache_updates = array_idx(&changes, 0);
40440c0fee87be994ba7eb60fc3512a9355708aaTimo Sirainenbool dsync_brain_mailbox_update_pre(struct dsync_brain *brain,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (local_box->uid_validity != remote_box->uid_validity) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* Keep the UIDVALIDITY for the mailbox that has more
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen messages. If they equal, use the higher UIDVALIDITY. */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (remote_box->messages_count > local_box->messages_count ||
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen (remote_box->messages_count == local_box->messages_count &&
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen remote_box->uid_validity > local_box->uid_validity))
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen update.uid_validity = remote_box->uid_validity;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen state = dsync_mailbox_state_find(brain, local_box->mailbox_guid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (state != NULL && state->last_common_uid > 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* we can't continue syncing this mailbox in this
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen session, because the other side already started
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen sending mailbox changes, but not for all mails. */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_state_remove(brain, local_box->mailbox_guid);
4f7951e71128c120d8a502d6406cc603fcc8eb0bTimo Sirainen *reason_r = "UIDVALIDITY changed during a stateful sync, need to restart";
67bbcd664bebce9a507a49c67273be4814d07c97Timo Sirainen dsync_cache_fields_update(local_box, remote_box, box, &update);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* no changes */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_error("Couldn't update mailbox %s metadata: %s",
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, &brain->mail_error));
e0c10ab25f82f3b5b099de5d84ece39efd18bc6aTimo Sirainendsync_brain_slave_send_mailbox_lost(struct dsync_brain *brain,
e0c10ab25f82f3b5b099de5d84ece39efd18bc6aTimo Sirainen memcpy(delete_box.mailbox_guid, dsync_box->mailbox_guid,
e0c10ab25f82f3b5b099de5d84ece39efd18bc6aTimo Sirainen dsync_ibc_send_mailbox(brain->ibc, &delete_box);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenbool dsync_brain_slave_recv_mailbox(struct dsync_brain *brain)
a85473f7c11c8734bdee9c2cbe4b767f144a18aaTimo Sirainen if ((ret = dsync_ibc_recv_mailbox(brain->ibc, &dsync_box)) == 0)
ec047a9c54a02338e85fb1767120b0923f6d4148Timo Sirainen if (dsync_brain_mailbox_alloc(brain, dsync_box->mailbox_guid,
ec047a9c54a02338e85fb1767120b0923f6d4148Timo Sirainen i_error("Couldn't allocate mailbox GUID %s: %s",
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainen guid_128_to_string(dsync_box->mailbox_guid), errstr);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* mailbox was probably deleted/renamed during sync */
16cd2c1b487b1fb63f3081761e0d1110d61137a9Timo Sirainen if (brain->backup_send && brain->no_backup_overwrite) {
16cd2c1b487b1fb63f3081761e0d1110d61137a9Timo Sirainen "mailbox GUID %s with -1 sync",
280bc7d8b07490dfa5cf0fc20aee8e9e2d15aa99Aki Tuomi dsync_brain_slave_send_mailbox_lost(brain, dsync_box, TRUE);
e0c10ab25f82f3b5b099de5d84ece39efd18bc6aTimo Sirainen //FIXME: verify this from log, and if not log an error.
4f7951e71128c120d8a502d6406cc603fcc8eb0bTimo Sirainen dsync_brain_set_changes_during_sync(brain, t_strdup_printf(
4f7951e71128c120d8a502d6406cc603fcc8eb0bTimo Sirainen "Mailbox GUID %s was lost",
4f7951e71128c120d8a502d6406cc603fcc8eb0bTimo Sirainen guid_128_to_string(dsync_box->mailbox_guid)));
280bc7d8b07490dfa5cf0fc20aee8e9e2d15aa99Aki Tuomi dsync_brain_slave_send_mailbox_lost(brain, dsync_box, FALSE);
c864fdd520b0c3f10a4b9bc5373368f4ae8faaffTimo Sirainen /* Lock before syncing */
c864fdd520b0c3f10a4b9bc5373368f4ae8faaffTimo Sirainen if (dsync_mailbox_lock(brain, box, &lock) < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) {
bf7dc750b95039981c0e9d728f313d50cf38a156Martti Rannanjärvi mailbox_get_last_internal_error(box, &brain->mail_error));
ce0e25f26d6e67480ee39b5ca0ad634fa60c4605Timo Sirainen if ((ret = dsync_box_get(box, &local_dsync_box, &error)) <= 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* another process just deleted this mailbox? */
280bc7d8b07490dfa5cf0fc20aee8e9e2d15aa99Aki Tuomi dsync_brain_slave_send_mailbox_lost(brain, dsync_box, FALSE);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(memcmp(dsync_box->mailbox_guid, local_dsync_box.mailbox_guid,
7d315281ae13a66e13da2b1ad006bdb883018278Timo Sirainen resync = !dsync_brain_mailbox_update_pre(brain, box, &local_dsync_box,
f48fdb57185ca68e8c079e174f3e04da36646880Timo Sirainen if (!dsync_boxes_need_sync(brain, &local_dsync_box, dsync_box)) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* no fields appear to have changed, skip this mailbox */
e475db821baf0c4680dec4441d033697ecebfe06Timo Sirainen i_debug("brain %c: Skipping unchanged mailbox %s",
464e82904c6670bd6c96b8793ceb294d776d6f44Timo Sirainen dsync_ibc_send_mailbox(brain->ibc, &local_dsync_box);
c864fdd520b0c3f10a4b9bc5373368f4ae8faaffTimo Sirainen dsync_brain_sync_mailbox_init(brain, box, lock, &local_dsync_box, FALSE);
7d315281ae13a66e13da2b1ad006bdb883018278Timo Sirainen if ((ret = dsync_brain_sync_mailbox_open(brain, dsync_box)) < 0)
4f7951e71128c120d8a502d6406cc603fcc8eb0bTimo Sirainen dsync_brain_set_changes_during_sync(brain, resync_reason);
280bc7d8b07490dfa5cf0fc20aee8e9e2d15aa99Aki Tuomi dsync_brain_slave_send_mailbox_lost(brain, dsync_box, FALSE);