[Bug 63402] Avatar image caching is not asynchronous

bugzilla-daemon at freedesktop.org bugzilla-daemon at freedesktop.org
Tue Sep 17 03:27:31 PDT 2013


https://bugs.freedesktop.org/show_bug.cgi?id=63402

--- Comment #6 from Chandni Verma <chandniverma2112 at gmail.com> ---
(In reply to comment #5)
> Thanks for looking into this!
> 
> I'm reviewing a flattened version here. I'd suggest attaching a new,
> flattened version with these changes - it'll be easier to review that way.
> 
> +  write_data *avatar_data = g_slice_new (write_data);
> +  write_data *mime_data = g_slice_new (write_data);
> +  AvatarFileWrittenData *avatar_file_written_data = g_slice_new
> +      (AvatarFileWrittenData);
> 
> These don't need to be separate structs. I'd use a single struct to
> represent the whole operation:
> 
> typedef struct {
>     TpContact *self;
>     gchar *token;
>     gchar *mime_type;
>     GFile *mime_file;
> } WriteAvatarData;
> 
> (and if you discover you need more fields, you can add them).

Done.


> 
> You don't actually need to copy the avatar data into this struct, as far as
> I can see, because you only use it for the first
> g_file_replace_contents_async() call (which will, internally, copy it).

I am not quite acquainted with GTask but if I remove the avatar data the test
./tests/dbus/test-contacts which checks this code-path fails with error:

ERROR:contacts.c:599:create_contact_with_fake_avatar: assertion failed (content
== avatar_data): ("\210\177*\b-avatar-data" == "fake-avatar-data")



> 
> It looks as though you leak the memory for these structs in error code
> paths. I would suggest not allocating them until you need them (that would
> be just after the comment "Save avatar in cache..." here, I think) and then
> you won't need to worry about cleanup on errors.
> 
> +  avatar_file = g_file_new_for_path (filename);
> 
> You don't unref this, so it's leaked. Unref it after calling
> g_file_replace_contents_async().

Done, but how do you know g_file_replace_contents_async() keeps it's own
reference? Also, the parameter is called "input file".


> 
> +      g_free (avatar_data->str);
> +      g_slice_free (write_data, avatar_data);
> +      g_free (mime_data->str);
> +      g_slice_free (write_data, mime_data);
> +      g_object_unref (avatar_file_written_data->mime_file);
> +      g_slice_free (AvatarFileWrittenData, avatar_file_written_data);
> 
> This should be in a new function avatar_file_written_data_free() (or
> write_avatar_data_free() if you use the naming I suggested) so you don't
> have to keep duplicating it.
> 
> I haven't reviewed all the duplicate copies of freeing the struct and its
> contents, so there might be memory leaks there - but when you do this, it'll
> be obvious at a glance whether things are being freed correctly.

I guess this isn't required now.


> 
> +  if (avatar_data->self == NULL)
> +    {
> +      g_free (avatar_data->str);
> +      g_slice_free (write_data, avatar_data);
> +      g_free (mime_data->str);
> +      g_slice_free (write_data, mime_data);
> +      g_object_unref (avatar_file_written_data->mime_file);
> +      g_slice_free (AvatarFileWrittenData, avatar_file_written_data);
> +      return;
> +    }
> +  /* Update the avatar token if a newer one is given */
> +  contact_set_avatar_token (avatar_data->self, avatar_data->str, FALSE);
> +
> +  tp_clear_object (&avatar_data->self->priv->avatar_file);
> +  avatar_data->self->priv->avatar_file = (GFile *) file;
> +  g_free (avatar_data->str);
> +  g_slice_free (write_data, avatar_data);
> +
> +  /* Now that the avatar-file has been written, write the mime-file. */
> +  g_file_replace_contents_async (avatar_file_written_data->mime_file,
> +      mime_data->str, strlen (mime_data->str), NULL, FALSE,
> G_FILE_CREATE_NONE,
> +      NULL, &mime_file_written, mime_data);
> +
> +  g_slice_free (AvatarFileWrittenData, avatar_file_written_data);
> 
> There's a logic error here: if the TpContact is NULL, you don't write the
> MIME type to a file. If you're signalling the avatar token here, I'd do:
> 
>     if (data->self != NULL)
>       {
>         contact_set_avatar_token (data->self, data->token, FALSE);
>       }
> 
>     g_file_replace_contents_async(...)
> 
> but actually it'd make more sense to delay signalling the changed avatar
> token until the end as well - the application can't usefully act on it until
> you've cached the file.
> 
> If writing the avatar data fails, it's probably still worth trying to write
> out the MIME type, and if either or both fail, I think it's still worth
> signalling the token change (and perhaps also the MIME type and
> avatar-file), even though the current implementation didn't. That simplifies
> things down to one code path.
> 
> General points
> --------------
> 
> In both g_file_replace_contents_async calls, I think you should use
> G_FILE_CREATE_PRIVATE|G_FILE_CREATE_REPLACE_DESTINATION for the overwrite -
> we're potentially dealing with private data here, and REPLACE_DESTINATION
> gives the closest match for how g_file_set_contents() worked.
> 
> Minor nitpicking stuff
> ----------------------
> 
> +typedef struct{
> 
> Coding style: space before "{".
> 
> +static void mime_file_written (GObject *file,
> +                               GAsyncResult *res,
> +                               gpointer user_data){
> 
> Coding style: newlines after "static void" and ")" here. We also usually
> indent the second and subsequent arguments in function definitions by 4
> spaces, rather than lining them up with the "(" - please follow
> <http://telepathy.freedesktop.org/wiki/Style/> and/or the style of nearby
> code.
> 
> +  GError* error = NULL;
> +  write_data* mime_data = (write_data *) user_data;
> 
> Coding style: "type *value" not "type* value"
> (<http://lists.freedesktop.org/archives/systemd-devel/2013-April/010753.
> html> for the reason).
> 
> You don't need a cast when going from gpointer (or equivalently, void *) to
> SomeType *.
> 
> There are a lot of (GFile *) casts here. I'd prefer this:
> 
>     static void
>     something_written (GObject *source_object,
>         GAsyncResult *res,
>         gpointer user_data)
>     {
>       GFile *file = G_FILE (source_object);
>       WriteFileData *data = user_data;
>       GError *error = NULL;
> 
>       if (!g_file_replace_contents_finish (file, res, NULL, &error))
>         {
>           ...
>         }
> 
>        ... (and the same for all other uses of the GFile) ...
>     }
> 
> Coding style: blank line after the variable declarations, please (like in
> the example immediately before this comment).
> 
> Coding style: it's conventional to check the return from the _finish
> function, rather than the contents of 'error', as in the same example. If it
> fails, it's OK to assume that error is non-NULL.

Fixed.
Patch follows.
It seems that the test required some changes though, I haven't looked into it
yet.

-- 
You are receiving this mail because:
You are the QA Contact for the bug.


More information about the telepathy-bugs mailing list