From e1bef591ed45c5baf6b5bdc69fb7fa5ff05df2b6 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Thu, 28 Jan 2016 19:56:38 +0200 Subject: [PATCH] dsync: Avoid finishing importer successfully on exporter failures. At least dsync_mailbox_import_changes_finish() could have been called when exporter was already failed. --- src/doveadm/dsync/dsync-brain-mails.c | 53 ++++++++++++++--------- src/doveadm/dsync/dsync-mailbox-export.c | 54 +++++++++++++----------- src/doveadm/dsync/dsync-mailbox-export.h | 15 ++++--- 3 files changed, 72 insertions(+), 50 deletions(-) diff --git a/src/doveadm/dsync/dsync-brain-mails.c b/src/doveadm/dsync/dsync-brain-mails.c index 2def387e64..137e64b1e2 100644 --- a/src/doveadm/dsync/dsync-brain-mails.c +++ b/src/doveadm/dsync/dsync-brain-mails.c @@ -97,14 +97,36 @@ static void dsync_brain_send_end_of_list(struct dsync_brain *brain, dsync_ibc_send_end_of_list(brain->ibc, type); } +static int dsync_brain_export_deinit(struct dsync_brain *brain) +{ + const char *errstr; + enum mail_error error; + + if (dsync_mailbox_export_deinit(&brain->box_exporter, + &errstr, &error) < 0) { + i_error("Exporting mailbox %s failed: %s", + mailbox_get_vname(brain->box), errstr); + brain->mail_error = error; + brain->failed = TRUE; + return -1; + } + return 0; +} + static void dsync_brain_send_mailbox_attribute(struct dsync_brain *brain) { const struct dsync_mailbox_attribute *attr; + int ret; - while ((attr = dsync_mailbox_export_next_attr(brain->box_exporter)) != NULL) { + while ((ret = dsync_mailbox_export_next_attr(brain->box_exporter, &attr)) > 0) { if (dsync_ibc_send_mailbox_attribute(brain->ibc, attr) == 0) return; } + if (ret < 0) { + if (dsync_brain_export_deinit(brain) == 0) + i_unreached(); + return; + } dsync_brain_send_end_of_list(brain, DSYNC_IBC_EOL_MAILBOX_ATTRIBUTE); brain->box_send_state = DSYNC_BOX_STATE_CHANGES; } @@ -133,11 +155,17 @@ static bool dsync_brain_recv_mail_change(struct dsync_brain *brain) static void dsync_brain_send_mail_change(struct dsync_brain *brain) { const struct dsync_mail_change *change; + int ret; - while ((change = dsync_mailbox_export_next(brain->box_exporter)) != NULL) { + while ((ret = dsync_mailbox_export_next(brain->box_exporter, &change)) > 0) { if (dsync_ibc_send_change(brain->ibc, change) == 0) return; } + if (ret < 0) { + if (dsync_brain_export_deinit(brain) == 0) + i_unreached(); + return; + } dsync_brain_send_end_of_list(brain, DSYNC_IBC_EOL_MAIL_CHANGES); if (brain->mail_requests && brain->box_importer != NULL) brain->box_send_state = DSYNC_BOX_STATE_MAIL_REQUESTS; @@ -188,22 +216,6 @@ static bool dsync_brain_send_mail_request(struct dsync_brain *brain) return TRUE; } -static int dsync_brain_export_deinit(struct dsync_brain *brain) -{ - const char *errstr; - enum mail_error error; - - if (dsync_mailbox_export_deinit(&brain->box_exporter, - &errstr, &error) < 0) { - i_error("Exporting mailbox %s failed: %s", - mailbox_get_vname(brain->box), errstr); - brain->mail_error = error; - brain->failed = TRUE; - return -1; - } - return 0; -} - static void dsync_brain_sync_half_finished(struct dsync_brain *brain) { struct dsync_mailbox_state state; @@ -227,7 +239,8 @@ static void dsync_brain_sync_half_finished(struct dsync_brain *brain) state.last_messages_count = brain->local_dsync_box.messages_count; } else { - if (dsync_mailbox_import_deinit(&brain->box_importer, TRUE, + if (dsync_mailbox_import_deinit(&brain->box_importer, + !brain->failed, &state.last_common_uid, &state.last_common_modseq, &state.last_common_pvt_modseq, @@ -284,7 +297,7 @@ static bool dsync_brain_send_mail(struct dsync_brain *brain) return FALSE; } - while ((mail = dsync_mailbox_export_next_mail(brain->box_exporter)) != NULL) { + while (dsync_mailbox_export_next_mail(brain->box_exporter, &mail) > 0) { if (dsync_ibc_send_mail(brain->ibc, mail) == 0) return TRUE; } diff --git a/src/doveadm/dsync/dsync-mailbox-export.c b/src/doveadm/dsync/dsync-mailbox-export.c index d08e0e1fce..c013eb0467 100644 --- a/src/doveadm/dsync/dsync-mailbox-export.c +++ b/src/doveadm/dsync/dsync-mailbox-export.c @@ -648,38 +648,41 @@ dsync_mailbox_export_iter_next_attr(struct dsync_mailbox_exporter *exporter) return dsync_mailbox_export_iter_next_nonexistent_attr(exporter); } -const struct dsync_mailbox_attribute * -dsync_mailbox_export_next_attr(struct dsync_mailbox_exporter *exporter) +int dsync_mailbox_export_next_attr(struct dsync_mailbox_exporter *exporter, + const struct dsync_mailbox_attribute **attr_r) { + int ret; + if (exporter->error != NULL) - return NULL; + return -1; if (exporter->attr.value_stream != NULL) i_stream_unref(&exporter->attr.value_stream); if (exporter->attr_iter != NULL) { - if (dsync_mailbox_export_iter_next_attr(exporter) <= 0) - return NULL; + ret = dsync_mailbox_export_iter_next_attr(exporter); } else { - if (dsync_mailbox_export_iter_next_nonexistent_attr(exporter) <= 0) - return NULL; + ret = dsync_mailbox_export_iter_next_nonexistent_attr(exporter); } - return &exporter->attr; + if (ret > 0) + *attr_r = &exporter->attr; + return ret; } -const struct dsync_mail_change * -dsync_mailbox_export_next(struct dsync_mailbox_exporter *exporter) +int dsync_mailbox_export_next(struct dsync_mailbox_exporter *exporter, + const struct dsync_mail_change **change_r) { struct dsync_mail_change *const *changes; unsigned int count; if (exporter->error != NULL) - return NULL; + return -1; changes = array_get(&exporter->sorted_changes, &count); if (exporter->change_idx == count) - return NULL; - return changes[exporter->change_idx++]; + return 0; + *change_r = changes[exporter->change_idx++]; + return 1; } static int @@ -837,8 +840,8 @@ void dsync_mailbox_export_want_mail(struct dsync_mailbox_exporter *exporter, instances->requested = TRUE; } -const struct dsync_mail * -dsync_mailbox_export_next_mail(struct dsync_mailbox_exporter *exporter) +int dsync_mailbox_export_next_mail(struct dsync_mailbox_exporter *exporter, + const struct dsync_mail **mail_r) { struct mail *mail; const char *const *guids; @@ -846,22 +849,24 @@ dsync_mailbox_export_next_mail(struct dsync_mailbox_exporter *exporter) int ret; if (exporter->error != NULL) - return NULL; + return -1; if (!exporter->body_search_initialized) { exporter->body_search_initialized = TRUE; if (dsync_mailbox_export_body_search_init(exporter) < 0) { i_assert(exporter->error != NULL); - return NULL; + return -1; } } while (mailbox_search_next(exporter->search_ctx, &mail)) { exporter->search_pos++; - if ((ret = dsync_mailbox_export_mail(exporter, mail)) > 0) - return &exporter->dsync_mail; + if ((ret = dsync_mailbox_export_mail(exporter, mail)) > 0) { + *mail_r = &exporter->dsync_mail; + return 1; + } if (ret < 0) { i_assert(exporter->error != NULL); - return NULL; + return -1; } /* the message was expunged. if the GUID has another instance, try sending it later. */ @@ -872,11 +877,11 @@ dsync_mailbox_export_next_mail(struct dsync_mailbox_exporter *exporter) dsync_mailbox_export_body_search_deinit(exporter); if ((ret = dsync_mailbox_export_body_search_init(exporter)) < 0) { i_assert(exporter->error != NULL); - return NULL; + return -1; } if (ret > 0) { /* not finished yet */ - return dsync_mailbox_export_next_mail(exporter); + return dsync_mailbox_export_next_mail(exporter, mail_r); } /* finished with messages. if there are any expunged messages, @@ -886,9 +891,10 @@ dsync_mailbox_export_next_mail(struct dsync_mailbox_exporter *exporter) memset(&exporter->dsync_mail, 0, sizeof(exporter->dsync_mail)); exporter->dsync_mail.guid = guids[exporter->expunged_guid_idx++]; - return &exporter->dsync_mail; + *mail_r = &exporter->dsync_mail; + return 1; } - return NULL; + return 0; } int dsync_mailbox_export_deinit(struct dsync_mailbox_exporter **_exporter, diff --git a/src/doveadm/dsync/dsync-mailbox-export.h b/src/doveadm/dsync/dsync-mailbox-export.h index fffeedbbb2..c8f95488eb 100644 --- a/src/doveadm/dsync/dsync-mailbox-export.h +++ b/src/doveadm/dsync/dsync-mailbox-export.h @@ -14,15 +14,18 @@ dsync_mailbox_export_init(struct mailbox *box, struct dsync_transaction_log_scan *log_scan, uint32_t last_common_uid, enum dsync_mailbox_exporter_flags flags); -const struct dsync_mailbox_attribute * -dsync_mailbox_export_next_attr(struct dsync_mailbox_exporter *exporter); -const struct dsync_mail_change * -dsync_mailbox_export_next(struct dsync_mailbox_exporter *exporter); +/* Returns 1 if attribute was returned, 0 if no more attributes, -1 on error */ +int dsync_mailbox_export_next_attr(struct dsync_mailbox_exporter *exporter, + const struct dsync_mailbox_attribute **attr_r); +/* Returns 1 if change was returned, 0 if no more changes, -1 on error */ +int dsync_mailbox_export_next(struct dsync_mailbox_exporter *exporter, + const struct dsync_mail_change **change_r); void dsync_mailbox_export_want_mail(struct dsync_mailbox_exporter *exporter, const struct dsync_mail_request *request); -const struct dsync_mail * -dsync_mailbox_export_next_mail(struct dsync_mailbox_exporter *exporter); +/* Returns 1 if mail was returned, 0 if no more mails, -1 on error */ +int dsync_mailbox_export_next_mail(struct dsync_mailbox_exporter *exporter, + const struct dsync_mail **mail_r); int dsync_mailbox_export_deinit(struct dsync_mailbox_exporter **exporter, const char **errstr_r, enum mail_error *error_r);