1
/* Copyright (c) 2009-2012 Dovecot authors, see the included COPYING file */
6
#include "dsync-worker.h"
7
#include "dsync-brain-private.h"
11
#define DSYNC_WRONG_DIRECTION_ERROR_MSG \
13
"Looks like you're trying to run backup in wrong direction. " \
14
"Source is empty and destination is not."
17
dsync_brain_mailbox_list_deinit(struct dsync_brain_mailbox_list **list);
19
dsync_brain_subs_list_deinit(struct dsync_brain_subs_list **list);
22
dsync_brain_init(struct dsync_worker *src_worker,
23
struct dsync_worker *dest_worker,
24
const char *mailbox, enum dsync_brain_flags flags)
26
struct dsync_brain *brain;
28
brain = i_new(struct dsync_brain, 1);
29
brain->src_worker = src_worker;
30
brain->dest_worker = dest_worker;
31
brain->mailbox = i_strdup(mailbox);
33
brain->verbose = (flags & DSYNC_BRAIN_FLAG_VERBOSE) != 0;
34
brain->backup = (flags & DSYNC_BRAIN_FLAG_BACKUP) != 0;
35
brain->stdout_tty = isatty(STDOUT_FILENO) > 0;
37
if ((flags & DSYNC_BRAIN_FLAG_VERBOSE) != 0) {
38
dsync_worker_set_verbose(src_worker);
39
dsync_worker_set_verbose(dest_worker);
44
void dsync_brain_fail(struct dsync_brain *brain)
47
io_loop_stop(current_ioloop);
50
int dsync_brain_deinit(struct dsync_brain **_brain)
52
struct dsync_brain *brain = *_brain;
53
int ret = brain->failed ? -1 : 0;
55
if (brain->state != DSYNC_STATE_SYNC_END)
57
if (brain->to != NULL)
58
timeout_remove(&brain->to);
61
/* make sure we unreference save input streams before workers
62
are deinitialized, so they can destroy the streams */
63
dsync_worker_msg_save_cancel(brain->src_worker);
64
dsync_worker_msg_save_cancel(brain->dest_worker);
67
if (brain->mailbox_sync != NULL)
68
dsync_brain_msg_sync_deinit(&brain->mailbox_sync);
70
if (brain->src_mailbox_list != NULL)
71
dsync_brain_mailbox_list_deinit(&brain->src_mailbox_list);
72
if (brain->dest_mailbox_list != NULL)
73
dsync_brain_mailbox_list_deinit(&brain->dest_mailbox_list);
75
if (brain->src_subs_list != NULL)
76
dsync_brain_subs_list_deinit(&brain->src_subs_list);
77
if (brain->dest_subs_list != NULL)
78
dsync_brain_subs_list_deinit(&brain->dest_subs_list);
80
if (dsync_worker_has_failed(brain->src_worker) ||
81
dsync_worker_has_failed(brain->dest_worker))
85
i_free(brain->mailbox);
90
static void dsync_brain_mailbox_list_finished(struct dsync_brain *brain)
92
if (brain->src_mailbox_list->iter != NULL ||
93
brain->dest_mailbox_list->iter != NULL)
96
/* both lists are finished */
98
dsync_brain_sync(brain);
101
static void dsync_worker_mailbox_input(void *context)
103
struct dsync_brain_mailbox_list *list = context;
104
struct dsync_mailbox dsync_box, *dup_box;
107
while ((ret = dsync_worker_mailbox_iter_next(list->iter,
109
if (list->brain->mailbox != NULL &&
110
strcmp(list->brain->mailbox, dsync_box.name) != 0)
113
dup_box = dsync_mailbox_dup(list->pool, &dsync_box);
114
if (!dsync_mailbox_is_noselect(dup_box))
115
array_append(&list->mailboxes, &dup_box, 1);
117
array_append(&list->dirs, &dup_box, 1);
120
/* finished listing mailboxes */
121
if (dsync_worker_mailbox_iter_deinit(&list->iter) < 0)
122
dsync_brain_fail(list->brain);
123
array_sort(&list->mailboxes, dsync_mailbox_p_guid_cmp);
124
array_sort(&list->dirs, dsync_mailbox_p_name_sha1_cmp);
125
dsync_brain_mailbox_list_finished(list->brain);
129
static struct dsync_brain_mailbox_list *
130
dsync_brain_mailbox_list_init(struct dsync_brain *brain,
131
struct dsync_worker *worker)
133
struct dsync_brain_mailbox_list *list;
136
pool = pool_alloconly_create("dsync brain mailbox list", 10240);
137
list = p_new(pool, struct dsync_brain_mailbox_list, 1);
140
list->worker = worker;
141
list->iter = dsync_worker_mailbox_iter_init(worker);
142
p_array_init(&list->mailboxes, pool, 128);
143
p_array_init(&list->dirs, pool, 32);
144
dsync_worker_set_input_callback(worker, dsync_worker_mailbox_input,
150
dsync_brain_mailbox_list_deinit(struct dsync_brain_mailbox_list **_list)
152
struct dsync_brain_mailbox_list *list = *_list;
156
if (list->iter != NULL)
157
(void)dsync_worker_mailbox_iter_deinit(&list->iter);
158
pool_unref(&list->pool);
161
static void dsync_brain_subs_list_finished(struct dsync_brain *brain)
163
if (brain->src_subs_list->iter != NULL ||
164
brain->dest_subs_list->iter != NULL)
167
/* both lists are finished */
169
dsync_brain_sync(brain);
173
dsync_worker_subscription_cmp(const struct dsync_worker_subscription *s1,
174
const struct dsync_worker_subscription *s2)
176
return strcmp(s1->vname, s2->vname);
180
dsync_worker_unsubscription_cmp(const struct dsync_worker_unsubscription *u1,
181
const struct dsync_worker_unsubscription *u2)
185
ret = strcmp(u1->ns_prefix, u2->ns_prefix);
186
return ret != 0 ? ret :
187
dsync_guid_cmp(&u1->name_sha1, &u2->name_sha1);
190
static void dsync_worker_subs_input(void *context)
192
struct dsync_brain_subs_list *list = context;
193
struct dsync_worker_subscription subs;
194
struct dsync_worker_unsubscription unsubs;
197
memset(&subs, 0, sizeof(subs));
198
while ((ret = dsync_worker_subs_iter_next(list->iter, &subs)) > 0) {
199
subs.vname = p_strdup(list->pool, subs.vname);
200
subs.storage_name = p_strdup(list->pool, subs.storage_name);
201
subs.ns_prefix = p_strdup(list->pool, subs.ns_prefix);
202
array_append(&list->subscriptions, &subs, 1);
207
memset(&unsubs, 0, sizeof(unsubs));
208
while ((ret = dsync_worker_subs_iter_next_un(list->iter,
210
unsubs.ns_prefix = p_strdup(list->pool, unsubs.ns_prefix);
211
array_append(&list->unsubscriptions, &unsubs, 1);
215
/* finished listing subscriptions */
216
if (dsync_worker_subs_iter_deinit(&list->iter) < 0)
217
dsync_brain_fail(list->brain);
218
array_sort(&list->subscriptions,
219
dsync_worker_subscription_cmp);
220
array_sort(&list->unsubscriptions,
221
dsync_worker_unsubscription_cmp);
222
dsync_brain_subs_list_finished(list->brain);
226
static struct dsync_brain_subs_list *
227
dsync_brain_subs_list_init(struct dsync_brain *brain,
228
struct dsync_worker *worker)
230
struct dsync_brain_subs_list *list;
233
pool = pool_alloconly_create(MEMPOOL_GROWING"dsync brain subs list",
235
list = p_new(pool, struct dsync_brain_subs_list, 1);
238
list->worker = worker;
239
list->iter = dsync_worker_subs_iter_init(worker);
240
p_array_init(&list->subscriptions, pool, 128);
241
p_array_init(&list->unsubscriptions, pool, 64);
242
dsync_worker_set_input_callback(worker, dsync_worker_subs_input, list);
247
dsync_brain_subs_list_deinit(struct dsync_brain_subs_list **_list)
249
struct dsync_brain_subs_list *list = *_list;
253
if (list->iter != NULL)
254
(void)dsync_worker_subs_iter_deinit(&list->iter);
255
pool_unref(&list->pool);
258
enum dsync_brain_mailbox_action {
259
DSYNC_BRAIN_MAILBOX_ACTION_NONE,
260
DSYNC_BRAIN_MAILBOX_ACTION_CREATE,
261
DSYNC_BRAIN_MAILBOX_ACTION_DELETE
265
dsync_brain_mailbox_action(struct dsync_brain *brain,
266
enum dsync_brain_mailbox_action action,
267
struct dsync_worker *action_worker,
268
struct dsync_mailbox *action_box)
270
struct dsync_mailbox new_box;
272
if (brain->backup && action_worker == brain->src_worker) {
273
/* backup mode: switch actions */
274
action_worker = brain->dest_worker;
276
case DSYNC_BRAIN_MAILBOX_ACTION_NONE:
278
case DSYNC_BRAIN_MAILBOX_ACTION_CREATE:
279
action = DSYNC_BRAIN_MAILBOX_ACTION_DELETE;
281
case DSYNC_BRAIN_MAILBOX_ACTION_DELETE:
282
action = DSYNC_BRAIN_MAILBOX_ACTION_CREATE;
288
case DSYNC_BRAIN_MAILBOX_ACTION_NONE:
290
case DSYNC_BRAIN_MAILBOX_ACTION_CREATE:
291
new_box = *action_box;
292
new_box.uid_next = action_box->uid_validity == 0 ? 0 : 1;
293
new_box.first_recent_uid = 0;
294
new_box.highest_modseq = 0;
295
dsync_worker_create_mailbox(action_worker, &new_box);
297
case DSYNC_BRAIN_MAILBOX_ACTION_DELETE:
298
if (!dsync_mailbox_is_noselect(action_box))
299
dsync_worker_delete_mailbox(action_worker, action_box);
301
dsync_worker_delete_dir(action_worker, action_box);
307
dsync_mailbox_list_is_empty(const ARRAY_TYPE(dsync_mailbox) *boxes_arr)
309
struct dsync_mailbox *const *boxes;
312
boxes = array_get(boxes_arr, &count);
315
if (count == 1 && strcasecmp(boxes[0]->name, "INBOX") == 0 &&
316
boxes[0]->message_count == 0)
321
static void dsync_brain_sync_mailboxes(struct dsync_brain *brain)
323
struct dsync_mailbox *const *src_boxes, *const *dest_boxes;
324
struct dsync_mailbox *action_box = NULL;
325
struct dsync_worker *action_worker = NULL;
326
unsigned int src, dest, src_count, dest_count;
327
enum dsync_brain_mailbox_action action;
328
bool src_deleted, dest_deleted;
332
dsync_mailbox_list_is_empty(&brain->src_mailbox_list->mailboxes) &&
333
!dsync_mailbox_list_is_empty(&brain->dest_mailbox_list->mailboxes)) {
334
i_fatal(DSYNC_WRONG_DIRECTION_ERROR_MSG);
337
/* create/delete missing mailboxes. the mailboxes are sorted by
338
GUID, so we can do this quickly. */
339
src_boxes = array_get(&brain->src_mailbox_list->mailboxes, &src_count);
340
dest_boxes = array_get(&brain->dest_mailbox_list->mailboxes, &dest_count);
341
for (src = dest = 0; src < src_count && dest < dest_count; ) {
342
action = DSYNC_BRAIN_MAILBOX_ACTION_NONE;
343
src_deleted = (src_boxes[src]->flags &
344
DSYNC_MAILBOX_FLAG_DELETED_MAILBOX) != 0;
345
dest_deleted = (dest_boxes[dest]->flags &
346
DSYNC_MAILBOX_FLAG_DELETED_MAILBOX) != 0;
347
ret = dsync_mailbox_guid_cmp(src_boxes[src],
350
/* exists only in source */
352
action = DSYNC_BRAIN_MAILBOX_ACTION_CREATE;
353
action_worker = brain->dest_worker;
354
action_box = src_boxes[src];
357
} else if (ret > 0) {
358
/* exists only in dest */
360
action = DSYNC_BRAIN_MAILBOX_ACTION_CREATE;
361
action_worker = brain->src_worker;
362
action_box = dest_boxes[dest];
365
} else if (src_deleted) {
366
/* delete from dest too */
368
action = DSYNC_BRAIN_MAILBOX_ACTION_DELETE;
369
action_worker = brain->dest_worker;
370
action_box = dest_boxes[dest];
373
} else if (dest_deleted) {
374
/* delete from src too */
375
action = DSYNC_BRAIN_MAILBOX_ACTION_DELETE;
376
action_worker = brain->src_worker;
377
action_box = src_boxes[src];
382
dsync_brain_mailbox_action(brain, action,
383
action_worker, action_box);
385
for (; src < src_count; src++) {
386
if ((src_boxes[src]->flags &
387
DSYNC_MAILBOX_FLAG_DELETED_MAILBOX) != 0)
390
dsync_brain_mailbox_action(brain,
391
DSYNC_BRAIN_MAILBOX_ACTION_CREATE,
392
brain->dest_worker, src_boxes[src]);
394
for (; dest < dest_count; dest++) {
395
if ((dest_boxes[dest]->flags &
396
DSYNC_MAILBOX_FLAG_DELETED_MAILBOX) != 0)
399
dsync_brain_mailbox_action(brain,
400
DSYNC_BRAIN_MAILBOX_ACTION_CREATE,
401
brain->src_worker, dest_boxes[dest]);
405
static void dsync_brain_sync_dirs(struct dsync_brain *brain)
407
struct dsync_mailbox *const *src_boxes, *const *dest_boxes, *action_box;
408
unsigned int src, dest, src_count, dest_count;
409
enum dsync_brain_mailbox_action action;
410
struct dsync_worker *action_worker = NULL;
411
bool src_deleted, dest_deleted;
414
/* create/delete missing directories. */
415
src_boxes = array_get(&brain->src_mailbox_list->dirs, &src_count);
416
dest_boxes = array_get(&brain->dest_mailbox_list->dirs, &dest_count);
417
for (src = dest = 0; src < src_count && dest < dest_count; ) {
418
action = DSYNC_BRAIN_MAILBOX_ACTION_NONE;
421
src_deleted = (src_boxes[src]->flags &
422
DSYNC_MAILBOX_FLAG_DELETED_DIR) != 0;
423
dest_deleted = (dest_boxes[dest]->flags &
424
DSYNC_MAILBOX_FLAG_DELETED_DIR) != 0;
425
ret = memcmp(src_boxes[src]->name_sha1.guid,
426
dest_boxes[dest]->name_sha1.guid,
427
sizeof(src_boxes[src]->name_sha1.guid));
429
/* exists only in source */
431
action = DSYNC_BRAIN_MAILBOX_ACTION_CREATE;
432
action_worker = brain->dest_worker;
433
action_box = src_boxes[src];
436
} else if (ret > 0) {
437
/* exists only in dest */
439
action = DSYNC_BRAIN_MAILBOX_ACTION_CREATE;
440
action_worker = brain->src_worker;
441
action_box = dest_boxes[dest];
444
} else if (src_deleted) {
445
/* delete from dest too */
447
action = DSYNC_BRAIN_MAILBOX_ACTION_DELETE;
448
action_worker = brain->dest_worker;
449
action_box = dest_boxes[dest];
452
} else if (dest_deleted) {
453
/* delete from src too */
454
action = DSYNC_BRAIN_MAILBOX_ACTION_DELETE;
455
action_worker = brain->src_worker;
456
action_box = src_boxes[src];
461
i_assert(action_box == NULL ||
462
dsync_mailbox_is_noselect(action_box));
463
dsync_brain_mailbox_action(brain, action,
464
action_worker, action_box);
466
for (; src < src_count; src++) {
467
if ((src_boxes[src]->flags &
468
DSYNC_MAILBOX_FLAG_DELETED_DIR) != 0)
471
dsync_brain_mailbox_action(brain,
472
DSYNC_BRAIN_MAILBOX_ACTION_CREATE,
473
brain->dest_worker, src_boxes[src]);
475
for (; dest < dest_count; dest++) {
476
if ((dest_boxes[dest]->flags &
477
DSYNC_MAILBOX_FLAG_DELETED_DIR) != 0)
480
dsync_brain_mailbox_action(brain,
481
DSYNC_BRAIN_MAILBOX_ACTION_CREATE,
482
brain->src_worker, dest_boxes[dest]);
487
dsync_brain_is_unsubscribed(struct dsync_brain_subs_list *list,
488
const struct dsync_worker_subscription *subs,
489
time_t *last_change_r)
491
const struct dsync_worker_unsubscription *unsubs;
492
struct dsync_worker_unsubscription lookup;
494
lookup.ns_prefix = subs->ns_prefix;
495
dsync_str_sha_to_guid(subs->storage_name, &lookup.name_sha1);
496
unsubs = array_bsearch(&list->unsubscriptions, &lookup,
497
dsync_worker_unsubscription_cmp);
498
if (unsubs == NULL) {
501
} else if (unsubs->last_change <= subs->last_change) {
502
*last_change_r = subs->last_change;
505
*last_change_r = unsubs->last_change;
510
static void dsync_brain_sync_subscriptions(struct dsync_brain *brain)
512
const struct dsync_worker_subscription *src_subs, *dest_subs;
513
const struct dsync_worker_subscription *action_subs;
514
struct dsync_worker *action_worker;
515
unsigned int src, dest, src_count, dest_count;
520
/* subscriptions are sorted by name. */
521
src_subs = array_get(&brain->src_subs_list->subscriptions, &src_count);
522
dest_subs = array_get(&brain->dest_subs_list->subscriptions, &dest_count);
523
for (src = dest = 0;; ) {
524
if (src == src_count) {
525
if (dest == dest_count)
528
} else if (dest == dest_count) {
531
ret = strcmp(src_subs[src].vname,
532
dest_subs[dest].vname);
540
/* subscribed only in source */
541
action_subs = &src_subs[src];
542
if (dsync_brain_is_unsubscribed(brain->dest_subs_list,
545
action_worker = brain->src_worker;
548
action_worker = brain->dest_worker;
553
/* subscribed only in dest */
554
action_subs = &dest_subs[dest];
555
if (dsync_brain_is_unsubscribed(brain->src_subs_list,
558
action_worker = brain->dest_worker;
561
action_worker = brain->src_worker;
567
if (brain->backup && action_worker == brain->src_worker) {
568
/* backup mode: switch action */
569
action_worker = brain->dest_worker;
570
subscribe = !subscribe;
571
last_change = ioloop_time;
573
dsync_worker_set_subscribed(action_worker, action_subs->vname,
574
last_change, subscribe);
578
static bool dsync_mailbox_has_changed_msgs(struct dsync_brain *brain,
579
const struct dsync_mailbox *box1,
580
const struct dsync_mailbox *box2)
582
const char *name = *box1->name != '\0' ? box1->name : box2->name;
584
if (box1->uid_validity != box2->uid_validity) {
585
if (brain->verbose) {
586
i_info("%s: uidvalidity changed: %u != %u", name,
587
box1->uid_validity, box2->uid_validity);
591
if (box1->uid_next != box2->uid_next) {
592
if (brain->verbose) {
593
i_info("%s: uidnext changed: %u != %u", name,
594
box1->uid_next, box2->uid_next);
598
if (box1->highest_modseq != box2->highest_modseq) {
599
if (brain->verbose) {
600
i_info("%s: highest_modseq changed: %llu != %llu", name,
601
(unsigned long long)box1->highest_modseq,
602
(unsigned long long)box2->highest_modseq);
606
if (box1->message_count != box2->message_count) {
607
if (brain->verbose) {
608
i_info("%s: message_count changed: %u != %u", name,
609
box1->message_count, box2->message_count);
616
static bool dsync_mailbox_has_changes(struct dsync_brain *brain,
617
const struct dsync_mailbox *box1,
618
const struct dsync_mailbox *box2)
620
if (strcmp(box1->name, box2->name) != 0)
622
return dsync_mailbox_has_changed_msgs(brain, box1, box2);
626
dsync_brain_get_changed_mailboxes(struct dsync_brain *brain,
627
ARRAY_TYPE(dsync_brain_mailbox) *brain_boxes,
630
struct dsync_mailbox *const *src_boxes, *const *dest_boxes;
631
struct dsync_brain_mailbox *brain_box;
632
unsigned int src, dest, src_count, dest_count;
633
bool src_deleted, dest_deleted;
636
src_boxes = array_get(&brain->src_mailbox_list->mailboxes, &src_count);
637
dest_boxes = array_get(&brain->dest_mailbox_list->mailboxes, &dest_count);
639
for (src = dest = 0; src < src_count && dest < dest_count; ) {
640
src_deleted = (src_boxes[src]->flags &
641
DSYNC_MAILBOX_FLAG_DELETED_MAILBOX) != 0;
642
dest_deleted = (dest_boxes[dest]->flags &
643
DSYNC_MAILBOX_FLAG_DELETED_MAILBOX) != 0;
645
ret = dsync_mailbox_guid_cmp(src_boxes[src], dest_boxes[dest]);
648
dsync_mailbox_has_changes(brain, src_boxes[src],
649
dest_boxes[dest])) &&
650
!src_deleted && !dest_deleted) {
651
brain_box = array_append_space(brain_boxes);
652
brain_box->box = *src_boxes[src];
654
brain_box->box.highest_modseq =
655
I_MAX(src_boxes[src]->highest_modseq,
656
dest_boxes[dest]->highest_modseq);
657
brain_box->box.uid_next =
658
I_MAX(src_boxes[src]->uid_next,
659
dest_boxes[dest]->uid_next);
660
brain_box->src = src_boxes[src];
661
brain_box->dest = dest_boxes[dest];
664
} else if (ret < 0) {
665
/* exists only in source */
667
brain_box = array_append_space(brain_boxes);
668
brain_box->box = *src_boxes[src];
669
brain_box->src = src_boxes[src];
670
if (brain->verbose) {
671
i_info("%s: only in source (guid=%s)",
673
dsync_guid_to_str(&brain_box->box.mailbox_guid));
678
/* exists only in dest */
680
brain_box = array_append_space(brain_boxes);
681
brain_box->box = *dest_boxes[dest];
682
brain_box->dest = dest_boxes[dest];
683
if (brain->verbose) {
684
i_info("%s: only in dest (guid=%s)",
686
dsync_guid_to_str(&brain_box->box.mailbox_guid));
692
for (; src < src_count; src++) {
693
if ((src_boxes[src]->flags &
694
DSYNC_MAILBOX_FLAG_DELETED_MAILBOX) != 0)
697
brain_box = array_append_space(brain_boxes);
698
brain_box->box = *src_boxes[src];
699
brain_box->src = src_boxes[src];
700
if (brain->verbose) {
701
i_info("%s: only in source (guid=%s)",
703
dsync_guid_to_str(&brain_box->box.mailbox_guid));
706
for (; dest < dest_count; dest++) {
707
if ((dest_boxes[dest]->flags &
708
DSYNC_MAILBOX_FLAG_DELETED_MAILBOX) != 0)
711
brain_box = array_append_space(brain_boxes);
712
brain_box->box = *dest_boxes[dest];
713
brain_box->dest = dest_boxes[dest];
714
if (brain->verbose) {
715
i_info("%s: only in dest (guid=%s)",
717
dsync_guid_to_str(&brain_box->box.mailbox_guid));
722
static bool dsync_brain_sync_msgs(struct dsync_brain *brain)
724
ARRAY_TYPE(dsync_brain_mailbox) mailboxes;
728
pool = pool_alloconly_create(MEMPOOL_GROWING"dsync changed mailboxes",
730
p_array_init(&mailboxes, pool, 128);
731
dsync_brain_get_changed_mailboxes(brain, &mailboxes,
732
(brain->flags & DSYNC_BRAIN_FLAG_FULL_SYNC) != 0);
733
if (array_count(&mailboxes) > 0) {
734
brain->mailbox_sync =
735
dsync_brain_msg_sync_init(brain, &mailboxes);
736
dsync_brain_msg_sync_more(brain->mailbox_sync);
746
dsync_brain_sync_rename_mailbox(struct dsync_brain *brain,
747
const struct dsync_brain_mailbox *mailbox)
749
if (mailbox->src->last_change > mailbox->dest->last_change ||
751
dsync_worker_rename_mailbox(brain->dest_worker,
752
&mailbox->box.mailbox_guid,
755
dsync_worker_rename_mailbox(brain->src_worker,
756
&mailbox->box.mailbox_guid,
762
dsync_brain_sync_update_mailboxes(struct dsync_brain *brain)
764
const struct dsync_brain_mailbox *mailbox;
765
bool failed_changes = dsync_brain_has_unexpected_changes(brain) ||
766
dsync_worker_has_failed(brain->src_worker) ||
767
dsync_worker_has_failed(brain->dest_worker);
769
if (brain->mailbox_sync == NULL) {
770
/* no mailboxes changed */
774
array_foreach(&brain->mailbox_sync->mailboxes, mailbox) {
775
/* don't update mailboxes if any changes had failed.
776
for example if some messages couldn't be saved, we don't
777
want to increase the next_uid to jump over them */
778
if (!brain->backup && !failed_changes) {
779
dsync_worker_update_mailbox(brain->src_worker,
782
if (!failed_changes) {
783
dsync_worker_update_mailbox(brain->dest_worker,
787
if (mailbox->src != NULL && mailbox->dest != NULL &&
788
strcmp(mailbox->src->name, mailbox->dest->name) != 0)
789
dsync_brain_sync_rename_mailbox(brain, mailbox);
793
static void dsync_brain_worker_finished(bool success, void *context)
795
struct dsync_brain *brain = context;
797
switch (brain->state) {
798
case DSYNC_STATE_SYNC_MSGS_FLUSH:
799
case DSYNC_STATE_SYNC_MSGS_FLUSH2:
800
case DSYNC_STATE_SYNC_FLUSH:
801
case DSYNC_STATE_SYNC_FLUSH2:
804
i_panic("dsync brain state=%d", brain->state);
808
dsync_brain_fail(brain);
811
if (brain->to == NULL && (brain->flags & DSYNC_BRAIN_FLAG_LOCAL) == 0)
812
brain->to = timeout_add(0, dsync_brain_sync, brain);
815
void dsync_brain_sync(struct dsync_brain *brain)
817
if (dsync_worker_has_failed(brain->src_worker) ||
818
dsync_worker_has_failed(brain->dest_worker)) {
819
/* we can't safely continue, especially with backup */
823
if (brain->to != NULL)
824
timeout_remove(&brain->to);
825
switch (brain->state) {
826
case DSYNC_STATE_GET_MAILBOXES:
827
i_assert(brain->src_mailbox_list == NULL);
828
brain->src_mailbox_list =
829
dsync_brain_mailbox_list_init(brain, brain->src_worker);
830
brain->dest_mailbox_list =
831
dsync_brain_mailbox_list_init(brain, brain->dest_worker);
832
dsync_worker_mailbox_input(brain->src_mailbox_list);
833
dsync_worker_mailbox_input(brain->dest_mailbox_list);
835
case DSYNC_STATE_GET_SUBSCRIPTIONS:
836
i_assert(brain->src_subs_list == NULL);
837
brain->src_subs_list =
838
dsync_brain_subs_list_init(brain, brain->src_worker);
839
brain->dest_subs_list =
840
dsync_brain_subs_list_init(brain, brain->dest_worker);
841
dsync_worker_subs_input(brain->src_subs_list);
842
dsync_worker_subs_input(brain->dest_subs_list);
844
case DSYNC_STATE_SYNC_MAILBOXES:
845
dsync_worker_set_input_callback(brain->src_worker, NULL, NULL);
846
dsync_worker_set_input_callback(brain->dest_worker, NULL, NULL);
848
dsync_brain_sync_mailboxes(brain);
849
dsync_brain_sync_dirs(brain);
852
case DSYNC_STATE_SYNC_SUBSCRIPTIONS:
853
dsync_brain_sync_subscriptions(brain);
856
case DSYNC_STATE_SYNC_MSGS:
857
if (dsync_brain_sync_msgs(brain))
860
/* no mailboxes changed */
861
case DSYNC_STATE_SYNC_MSGS_FLUSH:
862
/* wait until all saves are done, so we don't try to close
863
the mailbox too early */
864
dsync_worker_finish(brain->src_worker,
865
dsync_brain_worker_finished, brain);
866
dsync_worker_finish(brain->dest_worker,
867
dsync_brain_worker_finished, brain);
869
case DSYNC_STATE_SYNC_MSGS_FLUSH2:
871
case DSYNC_STATE_SYNC_UPDATE_MAILBOXES:
872
dsync_brain_sync_update_mailboxes(brain);
875
case DSYNC_STATE_SYNC_FLUSH:
876
dsync_worker_finish(brain->src_worker,
877
dsync_brain_worker_finished, brain);
878
dsync_worker_finish(brain->dest_worker,
879
dsync_brain_worker_finished, brain);
881
case DSYNC_STATE_SYNC_FLUSH2:
883
case DSYNC_STATE_SYNC_END:
884
io_loop_stop(current_ioloop);
891
void dsync_brain_sync_all(struct dsync_brain *brain)
893
enum dsync_state old_state;
895
while (brain->state != DSYNC_STATE_SYNC_END) {
896
old_state = brain->state;
897
dsync_brain_sync(brain);
899
if (dsync_brain_has_failed(brain))
902
i_assert(brain->state != old_state);
906
bool dsync_brain_has_unexpected_changes(struct dsync_brain *brain)
908
return brain->unexpected_changes ||
909
dsync_worker_has_unexpected_changes(brain->src_worker) ||
910
dsync_worker_has_unexpected_changes(brain->dest_worker);
913
bool dsync_brain_has_failed(struct dsync_brain *brain)
915
return brain->failed ||
916
dsync_worker_has_failed(brain->src_worker) ||
917
dsync_worker_has_failed(brain->dest_worker);