[Spice-devel] [spice-gtk v5 13/23] file-xfer: call progress_callback per FileTransferOperation

Victor Toso lists at victortoso.com
Thu Jul 7 09:12:03 UTC 2016


Hi,

On Wed, Jul 06, 2016 at 11:08:53AM -0500, Jonathon Jongsma wrote:
> On Tue, 2016-07-05 at 15:07 +0200, Victor Toso wrote:
> > Before this patch, the progress_callback is being called from
> > SpiceFileTransferTask each time that some data is flushed to the agent
> > of this given xfer-task. The progress value is computed by iterating
> > on all available xfer-tasks.
> > 
> > This patch intend to fix/change:
> > 
> > * The progress_callback should be called only with information related
> >   to the FileTransferOperation of given xfer-task; This was also
> >   suggested by 113093dd00a1cf10f6d3c3589b7589a184cec081;
> > 
> > * In case a SpiceFileTransferTask is cancelled or has an error, we
> >   remove the remaining bytes (not sent) of this file from the
> >   transfer_size;
> > 
> > * The progress_callback should not be done from SpiceFileTransferTask
> >   context by (proposed) design. As the transfer operation starts in
> >   spice_main_file_copy_async(), FileTransferOperation should handle
> >   these calls.
> > ---
> >  src/channel-main.c | 103 ++++++++++++++++++++++++++++++--------------------
> > ---
> >  1 file changed, 58 insertions(+), 45 deletions(-)
> > 
> > diff --git a/src/channel-main.c b/src/channel-main.c
> > index e57d2ba..c5540e7 100644
> > --- a/src/channel-main.c
> > +++ b/src/channel-main.c
> > @@ -61,8 +61,6 @@ static GHashTable
> > *spice_file_transfer_task_create_tasks(GFile **files,
> >                                                           SpiceMainChannel
> > *channel,
> >                                                           GFileCopyFlags
> > flags,
> >                                                           GCancellable
> > *cancellable,
> > -                                                         GFileProgressCallbac
> > k progress_callback,
> > -                                                         gpointer
> > progress_callback_data,
> >                                                           GAsyncReadyCallback
> > callback,
> >                                                           gpointer user_data);
> >  static void spice_file_transfer_task_init_task_async(SpiceFileTransferTask
> > *self,
> > @@ -78,6 +76,8 @@ static gssize
> > spice_file_transfer_task_read_finish(SpiceFileTransferTask *self,
> >                                                     GAsyncResult *result,
> >                                                     char **buffer,
> >                                                     GError **error);
> > +static guint64 spice_file_transfer_task_get_file_size(SpiceFileTransferTask
> > *self);
> > +static guint64 spice_file_transfer_task_get_bytes_read(SpiceFileTransferTask
> > *self);
> >  
> >  /**
> >   * SECTION:file-transfer-task
> > @@ -108,8 +108,6 @@ struct _SpiceFileTransferTask
> >      GFileInputStream               *file_stream;
> >      GFileCopyFlags                 flags;
> >      GCancellable                   *cancellable;
> > -    GFileProgressCallback          progress_callback;
> > -    gpointer                       progress_callback_data;
> >      GAsyncReadyCallback            callback;
> >      gpointer                       user_data;
> >      char                           *buffer;
> > @@ -161,6 +159,12 @@ typedef struct {
> >  typedef struct {
> >      GHashTable                 *xfer_task;
> >      SpiceMainChannel           *channel;
> > +    GFileProgressCallback       progress_callback;
> > +    gpointer                    progress_callback_data;
> > +    struct {
> > +        goffset                 total_sent;
> > +        goffset                 transfer_size;
> > +    } stats;
> >  } FileTransferOperation;
> >  
> >  struct _SpiceMainChannelPrivate  {
> > @@ -273,6 +277,7 @@ static SpiceFileTransferTask
> > *spice_main_channel_find_xfer_task_by_task_id(Spice
> >  static void file_transfer_operation_task_finished(SpiceFileTransferTask
> > *xfer_task,
> >                                                    GError *error,
> >                                                    gpointer userdata);
> > +static void file_transfer_operation_send_progress(SpiceFileTransferTask
> > *xfer_task);
> >  
> >  /* ------------------------------------------------------------------ */
> >  
> > @@ -1883,39 +1888,6 @@ static void file_xfer_close_cb(GObject      *object,
> >      g_object_unref(self);
> >  }
> >  
> > -static void file_xfer_send_progress(SpiceFileTransferTask *xfer_task)
> > -{
> > -    goffset read = 0;
> > -    goffset total = 0;
> > -    GHashTableIter iter;
> > -    gpointer key, value;
> > -    SpiceMainChannel *channel;
> > -
> > -    g_return_if_fail(xfer_task != NULL);
> > -
> > -    if (!xfer_task->progress_callback)
> > -        return;
> > -
> > -    channel = spice_file_transfer_task_get_channel(xfer_task);
> > -
> > -    /* FIXME: This iterates to all SpiceFileTransferTasks, including ones
> > from
> > -     * different FileTransferOperation. The progress_callback should only
> > return
> > -     * the info related to its FileTransferOperation */
> > -    /* since the progress_callback does not have a parameter to indicate
> > -     * which file the progress is associated with, report progress on all
> > -     * current transfers */
> > -    g_hash_table_iter_init(&iter, channel->priv->file_xfer_tasks);
> > -    while (g_hash_table_iter_next(&iter, &key, &value)) {
> > -        SpiceFileTransferTask *t;
> > -
> > -        t = spice_main_channel_find_xfer_task_by_task_id(channel,
> > GPOINTER_TO_UINT(key));
> > -        read += t->read_bytes;
> > -        total += t->file_size;
> > -    }
> > -
> > -    xfer_task->progress_callback(read, total, xfer_task-
> > >progress_callback_data);
> > -}
> > -
> >  static void file_xfer_data_flushed_cb(GObject *source_object,
> >                                        GAsyncResult *res,
> >                                        gpointer user_data)
> > @@ -1930,7 +1902,7 @@ static void file_xfer_data_flushed_cb(GObject
> > *source_object,
> >          return;
> >      }
> >  
> > -    file_xfer_send_progress(self);
> > +    file_transfer_operation_send_progress(self);
> >  
> >      if (spice_util_get_debug()) {
> >          const GTimeSpan interval = 20 * G_TIME_SPAN_SECOND;
> > @@ -1971,11 +1943,13 @@ static void file_xfer_read_async_cb(GObject
> > *source_object,
> >                                      GAsyncResult *res,
> >                                      gpointer user_data)
> >  {
> > +    FileTransferOperation *xfer_op;
> >      SpiceFileTransferTask *xfer_task;
> >      SpiceMainChannel *channel;
> >      gssize count;
> >      char *buffer;
> >      GCancellable *cancellable;
> > +    guint32 task_id;
> >      GError *error = NULL;
> >  
> >      xfer_task = SPICE_FILE_TRANSFER_TASK(source_object);
> > @@ -1994,6 +1968,10 @@ static void file_xfer_read_async_cb(GObject
> > *source_object,
> >          return;
> >      }
> >  
> > +    task_id = spice_file_transfer_task_get_id(xfer_task);
> > +    xfer_op = g_hash_table_lookup(channel->priv->file_xfer_tasks,
> > GUINT_TO_POINTER(task_id));
> > +    xfer_op->stats.total_sent += count;
> > +
> >      cancellable = spice_file_transfer_task_get_cancellable(xfer_task);
> >      file_xfer_flush_async(channel, cancellable, file_xfer_data_flushed_cb,
> > xfer_task);
> >  }
> > @@ -3027,6 +3005,7 @@ static void file_xfer_init_task_async_cb(GObject *obj,
> > GAsyncResult *res, gpoint
> >      VDAgentFileXferStartMessage msg;
> >      guint64 file_size;
> >      gsize data_len;
> > +    FileTransferOperation *xfer_op;
> >      GError *error = NULL;
> >  
> >      xfer_task = SPICE_FILE_TRANSFER_TASK(obj);
> > @@ -3039,6 +3018,9 @@ static void file_xfer_init_task_async_cb(GObject *obj,
> > GAsyncResult *res, gpoint
> >      basename = g_file_info_get_attribute_as_string(info,
> > G_FILE_ATTRIBUTE_STANDARD_NAME);
> >      file_size = g_file_info_get_attribute_uint64(info,
> > G_FILE_ATTRIBUTE_STANDARD_SIZE);
> >  
> > +    xfer_op = data;
> > +    xfer_op->stats.transfer_size += file_size;
> > +
> >      keyfile = g_key_file_new();
> >      g_key_file_set_string(keyfile, "vdagent-file-xfer", "name", basename);
> >      g_key_file_set_uint64(keyfile, "vdagent-file-xfer", "size", file_size);
> > @@ -3144,6 +3126,12 @@ static void
> > file_transfer_operation_task_finished(SpiceFileTransferTask *xfer_ta
> >          return;
> >      }
> >  
> > +    if (error) {
> > +        guint64 file_size =
> > spice_file_transfer_task_get_file_size(xfer_task);
> > +        guint64 bytes_read =
> > spice_file_transfer_task_get_bytes_read(xfer_task);
> > +        xfer_op->stats.transfer_size -= (file_size - bytes_read);
> > +    }
> > +
>
> It might be useful to have a code comment here explaining why we're
> doing this?  or maybe it's obvious?

Considering that we discussed a bit about it, I agree that we should
have some explanation in the code as well. (I put an extra bullet about
it in the commit log)

<snip>
 /* On error or cancellation of a SpiceFileTransferTask we remove the
  * remaining bytes from transfer-size in order to keep the coherence of
  * the information we provide to the user (total-sent and transfer-size)
  * in the progress-callback */

>
> >      /* Remove and free SpiceFileTransferTask */
> >      g_hash_table_remove(xfer_op->xfer_task, GUINT_TO_POINTER(task_id));
> >      g_object_unref(xfer_task);
> > @@ -3156,6 +3144,23 @@ static void
> > file_transfer_operation_task_finished(SpiceFileTransferTask *xfer_ta
> >          file_transfer_operation_free(xfer_op);
> >  }
> >  
> > +static void file_transfer_operation_send_progress(SpiceFileTransferTask
> > *xfer_task)
jjjjjjjjjjjjjjjjj> > +{
> > +    FileTransferOperation *xfer_op;
> > +    SpiceMainChannel *channel;
> > +    guint32 task_id;
> > +
> > +    channel = spice_file_transfer_task_get_channel(xfer_task);
> > +    task_id = spice_file_transfer_task_get_id(xfer_task);
> > +    xfer_op = g_hash_table_lookup(channel->priv->file_xfer_tasks,
> > GUINT_TO_POINTER(task_id));
> > +    g_return_if_fail(xfer_op != NULL);
> > +
> > +    if (xfer_op->progress_callback)
> > +        xfer_op->progress_callback(xfer_op->stats.total_sent,
> > +                                   xfer_op->stats.transfer_size,
> > +                                   xfer_op->progress_callback_data);
> > +}
> > +
> >  static SpiceFileTransferTask *spice_file_transfer_task_new(SpiceMainChannel
> > *channel,
> >                                                             GFile *file,
> >                                                             GCancellable
> > *cancellable);
> > @@ -3225,12 +3230,12 @@ void spice_main_file_copy_async(SpiceMainChannel
> > *channel,
> >  
> >      xfer_op = g_new0(FileTransferOperation, 1);
> >      xfer_op->channel = channel;
> > +    xfer_op->progress_callback = progress_callback;
> > +    xfer_op->progress_callback_data = progress_callback_data;
> >      xfer_op->xfer_task = spice_file_transfer_task_create_tasks(sources,
> >                                                                 channel,
> >                                                                 flags,
> >                                                                 cancellable,
> > -                                                               progress_callb
> > ack,
> > -                                                               progress_callb
> > ack_data,
> >                                                                 callback,
> >                                                                 user_data);
> >      g_hash_table_iter_init(&iter, xfer_op->xfer_task);
> > @@ -3248,7 +3253,7 @@ void spice_main_file_copy_async(SpiceMainChannel
> > *channel,
> >  
> >          spice_file_transfer_task_init_task_async(xfer_task,
> >                                                   file_xfer_init_task_async_cb
> > ,
> > -                                                 NULL);
> > +                                                 xfer_op);
> >      }
> >  }
> >  
> > @@ -3293,6 +3298,18 @@ static GCancellable
> > *spice_file_transfer_task_get_cancellable(SpiceFileTransferT
> >      return self->cancellable;
> >  }
> >  
> > +static guint64 spice_file_transfer_task_get_file_size(SpiceFileTransferTask
> > *self)
> > +{
> > +    g_return_val_if_fail(self != NULL, 0);
> > +    return self->file_size;
> > +}
> > +
> > +static guint64 spice_file_transfer_task_get_bytes_read(SpiceFileTransferTask
> > *self)
> > +{
> > +    g_return_val_if_fail(self != NULL, 0);
> > +    return self->read_bytes;
> > +}
> > +
> >  /* Helper function which only creates a SpiceFileTransferTask per GFile
> >   * in @files and returns a HashTable mapping task-id to the task itself
> >   * Note that the HashTable does not free its values upon destruction:
> > @@ -3302,8 +3319,6 @@ static GHashTable
> > *spice_file_transfer_task_create_tasks(GFile **files,
> >                                                           SpiceMainChannel
> > *channel,
> >                                                           GFileCopyFlags
> > flags,
> >                                                           GCancellable
> > *cancellable,
> > -                                                         GFileProgressCallbac
> > k progress_callback,
> > -                                                         gpointer
> > progress_callback_data,
> >                                                           GAsyncReadyCallback
> > callback,
> >                                                           gpointer user_data)
> >  {
> > @@ -3327,8 +3342,6 @@ static GHashTable
> > *spice_file_transfer_task_create_tasks(GFile **files,
> >          /* FIXME: Move the xfer-task initialization to
> > spice_file_transfer_task_new() */
> >          xfer_task = spice_file_transfer_task_new(channel, files[i],
> > task_cancellable);
> >          xfer_task->flags = flags;
> > -        xfer_task->progress_callback = progress_callback;
> > -        xfer_task->progress_callback_data = progress_callback_data;
> >          xfer_task->callback = callback;
> >          xfer_task->user_data = user_data;
> >  
>
> Acked-by: Jonathon Jongsma <jjongsma at redhat.com>

Thanks,

> _______________________________________________
> Spice-devel mailing list
> Spice-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/spice-devel


More information about the Spice-devel mailing list