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
This commit is contained in:
Carlos Garnacho 2018-12-03 13:09:47 +01:00 committed by Jonas Ådahl
parent 4cac5b4b28
commit 24f400d28a

View File

@ -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,
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);
}
/**