int dsync_brain_sync_mailbox_open(struct dsync_brain *brain,
const struct dsync_mailbox *remote_dsync_box)
{
+ struct mailbox_status status;
enum dsync_mailbox_exporter_flags exporter_flags = 0;
uint32_t last_common_uid, highest_wanted_uid;
uint64_t last_common_modseq, last_common_pvt_modseq;
+ int ret;
i_assert(brain->log_scan == NULL);
i_assert(brain->box_exporter == NULL);
last_common_pvt_modseq = brain->mailbox_state.last_common_pvt_modseq;
highest_wanted_uid = last_common_uid == 0 ?
(uint32_t)-1 : last_common_uid;
- if (dsync_transaction_log_scan_init(brain->box->view,
- brain->box->view_pvt,
- highest_wanted_uid,
- last_common_modseq,
- last_common_pvt_modseq,
- &brain->log_scan) < 0) {
+ ret = dsync_transaction_log_scan_init(brain->box->view,
+ brain->box->view_pvt,
+ highest_wanted_uid,
+ last_common_modseq,
+ last_common_pvt_modseq,
+ &brain->log_scan);
+ if (ret < 0) {
i_error("Failed to read transaction log for mailbox %s",
mailbox_get_vname(brain->box));
brain->failed = TRUE;
return -1;
}
+ if (last_common_uid != 0) {
+ mailbox_get_open_status(brain->box, STATUS_UIDNEXT |
+ STATUS_HIGHESTMODSEQ |
+ STATUS_HIGHESTPVTMODSEQ, &status);
+ if (status.uidnext < last_common_uid ||
+ status.highest_modseq < last_common_modseq ||
+ status.highest_pvt_modseq < last_common_pvt_modseq) {
+ /* last_common_* is higher than our current ones.
+ incremental sync state is stale, we need to do
+ a full resync */
+ ret = 0;
+ }
+ }
+
if (!brain->mail_requests)
exporter_flags |= DSYNC_MAILBOX_EXPORTER_FLAG_AUTO_EXPORT_MAILS;
if (remote_dsync_box->have_save_guids &&
last_common_uid,
exporter_flags);
dsync_brain_sync_mailbox_init_remote(brain, remote_dsync_box);
- return 0;
+ if (ret == 0) {
+ i_warning("Failed to do incremental sync for mailbox %s, "
+ "retry with a full sync",
+ mailbox_get_vname(brain->box));
+ brain->changes_during_sync = TRUE;
+ brain->require_full_resync = TRUE;
+ return 0;
+ }
+ return 1;
}
void dsync_brain_sync_mailbox_deinit(struct dsync_brain *brain)
{
i_assert(brain->box != NULL);
+ if (brain->require_full_resync) {
+ brain->mailbox_state.last_uidvalidity = 0;
+ brain->require_full_resync = FALSE;
+ }
array_append(&brain->remote_mailbox_states, &brain->mailbox_state, 1);
if (brain->box_exporter != NULL) {
const char *error;
}
}
-void dsync_brain_mailbox_update_pre(struct dsync_brain *brain,
+bool dsync_brain_mailbox_update_pre(struct dsync_brain *brain,
struct mailbox *box,
const struct dsync_mailbox *local_box,
const struct dsync_mailbox *remote_box)
{
struct mailbox_update update;
const struct dsync_mailbox_state *state;
+ bool ret = TRUE;
memset(&update, 0, sizeof(update));
session, because the other side already started
sending mailbox changes, but not for all mails. */
dsync_mailbox_state_remove(brain, local_box->mailbox_guid);
- // FIXME: handle this properly
+ ret = FALSE;
}
}
if (update.uid_validity == 0 &&
update.cache_updates == NULL) {
/* no changes */
- return;
+ return ret;
}
if (mailbox_update(box, &update) < 0) {
mailbox_get_last_error(box, NULL));
brain->failed = TRUE;
}
+ return ret;
}
static void
struct mailbox *box;
const char *error;
int ret;
+ bool resync;
i_assert(!brain->master_brain);
i_assert(brain->box == NULL);
{
const struct dsync_mailbox *dsync_box;
enum dsync_ibc_recv_ret ret;
+ bool resync;
i_assert(brain->master_brain);
if (dsync_box->mailbox_lost) {
/* remote lost the mailbox. it's probably already deleted, but
verify it on next sync just to be sure */
+ brain->changes_during_sync = TRUE;
+ brain->require_full_resync = TRUE;
dsync_brain_sync_mailbox_deinit(brain);
return TRUE;
}
- dsync_brain_mailbox_update_pre(brain, brain->box,
- &brain->local_dsync_box, dsync_box);
+ resync = !dsync_brain_mailbox_update_pre(brain, brain->box,
+ &brain->local_dsync_box,
+ dsync_box);
if (!dsync_boxes_need_sync(brain, &brain->local_dsync_box, dsync_box)) {
/* no fields appear to have changed, skip this mailbox */
dsync_brain_sync_mailbox_deinit(brain);
return TRUE;
}
- if (dsync_brain_sync_mailbox_open(brain, dsync_box) < 0)
+ if ((ret = dsync_brain_sync_mailbox_open(brain, dsync_box)) < 0)
return TRUE;
+ if (ret == 0 || resync) {
+ brain->changes_during_sync = TRUE;
+ brain->require_full_resync = TRUE;
+ }
dsync_brain_sync_init_box_states(brain);
return TRUE;
}
unsigned int no_mail_sync:1;
unsigned int no_backup_overwrite:1;
unsigned int changes_during_sync:1;
+ unsigned int require_full_resync:1;
unsigned int verbose_proctitle:1;
unsigned int failed:1;
};
void dsync_brain_sync_mailbox_deinit(struct dsync_brain *brain);
int dsync_brain_mailbox_alloc(struct dsync_brain *brain, const guid_128_t guid,
struct mailbox **box_r, const char **error_r);
-void dsync_brain_mailbox_update_pre(struct dsync_brain *brain,
+bool dsync_brain_mailbox_update_pre(struct dsync_brain *brain,
struct mailbox *box,
const struct dsync_mailbox *local_box,
const struct dsync_mailbox *remote_box);
view->index->filepath, log_seq, end_seq);
ret = -1;
}
- return ret < 0 ? -1 : 0;
+ if (ret < 0)
+ return -1;
+ if (modseq != 0) {
+ /* we didn't see all the changes that we wanted to */
+ return 0;
+ }
+ return 1;
}
static int
uint32_t file_seq, max_seq;
uoff_t file_offset, max_offset;
uint64_t cur_modseq;
+ int ret;
log_view = mail_transaction_log_view_open(view->index->log);
- if (dsync_log_set(ctx, view, pvt_scan, log_view, modseq) < 0) {
+ if ((ret = dsync_log_set(ctx, view, pvt_scan, log_view, modseq)) < 0) {
mail_transaction_log_view_close(&log_view);
return -1;
}
ctx->last_log_offset = file_offset;
}
mail_transaction_log_view_close(&log_view);
- return 0;
+ return ret;
}
static int
{
struct dsync_transaction_log_scan *ctx;
pool_t pool;
+ int ret, ret2;
pool = pool_alloconly_create(MEMPOOL_GROWING"dsync transaction log scan",
10240);
ctx->view = view;
ctx->highest_wanted_uid = highest_wanted_uid;
- if (dsync_log_scan(ctx, view, modseq, FALSE) < 0)
+ if ((ret = dsync_log_scan(ctx, view, modseq, FALSE)) < 0)
return -1;
if (pvt_view != NULL) {
- if (dsync_log_scan(ctx, pvt_view, pvt_modseq, TRUE) < 0)
+ if ((ret2 = dsync_log_scan(ctx, pvt_view, pvt_modseq, TRUE)) < 0)
return -1;
+ if (ret2 == 0)
+ ret = 0;
}
*scan_r = ctx;
- return 0;
+ return ret;
}
HASH_TABLE_TYPE(dsync_uid_mail_change)