core: Add async save method to MetaSessionManager
Allow saving the session gvdb file in the background, with as little overhead in the main thread as possible. We still need to serialize all created/deserialized MetaSessionState to a GVDB hashtable there, in order to avoid these being poked from the async task thread. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3825>
This commit is contained in:
parent
8468888508
commit
8b9bf6b051
2 changed files with 146 additions and 28 deletions
|
@ -31,9 +31,20 @@
|
||||||
|
|
||||||
#define SESSION_FILE_NAME "session.gvdb"
|
#define SESSION_FILE_NAME "session.gvdb"
|
||||||
|
|
||||||
|
typedef struct _MetaSessionData MetaSessionData;
|
||||||
|
|
||||||
|
struct _MetaSessionData
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
GHashTable *new_table; /* Gvdb table */
|
||||||
|
GHashTable *deleted_sessions; /* Set of session names */
|
||||||
|
GvdbTable *gvdb_table;
|
||||||
|
};
|
||||||
|
|
||||||
struct _MetaSessionManager
|
struct _MetaSessionManager
|
||||||
{
|
{
|
||||||
GObject parent_instance;
|
GObject parent_instance;
|
||||||
|
GMutex mutex;
|
||||||
GHashTable *sessions; /* Session name -> MetaSessionState */
|
GHashTable *sessions; /* Session name -> MetaSessionState */
|
||||||
GHashTable *deleted_sessions; /* Set of session names */
|
GHashTable *deleted_sessions; /* Set of session names */
|
||||||
GvdbTable *gvdb_table;
|
GvdbTable *gvdb_table;
|
||||||
|
@ -116,6 +127,7 @@ meta_session_manager_finalize (GObject *object)
|
||||||
g_clear_pointer (&session_manager->gvdb_table, gvdb_table_free);
|
g_clear_pointer (&session_manager->gvdb_table, gvdb_table_free);
|
||||||
g_clear_pointer (&session_manager->name, g_free);
|
g_clear_pointer (&session_manager->name, g_free);
|
||||||
g_clear_fd (&session_manager->fd, NULL);
|
g_clear_fd (&session_manager->fd, NULL);
|
||||||
|
g_mutex_clear (&session_manager->mutex);
|
||||||
|
|
||||||
G_OBJECT_CLASS (meta_session_manager_parent_class)->finalize (object);
|
G_OBJECT_CLASS (meta_session_manager_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
@ -151,6 +163,7 @@ meta_session_manager_init (MetaSessionManager *session_manager)
|
||||||
g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
|
g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
|
||||||
session_manager->deleted_sessions =
|
session_manager->deleted_sessions =
|
||||||
g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||||
|
g_mutex_init (&session_manager->mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
@ -350,16 +363,21 @@ snapshot_gvdb_recursively (GvdbTable *table,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
static void
|
||||||
meta_session_manager_save_sync (MetaSessionManager *manager,
|
meta_session_data_free (MetaSessionData *session_data)
|
||||||
GError **error)
|
{
|
||||||
|
g_clear_pointer (&session_data->new_table, g_hash_table_unref);
|
||||||
|
g_clear_pointer (&session_data->deleted_sessions, g_hash_table_unref);
|
||||||
|
g_free (session_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
meta_session_data_save (MetaSessionData *session_data,
|
||||||
|
GError **error)
|
||||||
{
|
{
|
||||||
GHashTableIter iter;
|
|
||||||
GHashTable *table;
|
|
||||||
MetaSessionState *session_state;
|
|
||||||
g_autofree char *session_dir = NULL, *session_file = NULL;
|
g_autofree char *session_dir = NULL, *session_file = NULL;
|
||||||
|
|
||||||
if (!manager->name)
|
if (!session_data->name)
|
||||||
{
|
{
|
||||||
g_set_error (error,
|
g_set_error (error,
|
||||||
G_IO_ERROR,
|
G_IO_ERROR,
|
||||||
|
@ -369,8 +387,7 @@ meta_session_manager_save_sync (MetaSessionManager *manager,
|
||||||
}
|
}
|
||||||
|
|
||||||
session_dir = g_build_filename (g_get_user_data_dir (),
|
session_dir = g_build_filename (g_get_user_data_dir (),
|
||||||
manager->name,
|
session_data->name, NULL);
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (g_mkdir_with_parents (session_dir, 0700) < 0)
|
if (g_mkdir_with_parents (session_dir, 0700) < 0)
|
||||||
{
|
{
|
||||||
|
@ -381,39 +398,132 @@ meta_session_manager_save_sync (MetaSessionManager *manager,
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
session_file = g_build_filename (session_dir, SESSION_FILE_NAME, NULL);
|
session_file = g_build_filename (session_dir,
|
||||||
|
SESSION_FILE_NAME,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (session_data->gvdb_table)
|
||||||
|
{
|
||||||
|
g_auto (GStrv) names;
|
||||||
|
gsize len, i;
|
||||||
|
|
||||||
|
names = gvdb_table_get_names (session_data->gvdb_table, &len);
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
if (g_hash_table_contains (session_data->new_table, names[i]))
|
||||||
|
continue;
|
||||||
|
if (g_hash_table_contains (session_data->deleted_sessions, names[i]))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
snapshot_gvdb_recursively (session_data->gvdb_table,
|
||||||
|
session_data->new_table, names[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return gvdb_table_write_contents (session_data->new_table, session_file,
|
||||||
|
FALSE, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
save_session_async (GTask *task,
|
||||||
|
gpointer source_object,
|
||||||
|
gpointer task_data,
|
||||||
|
GCancellable *cancellable)
|
||||||
|
{
|
||||||
|
MetaSessionManager *session_manager = source_object;
|
||||||
|
g_autoptr (GError) error = NULL;
|
||||||
|
|
||||||
|
g_mutex_lock (&session_manager->mutex);
|
||||||
|
|
||||||
|
if (meta_session_data_save (task_data, &error))
|
||||||
|
g_task_return_boolean (task, TRUE);
|
||||||
|
else
|
||||||
|
g_task_return_error (task, g_steal_pointer (&error));
|
||||||
|
|
||||||
|
g_mutex_unlock (&session_manager->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MetaSessionData *
|
||||||
|
meta_session_manager_snapshot (MetaSessionManager *manager)
|
||||||
|
{
|
||||||
|
MetaSessionState *session_state;
|
||||||
|
MetaSessionData *session_data;
|
||||||
|
GHashTableIter iter;
|
||||||
|
const gchar *name;
|
||||||
|
|
||||||
|
session_data = g_new0 (MetaSessionData, 1);
|
||||||
|
session_data->gvdb_table = manager->gvdb_table;
|
||||||
|
session_data->new_table = gvdb_hash_table_new (NULL, NULL);
|
||||||
|
session_data->name = manager->name;
|
||||||
|
|
||||||
|
session_data->deleted_sessions =
|
||||||
|
g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||||
|
g_hash_table_iter_init (&iter, manager->deleted_sessions);
|
||||||
|
while (g_hash_table_iter_next (&iter, (gpointer *) &name, NULL))
|
||||||
|
g_hash_table_add (session_data->deleted_sessions, g_strdup (name));
|
||||||
|
|
||||||
g_hash_table_iter_init (&iter, manager->sessions);
|
g_hash_table_iter_init (&iter, manager->sessions);
|
||||||
table = gvdb_hash_table_new (NULL, NULL);
|
|
||||||
|
|
||||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer*) &session_state))
|
while (g_hash_table_iter_next (&iter, NULL, (gpointer*) &session_state))
|
||||||
{
|
{
|
||||||
GHashTable *session_table;
|
GHashTable *session_table;
|
||||||
|
|
||||||
session_table =
|
session_table =
|
||||||
gvdb_hash_table_new (table, meta_session_state_get_name (session_state));
|
gvdb_hash_table_new (session_data->new_table,
|
||||||
|
meta_session_state_get_name (session_state));
|
||||||
meta_session_state_serialize (session_state, session_table);
|
meta_session_state_serialize (session_state, session_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (manager->gvdb_table)
|
return session_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_session_manager_save (MetaSessionManager *manager,
|
||||||
|
GAsyncReadyCallback cb,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
MetaSessionData *session_data;
|
||||||
|
g_autoptr (GTask) task = NULL;
|
||||||
|
|
||||||
|
task = g_task_new (manager, NULL, cb, user_data);
|
||||||
|
session_data = meta_session_manager_snapshot (manager);
|
||||||
|
if (session_data)
|
||||||
{
|
{
|
||||||
g_auto (GStrv) names;
|
g_task_set_task_data (task, session_data,
|
||||||
gsize len, i;
|
(GDestroyNotify) meta_session_data_free);
|
||||||
|
g_task_run_in_thread (task, save_session_async);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
g_task_return_boolean (task, TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
names = gvdb_table_get_names (manager->gvdb_table, &len);
|
gboolean
|
||||||
|
meta_session_manager_save_finish (MetaSessionManager *manager,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
return g_task_propagate_boolean (G_TASK (res), error);
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < len; i++)
|
gboolean
|
||||||
{
|
meta_session_manager_save_sync (MetaSessionManager *manager,
|
||||||
if (g_hash_table_contains (manager->sessions, names[i]))
|
GError **error)
|
||||||
continue;
|
{
|
||||||
if (g_hash_table_contains (manager->deleted_sessions, names[i]))
|
MetaSessionData *session_data;
|
||||||
continue;
|
gboolean retval = TRUE;
|
||||||
|
|
||||||
snapshot_gvdb_recursively (manager->gvdb_table, table, names[i]);
|
g_mutex_lock (&manager->mutex);
|
||||||
}
|
|
||||||
|
session_data = meta_session_manager_snapshot (manager);
|
||||||
|
if (session_data)
|
||||||
|
{
|
||||||
|
retval = meta_session_data_save (session_data, error);
|
||||||
|
meta_session_data_free (session_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return gvdb_table_write_contents (table,
|
g_mutex_unlock (&manager->mutex);
|
||||||
session_file,
|
|
||||||
FALSE, error);
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,14 @@ MetaSessionState * meta_session_manager_get_session (MetaSessionManager *manage
|
||||||
GType type,
|
GType type,
|
||||||
const char *name);
|
const char *name);
|
||||||
|
|
||||||
|
void meta_session_manager_save (MetaSessionManager *manager,
|
||||||
|
GAsyncReadyCallback cb,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
gboolean meta_session_manager_save_finish (MetaSessionManager *manager,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
gboolean meta_session_manager_save_sync (MetaSessionManager *manager,
|
gboolean meta_session_manager_save_sync (MetaSessionManager *manager,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue