[gnome-shell/wip/chergert/3-28-perf-fixes: 4/5] shell-global: Make saving of persistent state asynchronous



commit 166a8fb0d8700b48cafd12e1118f7b2641e04a82
Author: Carlos Garnacho <carlosg gnome org>
Date:   Mon Dec 3 13:09:47 2018 +0100

    shell-global: Make saving of persistent state asynchronous
    
    This is an expensive operation that is best avoided in the main loop. Given
    the call doesn't care much about returning error or status, it can just
    be made async within.
    
    Every operation on a given file will be destructive wrt previous
    operations on the same file, so we just cancel any pending operation on
    it before batching the current one.
    
    Closes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/815
    
    Conflicts:
            src/shell-global.c

 src/shell-global.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 75 insertions(+), 10 deletions(-)
---
diff --git a/src/shell-global.c b/src/shell-global.c
index c67ac4e4ac..a4319ff759 100644
--- a/src/shell-global.c
+++ b/src/shell-global.c
@@ -87,6 +87,8 @@ struct _ShellGlobal {
   /* For sound notifications */
   ca_context *sound_context;
 
+  GHashTable *save_ops;
+
   gboolean has_modal;
   gboolean frame_timestamps;
   gboolean frame_finish_timestamp;
@@ -322,6 +324,10 @@ shell_global_init (ShellGlobal *global)
                                      NULL);
 
   g_strfreev (search_path);
+
+  global->save_ops = g_hash_table_new_full (g_file_hash,
+                                            (GEqualFunc) g_file_equal,
+                                            g_object_unref, g_object_unref);
 }
 
 static void
@@ -341,6 +347,8 @@ shell_global_finalize (GObject *object)
   g_free (global->imagedir);
   g_free (global->userdatadir);
 
+  g_hash_table_unref (global->save_ops);
+
   G_OBJECT_CLASS(shell_global_parent_class)->finalize (object);
 }
 
@@ -1757,20 +1765,77 @@ shell_global_get_session_mode (ShellGlobal *global)
 }
 
 static void
-save_variant (GFile      *dir,
-              const char *property_name,
-              GVariant   *variant)
+delete_variant_cb (GObject      *object,
+                   GAsyncResult *result,
+                   gpointer      user_data)
+{
+  ShellGlobal *global = user_data;
+  GError *error = NULL;
+
+  if (!g_file_delete_finish (G_FILE (object), result, &error))
+    {
+      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        {
+          g_warning ("Could not delete runtime/persistent state file: %s\n",
+                     error->message);
+        }
+
+      g_error_free (error);
+    }
+
+  g_hash_table_remove (global->save_ops, object);
+}
+
+static void
+replace_variant_cb (GObject      *object,
+                    GAsyncResult *result,
+                    gpointer      user_data)
+{
+  ShellGlobal *global = user_data;
+  GError *error = NULL;
+
+  if (!g_file_replace_contents_finish (G_FILE (object), result, NULL, &error))
+    {
+      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+        {
+          g_warning ("Could not replace runtime/persistent state file: %s\n",
+                     error->message);
+        }
+
+      g_error_free (error);
+    }
+
+  g_hash_table_remove (global->save_ops, object);
+}
+
+static void
+save_variant (ShellGlobal *global,
+              GFile       *dir,
+              const char  *property_name,
+              GVariant    *variant)
 {
   GFile *path = g_file_get_child (dir, property_name);
+  GCancellable *cancellable;
+
+  cancellable = g_hash_table_lookup (global->save_ops, path);
+  g_cancellable_cancel (cancellable);
+
+  cancellable = g_cancellable_new ();
+  g_hash_table_insert (global->save_ops, g_object_ref (path), cancellable);
 
   if (variant == NULL || g_variant_get_data (variant) == NULL)
-    (void) g_file_delete (path, NULL, NULL);
+    {
+      g_file_delete_async (path, G_PRIORITY_DEFAULT, cancellable,
+                           delete_variant_cb, global);
+    }
   else
     {
-      gsize size = g_variant_get_size (variant);
-      g_file_replace_contents (path, g_variant_get_data (variant), size,
-                               NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION,
-                               NULL, NULL, NULL);
+      g_file_replace_contents_async (path,
+                                     g_variant_get_data (variant),
+                                     g_variant_get_size (variant),
+                                     NULL, FALSE,
+                                     G_FILE_CREATE_REPLACE_DESTINATION,
+                                     cancellable, replace_variant_cb, global);
     }
 
   g_object_unref (path);
@@ -1824,7 +1889,7 @@ shell_global_set_runtime_state (ShellGlobal  *global,
                                 const char   *property_name,
                                 GVariant     *variant)
 {
-  save_variant (global->runtime_state_path, property_name, variant);
+  save_variant (global, global->runtime_state_path, property_name, variant);
 }
 
 /**
@@ -1859,7 +1924,7 @@ shell_global_set_persistent_state (ShellGlobal *global,
                                    const char  *property_name,
                                    GVariant    *variant)
 {
-  save_variant (global->userdatadir_path, property_name, variant);
+  save_variant (global, global->userdatadir_path, property_name, variant);
 }
 
 /**


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