From: Timo Sirainen Date: Fri, 13 Mar 2015 18:08:34 +0000 (+0200) Subject: dsync: Added an extra "finish" state to allow slave-dsync to report error to master... X-Git-Tag: 2.2.17.rc1~270 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=24bd831901b8fd59718e353b36eaef6a950f09a2;p=thirdparty%2Fdovecot%2Fcore.git dsync: Added an extra "finish" state to allow slave-dsync to report error to master-dsync. I'm not sure if that's actually necessary, but just trying to follow the different possibilities on how dsync run can finish made me unsure about it. This should make it at least clear that if a slave-dsync has a failure flag set at deinit master-dsync will know about it before it returns success. --- diff --git a/src/doveadm/dsync/dsync-brain-mailbox.c b/src/doveadm/dsync/dsync-brain-mailbox.c index c0e5dfa717..a6984a0de6 100644 --- a/src/doveadm/dsync/dsync-brain-mailbox.c +++ b/src/doveadm/dsync/dsync-brain-mailbox.c @@ -534,7 +534,7 @@ void dsync_brain_master_send_mailbox(struct dsync_brain *brain) i_assert(brain->box == NULL); if (!dsync_brain_next_mailbox(brain, &box, &dsync_box)) { - brain->state = DSYNC_STATE_DONE; + brain->state = DSYNC_STATE_FINISH; dsync_ibc_send_end_of_list(brain->ibc, DSYNC_IBC_EOL_MAILBOX); return; } @@ -722,7 +722,7 @@ bool dsync_brain_slave_recv_mailbox(struct dsync_brain *brain) if ((ret = dsync_ibc_recv_mailbox(brain->ibc, &dsync_box)) == 0) return FALSE; if (ret < 0) { - brain->state = DSYNC_STATE_DONE; + brain->state = DSYNC_STATE_FINISH; return TRUE; } diff --git a/src/doveadm/dsync/dsync-brain-private.h b/src/doveadm/dsync/dsync-brain-private.h index d214a270fa..c0a84e26d2 100644 --- a/src/doveadm/dsync/dsync-brain-private.h +++ b/src/doveadm/dsync/dsync-brain-private.h @@ -32,6 +32,7 @@ enum dsync_state { after the mails are synced, another mailbox is synced. */ DSYNC_STATE_SYNC_MAILS, + DSYNC_STATE_FINISH, DSYNC_STATE_DONE }; diff --git a/src/doveadm/dsync/dsync-brain.c b/src/doveadm/dsync/dsync-brain.c index 6fddd9c1a9..e6d0293df6 100644 --- a/src/doveadm/dsync/dsync-brain.c +++ b/src/doveadm/dsync/dsync-brain.c @@ -30,6 +30,7 @@ static const char *dsync_state_names[] = { "master_send_mailbox", "slave_recv_mailbox", "sync_mails", + "finish", "done" }; @@ -554,6 +555,26 @@ static bool dsync_brain_slave_recv_last_common(struct dsync_brain *brain) return changed; } +static bool dsync_brain_finish(struct dsync_brain *brain) +{ + const char *error; + + if (!brain->master_brain) { + dsync_ibc_send_finish(brain->ibc, + brain->failed ? "dsync failed" : NULL); + brain->state = DSYNC_STATE_DONE; + return TRUE; + } + if (dsync_ibc_recv_finish(brain->ibc, &error) == DSYNC_IBC_RECV_RET_TRYAGAIN) + return FALSE; + if (error != NULL) { + i_error("Remote dsync failed: %s", error); + brain->failed = TRUE; + } + brain->state = DSYNC_STATE_DONE; + return TRUE; +} + static bool dsync_brain_run_real(struct dsync_brain *brain, bool *changed_r) { enum dsync_state orig_state = brain->state; @@ -602,6 +623,9 @@ static bool dsync_brain_run_real(struct dsync_brain *brain, bool *changed_r) case DSYNC_STATE_SYNC_MAILS: changed = dsync_brain_sync_mails(brain); break; + case DSYNC_STATE_FINISH: + changed = dsync_brain_finish(brain); + break; case DSYNC_STATE_DONE: changed = TRUE; ret = FALSE; diff --git a/src/doveadm/dsync/dsync-ibc-pipe.c b/src/doveadm/dsync/dsync-ibc-pipe.c index a972fb8776..e6e1651d42 100644 --- a/src/doveadm/dsync/dsync-ibc-pipe.c +++ b/src/doveadm/dsync/dsync-ibc-pipe.c @@ -19,7 +19,8 @@ enum item_type { ITEM_MAILBOX_ATTRIBUTE, ITEM_MAIL_CHANGE, ITEM_MAIL_REQUEST, - ITEM_MAIL + ITEM_MAIL, + ITEM_FINISH }; struct item { @@ -41,6 +42,7 @@ struct item { unsigned int count; char hierarchy_sep; } mailbox_delete; + const char *finish_error; } u; }; @@ -90,6 +92,7 @@ dsync_ibc_pipe_push_item(struct dsync_ibc_pipe *pipe, enum item_type type) case ITEM_MAIL_CHANGE: case ITEM_MAIL_REQUEST: case ITEM_MAIL: + case ITEM_FINISH: item->pool = dsync_ibc_pipe_get_pool(pipe); break; } @@ -483,6 +486,30 @@ dsync_ibc_pipe_recv_mail(struct dsync_ibc *ibc, struct dsync_mail **mail_r) return DSYNC_IBC_RECV_RET_OK; } +static void +dsync_ibc_pipe_send_finish(struct dsync_ibc *ibc, const char *error) +{ + struct dsync_ibc_pipe *pipe = (struct dsync_ibc_pipe *)ibc; + struct item *item; + + item = dsync_ibc_pipe_push_item(pipe->remote, ITEM_FINISH); + item->u.finish_error = p_strdup(item->pool, error); +} + +static enum dsync_ibc_recv_ret +dsync_ibc_pipe_recv_finish(struct dsync_ibc *ibc, const char **error_r) +{ + struct dsync_ibc_pipe *pipe = (struct dsync_ibc_pipe *)ibc; + struct item *item; + + item = dsync_ibc_pipe_pop_item(pipe, ITEM_FINISH); + if (item == NULL) + return DSYNC_IBC_RECV_RET_TRYAGAIN; + + *error_r = item->u.finish_error; + return DSYNC_IBC_RECV_RET_OK; +} + static void pipe_close_mail_streams(struct dsync_ibc_pipe *pipe) { struct item *item; @@ -524,6 +551,8 @@ static const struct dsync_ibc_vfuncs dsync_ibc_pipe_vfuncs = { dsync_ibc_pipe_recv_mail_request, dsync_ibc_pipe_send_mail, dsync_ibc_pipe_recv_mail, + dsync_ibc_pipe_send_finish, + dsync_ibc_pipe_recv_finish, dsync_ibc_pipe_close_mail_streams, dsync_ibc_pipe_is_send_queue_full, dsync_ibc_pipe_has_pending_data diff --git a/src/doveadm/dsync/dsync-ibc-private.h b/src/doveadm/dsync/dsync-ibc-private.h index c07cc71a55..5a18f56bee 100644 --- a/src/doveadm/dsync/dsync-ibc-private.h +++ b/src/doveadm/dsync/dsync-ibc-private.h @@ -68,6 +68,10 @@ struct dsync_ibc_vfuncs { (*recv_mail)(struct dsync_ibc *ibc, struct dsync_mail **mail_r); + void (*send_finish)(struct dsync_ibc *ibc, const char *error); + enum dsync_ibc_recv_ret + (*recv_finish)(struct dsync_ibc *ibc, const char **error_r); + void (*close_mail_streams)(struct dsync_ibc *ibc); bool (*is_send_queue_full)(struct dsync_ibc *ibc); bool (*has_pending_data)(struct dsync_ibc *ibc); diff --git a/src/doveadm/dsync/dsync-ibc-stream.c b/src/doveadm/dsync/dsync-ibc-stream.c index 5408063796..3c61e856f5 100644 --- a/src/doveadm/dsync/dsync-ibc-stream.c +++ b/src/doveadm/dsync/dsync-ibc-stream.c @@ -28,11 +28,12 @@ #define DSYNC_IBC_STREAM_OUTBUF_THROTTLE_SIZE (1024*128) #define DSYNC_PROTOCOL_VERSION_MAJOR 3 -#define DSYNC_PROTOCOL_VERSION_MINOR 2 -#define DSYNC_HANDSHAKE_VERSION "VERSION\tdsync\t3\t2\n" +#define DSYNC_PROTOCOL_VERSION_MINOR 3 +#define DSYNC_HANDSHAKE_VERSION "VERSION\tdsync\t3\t3\n" #define DSYNC_PROTOCOL_MINOR_HAVE_ATTRIBUTES 1 #define DSYNC_PROTOCOL_MINOR_HAVE_SAVE_GUID 2 +#define DSYNC_PROTOCOL_MINOR_HAVE_FINISH 3 enum item_type { ITEM_NONE, @@ -48,6 +49,7 @@ enum item_type { ITEM_MAIL_CHANGE, ITEM_MAIL_REQUEST, ITEM_MAIL, + ITEM_FINISH, ITEM_MAILBOX_CACHE_FIELD, @@ -122,6 +124,10 @@ static const struct { .chr = 'M', .optional_keys = "guid uid pop3_uidl pop3_order received_date saved_date stream" }, + { .name = "finish", + .chr = 'F', + .optional_keys = "error" + }, { .name = "mailbox_cache_field", .chr = 'c', .required_keys = "name decision", @@ -1820,6 +1826,44 @@ dsync_ibc_stream_recv_mail(struct dsync_ibc *_ibc, struct dsync_mail **mail_r) return DSYNC_IBC_RECV_RET_OK; } +static void +dsync_ibc_stream_send_finish(struct dsync_ibc *_ibc, const char *error) +{ + struct dsync_ibc_stream *ibc = (struct dsync_ibc_stream *)_ibc; + struct dsync_serializer_encoder *encoder; + string_t *str = t_str_new(128); + + str_append_c(str, items[ITEM_FINISH].chr); + encoder = dsync_serializer_encode_begin(ibc->serializers[ITEM_FINISH]); + if (error != NULL) + dsync_serializer_encode_add(encoder, "error", error); + dsync_serializer_encode_finish(&encoder, str); + dsync_ibc_stream_send_string(ibc, str); +} + +static enum dsync_ibc_recv_ret +dsync_ibc_stream_recv_finish(struct dsync_ibc *_ibc, const char **error_r) +{ + struct dsync_ibc_stream *ibc = (struct dsync_ibc_stream *)_ibc; + struct dsync_deserializer_decoder *decoder; + const char *value; + enum dsync_ibc_recv_ret ret; + + *error_r = NULL; + p_clear(ibc->ret_pool); + + if (ibc->minor_version < DSYNC_PROTOCOL_MINOR_HAVE_FINISH) + return DSYNC_IBC_RECV_RET_OK; + + ret = dsync_ibc_stream_input_next(ibc, ITEM_FINISH, &decoder); + if (ret != DSYNC_IBC_RECV_RET_OK) + return ret; + + if (dsync_deserializer_decode_try(decoder, "error", &value)) + *error_r = p_strdup(ibc->ret_pool, value); + return DSYNC_IBC_RECV_RET_OK; +} + static void dsync_ibc_stream_close_mail_streams(struct dsync_ibc *_ibc) { struct dsync_ibc_stream *ibc = (struct dsync_ibc_stream *)_ibc; @@ -1874,6 +1918,8 @@ static const struct dsync_ibc_vfuncs dsync_ibc_stream_vfuncs = { dsync_ibc_stream_recv_mail_request, dsync_ibc_stream_send_mail, dsync_ibc_stream_recv_mail, + dsync_ibc_stream_send_finish, + dsync_ibc_stream_recv_finish, dsync_ibc_stream_close_mail_streams, dsync_ibc_stream_is_send_queue_full, dsync_ibc_stream_has_pending_data diff --git a/src/doveadm/dsync/dsync-ibc.c b/src/doveadm/dsync/dsync-ibc.c index 9bffc3ac06..4f7f9d693d 100644 --- a/src/doveadm/dsync/dsync-ibc.c +++ b/src/doveadm/dsync/dsync-ibc.c @@ -195,6 +195,17 @@ dsync_ibc_recv_mail(struct dsync_ibc *ibc, struct dsync_mail **mail_r) return ibc->v.recv_mail(ibc, mail_r); } +void dsync_ibc_send_finish(struct dsync_ibc *ibc, const char *error) +{ + ibc->v.send_finish(ibc, error); +} + +enum dsync_ibc_recv_ret +dsync_ibc_recv_finish(struct dsync_ibc *ibc, const char **error_r) +{ + return ibc->v.recv_finish(ibc, error_r); +} + void dsync_ibc_close_mail_streams(struct dsync_ibc *ibc) { ibc->v.close_mail_streams(ibc); diff --git a/src/doveadm/dsync/dsync-ibc.h b/src/doveadm/dsync/dsync-ibc.h index 1b895b4c0f..32709b8ac5 100644 --- a/src/doveadm/dsync/dsync-ibc.h +++ b/src/doveadm/dsync/dsync-ibc.h @@ -144,6 +144,10 @@ dsync_ibc_send_mail(struct dsync_ibc *ibc, const struct dsync_mail *mail); enum dsync_ibc_recv_ret dsync_ibc_recv_mail(struct dsync_ibc *ibc, struct dsync_mail **mail_r); +void dsync_ibc_send_finish(struct dsync_ibc *ibc, const char *error); +enum dsync_ibc_recv_ret +dsync_ibc_recv_finish(struct dsync_ibc *ibc, const char **error_r); + /* Close any mail input streams that are kept open. This needs to be called before the mail is attempted to be freed (usually on error conditions). */ void dsync_ibc_close_mail_streams(struct dsync_ibc *ibc);