[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