]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
dsync: Added an extra "finish" state to allow slave-dsync to report error to master...
authorTimo Sirainen <tss@iki.fi>
Fri, 13 Mar 2015 18:08:34 +0000 (20:08 +0200)
committerTimo Sirainen <tss@iki.fi>
Fri, 13 Mar 2015 18:08:34 +0000 (20:08 +0200)
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.

src/doveadm/dsync/dsync-brain-mailbox.c
src/doveadm/dsync/dsync-brain-private.h
src/doveadm/dsync/dsync-brain.c
src/doveadm/dsync/dsync-ibc-pipe.c
src/doveadm/dsync/dsync-ibc-private.h
src/doveadm/dsync/dsync-ibc-stream.c
src/doveadm/dsync/dsync-ibc.c
src/doveadm/dsync/dsync-ibc.h

index c0e5dfa71775b9a862c2e50396b412c36ae5c927..a6984a0de68dc6ea11d31a1dc2ca80495f895adc 100644 (file)
@@ -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;
        }
 
index d214a270fac74c5bcae8a8f59255a2aac26f6dd1..c0a84e26d2911060ac2c27a964563f860c1b88a9 100644 (file)
@@ -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
 };
 
index 6fddd9c1a9f15d742bd31dd064e6406f08c37692..e6d0293df68fc8c7d9f961c9cfcabc3f38f7899f 100644 (file)
@@ -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;
index a972fb877626256a6964f7a42f6cac1709b3284a..e6e1651d42508ee43b00ac934a7a40a980331015 100644 (file)
@@ -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
index c07cc71a5527b6b3acabbbbee8e8515cc15d84ca..5a18f56beebebe0abfbb34a52e431df641fa495c 100644 (file)
@@ -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);
index 5408063796a43a7d26d0b41008dfdedc15adc722..3c61e856f56566e25bd34095c270778dee18616c 100644 (file)
 #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
index 9bffc3ac06b0e1b8c45685761d3cc3f4e3e6d8ab..4f7f9d693da25b09ddb80bfd221232aacc92b433 100644 (file)
@@ -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);
index 1b895b4c0f2f555ee4c686c3c931e6b589487cde..32709b8ac5a21007b946194200631488f08c152f 100644 (file)
@@ -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);