gvfs/trash-Use-GHashTable-for-trash-directory-items.patch
Ondrej Holy b57f602cb4 Improve trash backend performance
Resolves: RHEL-127445
2026-06-03 12:30:27 +02:00

222 lines
6.6 KiB
Diff

From 97d9831042ca1c5c13fdb6cd9bfb2e2fe77f94f8 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Wed, 3 Jun 2026 08:45:00 +0200
Subject: [PATCH] trash: Use GHashTable for trash directory items
Backport of commit 665ff6b8.
Adjusted context for target version.
---
daemon/trashlib/trashdir.c | 122 +++++++++++++++----------------------
1 file changed, 48 insertions(+), 74 deletions(-)
diff --git a/daemon/trashlib/trashdir.c b/daemon/trashlib/trashdir.c
index 23aa0d7..610f2c3 100644
--- a/daemon/trashlib/trashdir.c
+++ b/daemon/trashlib/trashdir.c
@@ -16,7 +16,7 @@
struct OPAQUE_TYPE__TrashDir
{
TrashRoot *root;
- GSList *items;
+ GHashTable *items; /* basename -> GFile */
GFile *directory;
GFile *topdir;
@@ -27,28 +27,6 @@ struct OPAQUE_TYPE__TrashDir
GFileMonitor *monitor;
};
-static gint
-compare_basename (gconstpointer a,
- gconstpointer b)
-{
- GFile *file_a, *file_b;
- char *name_a, *name_b;
- gint result;
-
- file_a = (GFile *) a;
- file_b = (GFile *) b;
-
- name_a = g_file_get_basename (file_a);
- name_b = g_file_get_basename (file_b);
-
- result = strcmp (name_a, name_b);
-
- g_free (name_a);
- g_free (name_b);
-
- return result;
-}
-
static void
trash_dir_query_mtime (TrashDir *dir, GTimeVal *mtime)
{
@@ -70,47 +48,36 @@ trash_dir_query_mtime (TrashDir *dir, GTimeVal *mtime)
}
static void
-trash_dir_set_files (TrashDir *dir,
- GSList *items)
+trash_dir_set_files (TrashDir *dir,
+ GHashTable *items)
{
- GSList **old, *new;
-
- items = g_slist_sort (items, (GCompareFunc) compare_basename);
- old = &dir->items;
- new = items;
+ GHashTableIter iter;
+ gpointer key, value;
- while (new || *old)
+ g_hash_table_iter_init (&iter, dir->items);
+ while (g_hash_table_iter_next (&iter, &key, &value))
{
- int result;
-
- if ((result = (new == NULL) - (*old == NULL)) == 0)
- result = compare_basename (new->data, (*old)->data);
-
- if (result < 0)
- {
- /* new entry. add it. */
- *old = g_slist_prepend (*old, new->data); /* take reference */
- old = &(*old)->next;
- trash_root_add_item (dir->root, new->data, dir->topdir, dir->is_homedir);
- new = new->next;
- }
- else if (result > 0)
+ if (!g_hash_table_contains (items, key))
{
/* old entry. remove it. */
- trash_root_remove_item (dir->root, (*old)->data, dir->is_homedir);
- g_object_unref ((*old)->data);
- *old = g_slist_delete_link (*old, *old);
+ trash_root_remove_item (dir->root, value, dir->is_homedir);
+ g_hash_table_iter_remove (&iter);
}
- else
+ }
+
+ g_hash_table_iter_init (&iter, items);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ if (!g_hash_table_contains (dir->items, key))
{
- /* match. no change. */
- old = &(*old)->next;
- g_object_unref (new->data);
- new = new->next;
+ /* new entry. add it. */
+ g_hash_table_iter_steal (&iter);
+ g_hash_table_insert (dir->items, key, value);
+ trash_root_add_item (dir->root, value, dir->topdir, dir->is_homedir);
}
}
- g_slist_free (items);
+ g_hash_table_unref (items);
trash_root_thaw (dir->root);
}
@@ -118,16 +85,23 @@ trash_dir_set_files (TrashDir *dir,
static void
trash_dir_empty (TrashDir *dir)
{
- trash_dir_set_files (dir, NULL);
+ GHashTable *empty;
+
+ empty = g_hash_table_new (g_str_hash, g_str_equal);
+ trash_dir_set_files (dir, empty);
}
static void
trash_dir_enumerate (TrashDir *dir)
{
GFileEnumerator *enumerator;
- GSList *files = NULL;
+ GHashTable *files = NULL;
trash_dir_query_mtime (dir, &dir->mtime);
+
+ files = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, g_object_unref);
+
enumerator = g_file_enumerate_children (dir->directory,
G_FILE_ATTRIBUTE_STANDARD_NAME,
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
@@ -140,10 +113,11 @@ trash_dir_enumerate (TrashDir *dir)
while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)))
{
GFile *file;
+ const gchar *name;
- file = g_file_get_child (dir->directory,
- g_file_info_get_name (info));
- files = g_slist_prepend (files, file);
+ name = g_file_info_get_name (info);
+ file = g_file_get_child (dir->directory, name);
+ g_hash_table_insert (files, g_strdup (name), file);
g_object_unref (info);
}
@@ -165,24 +139,20 @@ trash_dir_changed (GFileMonitor *monitor,
if (event_type == G_FILE_MONITOR_EVENT_CREATED)
{
- dir->items = g_slist_insert_sorted (dir->items,
- g_object_ref (file),
- (GCompareFunc) compare_basename);
- trash_root_add_item (dir->root, file, dir->topdir, dir->is_homedir);
+ g_autofree gchar *name = g_file_get_basename (file);
+
+ if (!g_hash_table_contains (dir->items, name))
+ {
+ g_hash_table_insert (dir->items, g_steal_pointer (&name), g_object_ref (file));
+ trash_root_add_item (dir->root, file, dir->topdir, dir->is_homedir);
+ }
}
else if (event_type == G_FILE_MONITOR_EVENT_DELETED)
{
- GSList *node;
+ g_autofree char *name = g_file_get_basename (file);
- node = g_slist_find_custom (dir->items,
- file,
- (GCompareFunc) compare_basename);
- if (node)
- {
- g_object_unref (node->data);
- dir->items = g_slist_delete_link (dir->items, node);
- }
+ g_hash_table_remove (dir->items, name);
trash_root_remove_item (dir->root, file, dir->is_homedir);
}
@@ -386,7 +356,8 @@ trash_dir_new (TrashRoot *root,
dir = g_slice_new (TrashDir);
dir->root = root;
- dir->items = NULL;
+ dir->items = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, g_object_unref);
dir->topdir = g_file_new_for_path (mount_point);
dir->directory = g_file_get_child (dir->topdir, rel);
dir->monitor = NULL;
@@ -416,7 +387,9 @@ trash_dir_free (TrashDir *dir)
if (dir->monitor)
g_object_unref (dir->monitor);
- trash_dir_set_files (dir, NULL);
+ trash_dir_empty (dir);
+
+ g_hash_table_unref (dir->items);
g_object_unref (dir->directory);
g_object_unref (dir->topdir);
--
2.53.0