changeset 18351:b4dbe64c0032

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.
author Timo Sirainen <tss@iki.fi>
date Fri, 13 Mar 2015 20:08:34 +0200
parents e86211e8d728
children d88af513a942
files 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
diffstat 8 files changed, 124 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/doveadm/dsync/dsync-brain-mailbox.c	Fri Mar 13 20:05:03 2015 +0200
+++ b/src/doveadm/dsync/dsync-brain-mailbox.c	Fri Mar 13 20:08:34 2015 +0200
@@ -534,7 +534,7 @@
 	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 @@
 	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;
 	}
 
--- a/src/doveadm/dsync/dsync-brain-private.h	Fri Mar 13 20:05:03 2015 +0200
+++ b/src/doveadm/dsync/dsync-brain-private.h	Fri Mar 13 20:08:34 2015 +0200
@@ -32,6 +32,7 @@
 	   after the mails are synced, another mailbox is synced. */
 	DSYNC_STATE_SYNC_MAILS,
 
+	DSYNC_STATE_FINISH,
 	DSYNC_STATE_DONE
 };
 
--- a/src/doveadm/dsync/dsync-brain.c	Fri Mar 13 20:05:03 2015 +0200
+++ b/src/doveadm/dsync/dsync-brain.c	Fri Mar 13 20:08:34 2015 +0200
@@ -30,6 +30,7 @@
 	"master_send_mailbox",
 	"slave_recv_mailbox",
 	"sync_mails",
+	"finish",
 	"done"
 };
 
@@ -554,6 +555,26 @@
 	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 @@
 	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;
--- a/src/doveadm/dsync/dsync-ibc-pipe.c	Fri Mar 13 20:05:03 2015 +0200
+++ b/src/doveadm/dsync/dsync-ibc-pipe.c	Fri Mar 13 20:08:34 2015 +0200
@@ -19,7 +19,8 @@
 	ITEM_MAILBOX_ATTRIBUTE,
 	ITEM_MAIL_CHANGE,
 	ITEM_MAIL_REQUEST,
-	ITEM_MAIL
+	ITEM_MAIL,
+	ITEM_FINISH
 };
 
 struct item {
@@ -41,6 +42,7 @@
 			unsigned int count;
 			char hierarchy_sep;
 		} mailbox_delete;
+		const char *finish_error;
 	} u;
 };
 
@@ -90,6 +92,7 @@
 	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 @@
 	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 @@
 	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
--- a/src/doveadm/dsync/dsync-ibc-private.h	Fri Mar 13 20:05:03 2015 +0200
+++ b/src/doveadm/dsync/dsync-ibc-private.h	Fri Mar 13 20:08:34 2015 +0200
@@ -68,6 +68,10 @@
 		(*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);
--- a/src/doveadm/dsync/dsync-ibc-stream.c	Fri Mar 13 20:05:03 2015 +0200
+++ b/src/doveadm/dsync/dsync-ibc-stream.c	Fri Mar 13 20:08:34 2015 +0200
@@ -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 @@
 	ITEM_MAIL_CHANGE,
 	ITEM_MAIL_REQUEST,
 	ITEM_MAIL,
+	ITEM_FINISH,
 
 	ITEM_MAILBOX_CACHE_FIELD,
 
@@ -122,6 +124,10 @@
 	  .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 @@
 	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 @@
 	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
--- a/src/doveadm/dsync/dsync-ibc.c	Fri Mar 13 20:05:03 2015 +0200
+++ b/src/doveadm/dsync/dsync-ibc.c	Fri Mar 13 20:08:34 2015 +0200
@@ -195,6 +195,17 @@
 	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);
--- a/src/doveadm/dsync/dsync-ibc.h	Fri Mar 13 20:05:03 2015 +0200
+++ b/src/doveadm/dsync/dsync-ibc.h	Fri Mar 13 20:08:34 2015 +0200
@@ -144,6 +144,10 @@
 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);