[Spice-devel] [spice PATCH 36/55] main: send MSG_MIGRATE upon vm migration completion

Yonit Halperin yhalperi at redhat.com
Wed Aug 15 00:56:16 PDT 2012


Before sending the above msg, if there is a pending partial msg that
has been read from the agent, we send it to the client. The alternative
was to keep the msg as part of the migration data, and then
to send it to the destination server via the client and to wait there
for the msg chunk completion, before sending it to the client. Of
course, the latter is less efficient.
---
 server/main_channel.c |   10 ++++++++++
 server/red_channel.c  |    2 +-
 server/reds.c         |   44 ++++++++++++++++++++++++++++++++++++++++++++
 server/reds.h         |    1 +
 4 files changed, 56 insertions(+), 1 deletions(-)

diff --git a/server/main_channel.c b/server/main_channel.c
index 648a06d..6cdbc4d 100644
--- a/server/main_channel.c
+++ b/server/main_channel.c
@@ -1160,10 +1160,17 @@ uint64_t main_channel_client_get_bitrate_per_sec(MainChannelClient *mcc)
     return mcc->bitrate_per_sec;
 }
 
+static void main_channel_client_migrate(RedChannelClient *rcc)
+{
+    reds_on_main_channel_migrate(SPICE_CONTAINEROF(rcc, MainChannelClient, base));
+    red_channel_client_default_migrate(rcc);
+}
+
 MainChannel* main_channel_init(void)
 {
     RedChannel *channel;
     ChannelCbs channel_cbs = { NULL, };
+    ClientCbs client_cbs = {NULL, };
 
     channel_cbs.config_socket = main_channel_config_socket;
     channel_cbs.on_disconnect = main_channel_client_on_disconnect;
@@ -1187,6 +1194,9 @@ MainChannel* main_channel_init(void)
     spice_assert(channel);
     red_channel_set_cap(channel, SPICE_MAIN_CAP_SEMI_SEAMLESS_MIGRATE);
 
+    client_cbs.migrate = main_channel_client_migrate;
+    red_channel_register_client_cbs(channel, &client_cbs);
+
     return (MainChannel *)channel;
 }
 
diff --git a/server/red_channel.c b/server/red_channel.c
index 16335a3..803804e 100644
--- a/server/red_channel.c
+++ b/server/red_channel.c
@@ -901,7 +901,7 @@ RedChannel *red_channel_create_parser(int size,
 
 void red_channel_register_client_cbs(RedChannel *channel, ClientCbs *client_cbs)
 {
-    spice_assert(client_cbs->connect);
+    spice_assert(client_cbs->connect || channel->type == SPICE_CHANNEL_MAIN);
     channel->client_cbs.connect = client_cbs->connect;
 
     if (client_cbs->disconnect) {
diff --git a/server/reds.c b/server/reds.c
index a31bad9..f801454 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1219,6 +1219,50 @@ void reds_on_main_mouse_mode_request(void *message, size_t size)
     }
 }
 
+/*
+ * Push partial agent data, even if not all the chunk was consumend,
+ * in order to avoid the roundtrip (src-server->client->dest-server)
+ */
+void reds_on_main_channel_migrate(MainChannelClient *mcc)
+{
+    VDIPortState *agent_state = &reds->agent_state;
+    uint32_t read_data_len;
+
+    spice_assert(reds->num_clients == 1);
+
+    if (agent_state->read_state != VDI_PORT_READ_STATE_READ_DATA) {
+        return;
+    }
+    spice_assert(agent_state->current_read_buf->data &&
+                 agent_state->recive_pos > agent_state->current_read_buf->data);
+    read_data_len = agent_state->recive_pos - agent_state->current_read_buf->data;
+
+    if (agent_state->read_filter.msg_data_to_read ||
+        read_data_len > sizeof(VDAgentMessage)) { /* msg header has been read */
+        VDIReadBuf *read_buf = agent_state->current_read_buf;
+
+        spice_debug("push partial read %u (msg first chunk? %d)", read_data_len,
+                    !agent_state->read_filter.msg_data_to_read);
+
+        read_buf->len = read_data_len;
+        if (vdi_port_read_buf_process(agent_state->vdi_chunk_header.port, read_buf)) {
+            main_channel_client_push_agent_data(mcc,
+                                                read_buf->data,
+                                                read_buf->len,
+                                                vdi_port_read_buf_release,
+                                                read_buf);
+        } else {
+            vdi_port_read_buf_unref(read_buf);
+        }
+
+        spice_assert(agent_state->recive_len);
+        agent_state->message_recive_len += agent_state->recive_len;
+        agent_state->read_state = VDI_PORT_READ_STATE_GET_BUFF;
+        agent_state->current_read_buf = NULL;
+        agent_state->recive_pos = NULL;
+    }
+}
+
 #define MAIN_CHANNEL_MIG_DATA_VERSION 1
 
 typedef struct WriteQueueInfo {
diff --git a/server/reds.h b/server/reds.h
index 779d0db..a575d11 100644
--- a/server/reds.h
+++ b/server/reds.h
@@ -159,6 +159,7 @@ void reds_on_main_mouse_mode_request(void *message, size_t size);
 int reds_on_migrate_dst_set_seamless(MainChannelClient *mcc, uint32_t src_version);
 void reds_on_client_semi_seamless_migrate_complete(RedClient *client);
 void reds_on_client_seamless_migrate_complete(RedClient *client);
+void reds_on_main_channel_migrate(MainChannelClient *mcc);
 void reds_on_char_device_state_destroy(SpiceCharDeviceState *dev);
 
 #endif
-- 
1.7.7.6



More information about the Spice-devel mailing list