[gnome-photos] base-item: Add a cache to batch together pipeline loading operations



commit a6d1f6bcb7677d347c8ee3a3a6185bf2ef7e7023
Author: Debarshi Ray <debarshir gnome org>
Date:   Mon Feb 27 01:06:57 2017 +0100

    base-item: Add a cache to batch together pipeline loading operations
    
    Some asynchronous operations assume that there won't be multiple
    invocations running concurrently. eg., photos_base_item_load_async.
    The simpler issue is that the code doesn't consider that instance
    variables might have already been set by another instance of the
    operation. The deeper quandary is that running multiple separate
    instances is wasteful. eg., there is no need to load an entire item
    multiple times in quick succession because reading and decoding a big
    image file consumes a significant amount of CPU and I/O. It will be
    better to run the operation only once and multiplex the result across
    several callers.
    
    Fortunately, at the moment, this is purely a theoretical snag. The UI
    prevents multiple instances of such tasks from actually coinciding.
    However, it will be good to fix this so that the code is robust enough
    to sustain future changes.
    
    As an experiment, use an EggTaskCache to batch and cache PhotosPipeline
    loading operations. Loading a pipeline is an easier task, and a
    subsequent commit will change photos_base_item_pipeline_is_edited_async
    to only load the pipeline, and not the entire item. That will benefit
    from having an EggTaskCache to batch together concurrent pipeline
    loading operations from photos_base_item_load_async and
    photos_base_item_pipeline_is_edited_async.

 src/photos-base-item.c |   73 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 73 insertions(+), 0 deletions(-)
---
diff --git a/src/photos-base-item.c b/src/photos-base-item.c
index 713fdd4..c4f1503 100644
--- a/src/photos-base-item.c
+++ b/src/photos-base-item.c
@@ -40,6 +40,7 @@
 #include <tracker-sparql.h>
 
 #include "egg-counter.h"
+#include "egg-task-cache.h"
 #include "photos-application.h"
 #include "photos-base-item.h"
 #include "photos-collection-icon-watcher.h"
@@ -177,6 +178,7 @@ struct _PhotosBaseItemSaveToStreamData
   gdouble zoom;
 };
 
+static EggTaskCache *pipeline_cache;
 static GdkPixbuf *failed_icon;
 static GdkPixbuf *thumbnailing_icon;
 static GThreadPool *create_thumbnail_pool;
@@ -425,6 +427,7 @@ photos_base_item_clear_pixels (PhotosBaseItem *self)
   priv = photos_base_item_get_instance_private (self);
 
   priv->buffer_source = NULL;
+  egg_task_cache_evict (pipeline_cache, self);
 
   g_clear_object (&priv->edit_graph);
   g_clear_object (&priv->pipeline);
@@ -1459,6 +1462,64 @@ photos_base_item_load_buffer_finish (PhotosBaseItem *self, GAsyncResult *res, GE
 
 
 static void
+photos_base_item_load_pipeline_task_cache_populate_new (GObject *source_object,
+                                                        GAsyncResult *res,
+                                                        gpointer user_data)
+{
+  GError *error;
+  GTask *task = G_TASK (user_data);
+  PhotosPipeline *pipeline = NULL;
+
+  error = NULL;
+  pipeline = photos_pipeline_new_finish (res, &error);
+  if (error != NULL)
+    {
+      g_task_return_error (task, error);
+      goto out;
+    }
+
+  g_task_return_pointer (task, g_object_ref (pipeline), g_object_unref);
+
+ out:
+  g_clear_object (&pipeline);
+  g_object_unref (task);
+}
+
+
+static void
+photos_base_item_load_pipeline_task_cache_populate (EggTaskCache *cache,
+                                                    gconstpointer key,
+                                                    GTask *task,
+                                                    gpointer user_data)
+{
+  PhotosBaseItem *self = PHOTOS_BASE_ITEM ((gpointer) key);
+  PhotosBaseItemClass *class;
+  GCancellable *cancellable;
+  gchar *uri = NULL;
+
+  cancellable = g_task_get_cancellable (task);
+
+  class = PHOTOS_BASE_ITEM_GET_CLASS (self);
+  if (class->create_pipeline_path != NULL)
+    {
+      gchar *path;
+
+      path = class->create_pipeline_path (self);
+      uri = photos_utils_convert_path_to_uri (path);
+      g_free (path);
+    }
+
+  photos_pipeline_new_async (NULL,
+                             uri,
+                             cancellable,
+                             photos_base_item_load_pipeline_task_cache_populate_new,
+                             g_object_ref (task));
+
+  g_free (uri);
+}
+
+
+static void
 photos_base_item_load_process (GObject *source_object, GAsyncResult *res, gpointer user_data)
 {
   GTask *task = G_TASK (user_data);
@@ -2696,6 +2757,18 @@ photos_base_item_class_init (PhotosBaseItemClass *class)
   g_object_class_override_property (object_class, PROP_SECONDARY_TEXT, "secondary-text");
   g_object_class_override_property (object_class, PROP_URI, "uri");
 
+  pipeline_cache = egg_task_cache_new (g_direct_hash,
+                                       g_direct_equal,
+                                       NULL,
+                                       NULL,
+                                       g_object_ref,
+                                       g_object_unref,
+                                       0,
+                                       photos_base_item_load_pipeline_task_cache_populate,
+                                       NULL,
+                                       NULL);
+  egg_task_cache_set_name (pipeline_cache, "PhotosPipeline cache");
+
   create_thumbnail_pool = g_thread_pool_new (photos_base_item_create_thumbnail_in_thread_func,
                                              NULL,
                                              1,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]