diff src/doveadm/dsync/dsync-brain.c @ 15232:6c850258002f

doveadm sync/backup: Added -s <state> parameter to do a fast stateful sync. Initially use an empty string for the input state. The output state is written to stdout.
author Timo Sirainen <tss@iki.fi>
date Sun, 21 Oct 2012 12:20:30 +0300
parents 454d0563927d
children b52f4852e5f8
line wrap: on
line diff
--- a/src/doveadm/dsync/dsync-brain.c	Sun Oct 21 10:01:54 2012 +0300
+++ b/src/doveadm/dsync/dsync-brain.c	Sun Oct 21 12:20:30 2012 +0300
@@ -47,9 +47,9 @@
 	brain->user = user;
 	brain->ibc = ibc;
 	brain->sync_type = DSYNC_BRAIN_SYNC_TYPE_UNKNOWN;
-	hash_table_create(&brain->remote_mailbox_states,
-			  brain->pool, 0, guid_128_hash, guid_128_cmp);
-	p_array_init(&brain->mailbox_states, pool, 64);
+	hash_table_create(&brain->mailbox_states, pool, 0,
+			  guid_128_hash, guid_128_cmp);
+	p_array_init(&brain->remote_mailbox_states, pool, 64);
 	return brain;
 }
 
@@ -87,12 +87,14 @@
 
 	brain->state = DSYNC_STATE_SEND_MAILBOX_TREE;
 	if (sync_type == DSYNC_BRAIN_SYNC_TYPE_STATE) {
-		if (dsync_mailbox_states_import(&brain->mailbox_states, state,
+		if (dsync_mailbox_states_import(brain->mailbox_states,
+						brain->pool, state,
 						&error) < 0) {
-			array_clear(&brain->mailbox_states);
+			hash_table_clear(brain->mailbox_states, FALSE);
 			i_error("Saved sync state is invalid, "
 				"falling back to full sync: %s", error);
-			brain->sync_type = DSYNC_BRAIN_SYNC_TYPE_FULL;
+			brain->sync_type = sync_type =
+				DSYNC_BRAIN_SYNC_TYPE_FULL;
 		} else {
 			brain->state = DSYNC_STATE_MASTER_SEND_LAST_COMMON;
 		}
@@ -142,8 +144,9 @@
 		dsync_brain_sync_mailbox_deinit(brain);
 	if (brain->local_tree_iter != NULL)
 		dsync_mailbox_tree_iter_deinit(&brain->local_tree_iter);
-
-	hash_table_destroy(&brain->remote_mailbox_states);
+	if (brain->mailbox_states_iter != NULL)
+		hash_table_iterate_deinit(&brain->mailbox_states_iter);
+	hash_table_destroy(&brain->mailbox_states);
 
 	ret = brain->failed ? -1 : 0;
 	pool_unref(&brain->pool);
@@ -184,22 +187,41 @@
 
 static void dsync_brain_master_send_last_common(struct dsync_brain *brain)
 {
-	const struct dsync_mailbox_state *states;
-	unsigned int count;
+	struct dsync_mailbox_state *state;
+	uint8_t *guid;
 	enum dsync_ibc_send_ret ret = DSYNC_IBC_SEND_RET_OK;
 
 	i_assert(brain->master_brain);
 
-	states = array_get(&brain->mailbox_states, &count);
-	while (brain->mailbox_state_idx < count) {
+	if (brain->mailbox_states_iter == NULL) {
+		brain->mailbox_states_iter =
+			hash_table_iterate_init(brain->mailbox_states);
+	}
+
+	for (;;) {
 		if (ret == DSYNC_IBC_SEND_RET_FULL)
 			return;
-		ret = dsync_ibc_send_mailbox_state(brain->ibc,
-				&states[brain->mailbox_state_idx++]);
+		if (!hash_table_iterate(brain->mailbox_states_iter,
+					brain->mailbox_states, &guid, &state))
+			break;
+		ret = dsync_ibc_send_mailbox_state(brain->ibc, state);
 	}
+	hash_table_iterate_deinit(&brain->mailbox_states_iter);
+
 	dsync_ibc_send_end_of_list(brain->ibc);
 	brain->state = DSYNC_STATE_SEND_MAILBOX_TREE;
-	brain->mailbox_state_idx = 0;
+}
+
+static void dsync_mailbox_state_add(struct dsync_brain *brain,
+				    const struct dsync_mailbox_state *state)
+{
+	struct dsync_mailbox_state *dupstate;
+	uint8_t *guid_p;
+
+	dupstate = p_new(brain->pool, struct dsync_mailbox_state, 1);
+	*dupstate = *state;
+	guid_p = dupstate->mailbox_guid;
+	hash_table_insert(brain->mailbox_states, guid_p, dupstate);
 }
 
 static bool dsync_brain_slave_recv_last_common(struct dsync_brain *brain)
@@ -211,7 +233,7 @@
 	i_assert(!brain->master_brain);
 
 	while ((ret = dsync_ibc_recv_mailbox_state(brain->ibc, &state)) > 0) {
-		array_append(&brain->mailbox_states, &state, 1);
+		dsync_mailbox_state_add(brain, &state);
 		changed = TRUE;
 	}
 	if (ret == DSYNC_IBC_RECV_RET_FINISHED) {
@@ -292,6 +314,39 @@
 	return ret;
 }
 
+void dsync_brain_get_state(struct dsync_brain *brain, string_t *output)
+{
+	struct hash_iterate_context *iter;
+	struct dsync_mailbox_node *node;
+	const struct dsync_mailbox_state *new_state;
+	struct dsync_mailbox_state *state;
+	const uint8_t *guid_p;
+	uint8_t *guid;
+
+	/* update mailbox states */
+	array_foreach(&brain->remote_mailbox_states, new_state) {
+		guid_p = new_state->mailbox_guid;
+		state = hash_table_lookup(brain->mailbox_states, guid_p);
+		if (state != NULL)
+			*state = *new_state;
+		else
+			dsync_mailbox_state_add(brain, new_state);
+	}
+
+	/* remove nonexistent mailboxes */
+	iter = hash_table_iterate_init(brain->mailbox_states);
+	while (hash_table_iterate(iter, brain->mailbox_states, &guid, &state)) {
+		node = dsync_mailbox_tree_lookup_guid(brain->local_mailbox_tree,
+						      guid);
+		if (node == NULL ||
+		    node->existence != DSYNC_MAILBOX_NODE_EXISTS)
+			hash_table_remove(brain->mailbox_states, guid);
+	}
+	hash_table_iterate_deinit(&iter);
+
+	dsync_mailbox_states_export(brain->mailbox_states, output);
+}
+
 bool dsync_brain_has_failed(struct dsync_brain *brain)
 {
 	return brain->failed;