diff -Nru gvfs-1.28.2/debian/changelog gvfs-1.28.2/debian/changelog --- gvfs-1.28.2/debian/changelog 2016-05-13 10:26:29.000000000 -0500 +++ gvfs-1.28.2/debian/changelog 2017-08-03 23:40:48.000000000 -0500 @@ -1,3 +1,11 @@ +gvfs (1.28.2-1ubuntu1~16.04.2) xenial; urgency=high + + * Greatly improve file manager performance and fix Nautilus crash by + backporting four patches (debian/patches/lp1133477-*) from upstream + (LP: #1133477). + + -- Simon Quigley Thu, 03 Aug 2017 23:40:48 -0500 + gvfs (1.28.2-1ubuntu1~16.04.1) xenial; urgency=low * Merge from Debian unstable to 16.04 as a stable update (LP: #1581577). diff -Nru gvfs-1.28.2/debian/patches/lp1133477-client-use-sync-methods-instead-of-flushing-dbus.patch gvfs-1.28.2/debian/patches/lp1133477-client-use-sync-methods-instead-of-flushing-dbus.patch --- gvfs-1.28.2/debian/patches/lp1133477-client-use-sync-methods-instead-of-flushing-dbus.patch 1969-12-31 18:00:00.000000000 -0600 +++ gvfs-1.28.2/debian/patches/lp1133477-client-use-sync-methods-instead-of-flushing-dbus.patch 2017-08-03 23:40:48.000000000 -0500 @@ -0,0 +1,63 @@ +Description: client: Use sync methods instead of flushing dbus + g_dbus_connection_flush_sync causes troubles in certain cases when using + multiple threads. The problem occurs when there are ongoing + gvfs_metadata_call_set_sync calls. It blocks threads e.g. when moving files + over Nautilus. Nautilus freezes sometimes due to it. Use sync methods instead + of flushing dbus. I don't see any significant slowdown when using sync + methods instead of the flushing according to my testing. It fixes hangs in + Nautilus and moving in Nautilus is almost instant again. +Author: Ondrej Holy +Origin: backport +Bug: https://bugzilla.gnome.org/show_bug.cgi?id=757747 +Bug-Ubuntu: https://pad.lv/1133477 +Applied-Upstream: 57acc8081cb67c3176d164abef02f878e40ab688 +Reviewed-by: Ondrej Holy +Last-Update: 2017-08-04 +--- a/client/gdaemonvfs.c ++++ b/client/gdaemonvfs.c +@@ -1361,16 +1361,11 @@ g_daemon_vfs_local_file_removed (GVfs + if (proxy) + { + metatreefile = meta_tree_get_filename (tree); +- /* we don't care about the result, let's queue the call and don't block */ +- gvfs_metadata_call_remove (proxy, +- metatreefile, +- tree_path, +- NULL, +- NULL, /* callback */ +- NULL); +- /* flush the call with the expense of sending all queued messages on the connection */ +- g_dbus_connection_flush_sync (g_dbus_proxy_get_connection (G_DBUS_PROXY (proxy)), +- NULL, NULL); ++ gvfs_metadata_call_remove_sync (proxy, ++ metatreefile, ++ tree_path, ++ NULL, ++ NULL); + } + + meta_tree_unref (tree); +@@ -1408,17 +1403,12 @@ g_daemon_vfs_local_file_moved (GVfs + if (proxy) + { + metatreefile = meta_tree_get_filename (tree1); +- /* we don't care about the result, let's queue the call and don't block */ +- gvfs_metadata_call_move (proxy, +- metatreefile, +- tree_path1, +- tree_path2, +- NULL, +- NULL, /* callback */ +- NULL); +- /* flush the call with the expense of sending all queued messages on the connection */ +- g_dbus_connection_flush_sync (g_dbus_proxy_get_connection (G_DBUS_PROXY (proxy)), +- NULL, NULL); ++ gvfs_metadata_call_move_sync (proxy, ++ metatreefile, ++ tree_path1, ++ tree_path2, ++ NULL, ++ NULL); + } + } + diff -Nru gvfs-1.28.2/debian/patches/lp1133477-metadata-fix-bogus-condition.patch gvfs-1.28.2/debian/patches/lp1133477-metadata-fix-bogus-condition.patch --- gvfs-1.28.2/debian/patches/lp1133477-metadata-fix-bogus-condition.patch 1969-12-31 18:00:00.000000000 -0600 +++ gvfs-1.28.2/debian/patches/lp1133477-metadata-fix-bogus-condition.patch 2017-08-03 23:40:48.000000000 -0500 @@ -0,0 +1,21 @@ +Description: metadata: Fix bogus condition + The file->children condition is always true at this point, child->children + should be there instead in order to speed up processing. This fix doesn't + affect the functionality, it just slightly improves processing. +Author: Ondrej Holy +Origin: backport +Bug: https://bugzilla.gnome.org/show_bug.cgi?id=757747 +Bug-Ubuntu: https://pad.lv/1133477 +Applied-Upstream: 1224147b051af726c8b33f34d37ef78015ed5b95 +Last-Update: 2017-08-04 +--- a/metadata/metabuilder.c ++++ b/metadata/metabuilder.c +@@ -784,7 +784,7 @@ write_children (GString *out, + append_uint32 (out, 0, &child->metadata_pointer); + append_time_t (out, child->last_changed, builder); + +- if (file->children) ++ if (child->children) + g_queue_push_tail (files, child); + } + diff -Nru gvfs-1.28.2/debian/patches/lp1133477-metadata-use-queues-instead-of-lists.patch gvfs-1.28.2/debian/patches/lp1133477-metadata-use-queues-instead-of-lists.patch --- gvfs-1.28.2/debian/patches/lp1133477-metadata-use-queues-instead-of-lists.patch 1969-12-31 18:00:00.000000000 -0600 +++ gvfs-1.28.2/debian/patches/lp1133477-metadata-use-queues-instead-of-lists.patch 2017-08-03 23:40:48.000000000 -0500 @@ -0,0 +1,154 @@ +Description: metadata: Use queues instead of lists + Some of the lists used by the metabuilder have items appended to them. + Appending to a list is done in linear time and this highly affects + efficiency. In order to fix this, use GQueue which supports appending in + constant time. +Author: Razvan Chitu +Origin: backport +Bug: https://bugzilla.gnome.org/show_bug.cgi?id=757747 +Bug-Ubuntu: https://pad.lv/1133477 +Applied-Upstream: fe3351227e89f484cc636107566d7b9ceca6ebfe +Reviewed-by: Ondrej Holy +Last-Update: 2017-08-04 +--- a/metadata/metabuilder.c ++++ b/metadata/metabuilder.c +@@ -627,22 +627,22 @@ append_string (GString *out, + GHashTable *string_block) + { + guint32 offset; +- GList *offsets; ++ GQueue *offsets; + + append_uint32 (out, 0xdeaddead, &offset); + +- if (g_hash_table_lookup_extended (string_block, +- string, NULL, +- (gpointer *)&offsets)) +- { +- offsets = g_list_append (offsets, GUINT_TO_POINTER (offset)); +- } +- else ++ if (!g_hash_table_lookup_extended (string_block, ++ string, NULL, ++ (gpointer *)&offsets)) + { ++ offsets = g_queue_new (); ++ + g_hash_table_insert (string_block, +- (char *)string, +- g_list_prepend (NULL, GUINT_TO_POINTER (offset))); ++ (char *)string, ++ offsets); + } ++ ++ g_queue_push_tail (offsets, GUINT_TO_POINTER (offset)); + } + + static void +@@ -650,7 +650,8 @@ string_block_end (GString *out, + GHashTable *string_block) + { + char *string; +- GList *offsets, *l; ++ GQueue *offsets; ++ GList *l; + guint32 string_offset, offset; + GHashTableIter iter; + +@@ -661,12 +662,12 @@ string_block_end (GString *out, + { + string_offset = out->len; + g_string_append_len (out, string, strlen (string) + 1); +- for (l = offsets; l != NULL; l = l->next) ++ for (l = g_queue_peek_head_link (offsets); l != NULL; l = l->next) + { + offset = GPOINTER_TO_UINT (l->data); + set_uint32 (out, offset, string_offset); + } +- g_list_free (offsets); ++ g_queue_free (offsets); + } + + g_hash_table_destroy (string_block); +@@ -745,14 +746,15 @@ write_children (GString *out, + GHashTable *strings; + MetaFile *child, *file; + GSequenceIter *iter; +- GList *files; ++ GQueue *files; ++ ++ files = g_queue_new (); + +- files = g_list_prepend (NULL, builder->root); ++ g_queue_push_tail (files, builder->root); + +- while (files != NULL) ++ while (!g_queue_is_empty (files)) + { +- file = files->data; +- files = g_list_delete_link (files, files); ++ file = g_queue_pop_head (files); + + if (file->children == NULL) + continue; /* No children, skip file */ +@@ -782,12 +784,14 @@ write_children (GString *out, + append_uint32 (out, 0, &child->metadata_pointer); + append_time_t (out, child->last_changed, builder); + +- if (file->children) +- files = g_list_append (files, child); +- } ++ if (file->children) ++ g_queue_push_tail (files, child); ++ } + + string_block_end (out, strings); + } ++ ++ g_queue_free (files); + } + + static void +@@ -832,7 +836,7 @@ write_metadata (GString *out, + GList *stringvs; + MetaFile *child, *file; + GSequenceIter *iter; +- GList *files; ++ GQueue *files; + + /* Root metadata */ + if (builder->root->data != NULL) +@@ -847,11 +851,13 @@ write_metadata (GString *out, + + /* the rest, breadth first with all files in one + dir sharing string block */ +- files = g_list_prepend (NULL, builder->root); +- while (files != NULL) ++ files = g_queue_new (); ++ ++ g_queue_push_tail (files, builder->root); ++ ++ while (!g_queue_is_empty (files)) + { +- file = files->data; +- files = g_list_delete_link (files, files); ++ file = g_queue_pop_head (files); + + if (file->children == NULL) + continue; /* No children, skip file */ +@@ -870,12 +876,14 @@ write_metadata (GString *out, + &stringvs, strings, key_hash); + + if (child->children != NULL) +- files = g_list_append (files, child); ++ g_queue_push_tail (files, child); + } + + stringv_block_end (out, strings, stringvs); + string_block_end (out, strings); + } ++ ++ g_queue_free (files); + } + + static gboolean diff -Nru gvfs-1.28.2/debian/patches/lp1133477-metadata-use-sequences-instead-of-lists.patch gvfs-1.28.2/debian/patches/lp1133477-metadata-use-sequences-instead-of-lists.patch --- gvfs-1.28.2/debian/patches/lp1133477-metadata-use-sequences-instead-of-lists.patch 1969-12-31 18:00:00.000000000 -0600 +++ gvfs-1.28.2/debian/patches/lp1133477-metadata-use-sequences-instead-of-lists.patch 2017-08-03 23:40:48.000000000 -0500 @@ -0,0 +1,439 @@ +Description: metadata: Use sequences instead of lists + The metabuilder stores files and data in sorted lists. An insertion into a + sorted list is done in linear time, which highly affects efficiency. In order + to fix this, use GSequence instead which does insertion and deletion in + logarithmic time. +Author: Razvan Chitu +Origin: backport +Bug: https://bugzilla.gnome.org/show_bug.cgi?id=757747 +Bug-Ubuntu: https://pad.lv/1133477 +Applied-Upstream: 0e001c9ced0dc6c6891f588e9c683308b46c9001 +Reviewed-by: Ondrej Holy +Last-Update: 2017-08-04 +--- a/metadata/metabuilder.c ++++ b/metadata/metabuilder.c +@@ -78,8 +78,9 @@ meta_builder_free (MetaBuilder *builder) + } + + static gint +-compare_metafile (gconstpointer a, +- gconstpointer b) ++compare_metafile (gconstpointer a, ++ gconstpointer b, ++ gpointer user_data) + { + const MetaFile *aa, *bb; + +@@ -89,8 +90,9 @@ compare_metafile (gconstpointer a, + } + + static gint +-compare_metadata (gconstpointer a, +- gconstpointer b) ++compare_metadata (gconstpointer a, ++ gconstpointer b, ++ gpointer user_data) + { + const MetaData *aa, *bb; + +@@ -99,6 +101,18 @@ compare_metadata (gconstpointer a, + return strcmp (aa->key, bb->key); + } + ++static void ++metadata_free (MetaData *data) ++{ ++ g_free (data->key); ++ if (data->is_list) ++ g_list_free_full (data->values, g_free); ++ else ++ g_free (data->value); ++ ++ g_free (data); ++} ++ + MetaFile * + metafile_new (const char *name, + MetaFile *parent) +@@ -107,9 +121,10 @@ metafile_new (const char *name, + + f = g_new0 (MetaFile, 1); + f->name = g_strdup (name); ++ f->children = g_sequence_new ((GDestroyNotify)metafile_free); ++ f->data = g_sequence_new ((GDestroyNotify)metadata_free); + if (parent) +- parent->children = g_list_insert_sorted (parent->children, f, +- compare_metafile); ++ g_sequence_insert_sorted (parent->children, f, compare_metafile, NULL); + + return f; + } +@@ -124,7 +139,7 @@ metadata_new (const char *key, + data->key = g_strdup (key); + + if (file) +- file->data = g_list_insert_sorted (file->data, data, compare_metadata); ++ g_sequence_insert_sorted (file->data, data, compare_metadata, NULL); + + return data; + } +@@ -152,24 +167,12 @@ metadata_dup (MetaFile *file, + return new_data; + } + +-static void +-metadata_free (MetaData *data) +-{ +- g_free (data->key); +- if (data->is_list) +- g_list_free_full (data->values, g_free); +- else +- g_free (data->value); +- +- g_free (data); +-} +- + void + metafile_free (MetaFile *file) + { + g_free (file->name); +- g_list_free_full (file->children, (GDestroyNotify)metafile_free); +- g_list_free_full (file->data, (GDestroyNotify)metadata_free); ++ g_sequence_free (file->children); ++ g_sequence_free (file->data); + g_free (file); + } + +@@ -178,15 +181,20 @@ metafile_lookup_child (MetaFile *metafil + const char *name, + gboolean create) + { +- GList *l; + MetaFile *child; ++ MetaFile lookup_file; ++ GSequenceIter *lookup_file_iter; ++ ++ lookup_file.name = (char *)name; ++ ++ lookup_file_iter = g_sequence_lookup (metafile->children, ++ &lookup_file, ++ compare_metafile, ++ NULL); ++ ++ if (lookup_file_iter) ++ return g_sequence_get (lookup_file_iter); + +- for (l = metafile->children; l != NULL; l = l->next) +- { +- child = l->data; +- if (strcmp (child->name, name) == 0) +- return child; +- } + child = NULL; + if (create) + child = metafile_new (name, metafile); +@@ -252,16 +260,22 @@ meta_builder_remove (MetaBuilder *builde + + if (parent != NULL) + { +- parent->children = g_list_remove (parent->children, f); +- metafile_free (f); ++ GSequenceIter *iter; ++ ++ iter = g_sequence_lookup (parent->children, ++ f, ++ compare_metafile, ++ NULL); ++ g_sequence_remove (iter); ++ + if (mtime) + parent->last_changed = mtime; + } + else + { + /* Removing root not allowed, just remove children */ +- g_list_free_full (f->children, (GDestroyNotify)metafile_free); +- f->children = NULL; ++ g_sequence_remove_range (g_sequence_get_begin_iter (f->children), ++ g_sequence_get_end_iter (f->children)); + if (mtime) + f->last_changed = mtime; + } +@@ -274,19 +288,23 @@ meta_file_copy_into (MetaFile *src, + guint64 mtime) + { + MetaFile *src_child, *dest_child; +- GList *l; ++ GSequenceIter *iter; + + if (mtime) + dest->last_changed = mtime; + else + dest->last_changed = src->last_changed; + +- for (l = src->data; l != NULL; l = l->next) +- metadata_dup (dest, l->data); +- +- for (l = src->children; l != NULL; l = l->next) ++ for (iter = g_sequence_get_begin_iter (src->data); ++ iter != g_sequence_get_end_iter (src->data); ++ iter = g_sequence_iter_next (iter)) ++ metadata_dup (dest, g_sequence_get (iter)); ++ ++ for (iter = g_sequence_get_begin_iter (src->children); ++ iter != g_sequence_get_end_iter (src->children); ++ iter = g_sequence_iter_next (iter)) + { +- src_child = l->data; ++ src_child = g_sequence_get (iter); + dest_child = metafile_new (src_child->name, dest); + meta_file_copy_into (src_child, dest_child, mtime); + } +@@ -310,6 +328,8 @@ meta_builder_copy (MetaBuilder *builder, + meta_file_copy_into (src, temp, mtime); + + dest = meta_builder_lookup (builder, dest_path, TRUE); ++ g_sequence_free (dest->data); ++ g_sequence_free (dest->children); + dest->data = temp->data; + dest->children = temp->children; + dest->last_changed = temp->last_changed; +@@ -324,20 +344,31 @@ metafile_set_mtime (MetaFile *file, + file->last_changed = mtime; + } + ++GSequenceIter * ++metafile_key_lookup_iter (MetaFile *file, ++ const char *key) ++{ ++ MetaData lookup_data; ++ ++ lookup_data.key = (char *)key; ++ ++ return g_sequence_lookup (file->data, ++ &lookup_data, ++ compare_metadata, ++ NULL); ++} ++ + MetaData * + metafile_key_lookup (MetaFile *file, + const char *key, + gboolean create) + { +- GList *l; + MetaData *data; ++ GSequenceIter *iter; + +- for (l = file->data; l != NULL; l = l->next) +- { +- data = l->data; +- if (strcmp (data->key, key) == 0) +- return data; +- } ++ iter = metafile_key_lookup_iter (file, key); ++ if (iter) ++ return g_sequence_get (iter); + + data = NULL; + if (create) +@@ -364,14 +395,11 @@ void + metafile_key_unset (MetaFile *metafile, + const char *key) + { +- MetaData *data; ++ GSequenceIter *iter; + +- data = metafile_key_lookup (metafile, key, FALSE); +- if (data) +- { +- metafile->data = g_list_remove (metafile->data, data); +- metadata_free (data); +- } ++ iter = metafile_key_lookup_iter (metafile, key); ++ if (iter) ++ g_sequence_remove (iter); + } + + void +@@ -423,7 +451,8 @@ metafile_key_list_add (MetaFile *metafil + static void + metafile_print (MetaFile *file, int indent, char *parent) + { +- GList *l, *v; ++ GSequenceIter *iter; ++ GList *v; + MetaData *data; + char *dir; + +@@ -438,9 +467,11 @@ metafile_print (MetaFile *file, int inde + indent += 3; + } + +- for (l = file->data; l != NULL; l = l->next) ++ for (iter = g_sequence_get_begin_iter (file->data); ++ iter != g_sequence_get_end_iter (file->data); ++ iter = g_sequence_iter_next (iter)) + { +- data = l->data; ++ data = g_sequence_get (iter); + g_print ("%*s%s=", indent, "", data->key); + if (data->is_list) + { +@@ -455,9 +486,11 @@ metafile_print (MetaFile *file, int inde + g_print ("%s", data->value); + g_print ("\n"); + } +- for (l = file->children; l != NULL; l = l->next) ++ for (iter = g_sequence_get_begin_iter (file->children); ++ iter != g_sequence_get_end_iter (file->children); ++ iter = g_sequence_iter_next (iter)) + { +- metafile_print (l->data, indent, dir); ++ metafile_print (g_sequence_get (iter), indent, dir); + } + + g_free (dir); +@@ -534,7 +567,7 @@ metafile_collect_times (MetaFile *file, + gint64 *time_t_min, + gint64 *time_t_max) + { +- GList *l; ++ GSequenceIter *iter; + MetaFile *child; + + if (*time_t_min == 0) +@@ -545,9 +578,11 @@ metafile_collect_times (MetaFile *file, + if (file->last_changed > *time_t_max) + *time_t_max = file->last_changed; + +- for (l = file->children; l != NULL; l = l->next) ++ for (iter = g_sequence_get_begin_iter (file->children); ++ iter != g_sequence_get_end_iter (file->children); ++ iter = g_sequence_iter_next (iter)) + { +- child = l->data; ++ child = g_sequence_get (iter); + metafile_collect_times (child, time_t_min, time_t_max); + } + } +@@ -556,22 +591,26 @@ static void + metafile_collect_keywords (MetaFile *file, + GHashTable *hash) + { +- GList *l; ++ GSequenceIter *iter; + MetaData *data; + MetaFile *child; + + file->metadata_pointer = 0; + file->children_pointer = 0; + +- for (l = file->data; l != NULL; l = l->next) ++ for (iter = g_sequence_get_begin_iter (file->data); ++ iter != g_sequence_get_end_iter (file->data); ++ iter = g_sequence_iter_next (iter)) + { +- data = l->data; ++ data = g_sequence_get (iter); + g_hash_table_insert (hash, data->key, GINT_TO_POINTER (1)); + } + +- for (l = file->children; l != NULL; l = l->next) ++ for (iter = g_sequence_get_begin_iter (file->children); ++ iter != g_sequence_get_end_iter (file->children); ++ iter = g_sequence_iter_next (iter)) + { +- child = l->data; ++ child = g_sequence_get (iter); + metafile_collect_keywords (child, hash); + } + } +@@ -705,7 +744,7 @@ write_children (GString *out, + { + GHashTable *strings; + MetaFile *child, *file; +- GList *l; ++ GSequenceIter *iter; + GList *files; + + files = g_list_prepend (NULL, builder->root); +@@ -723,11 +762,13 @@ write_children (GString *out, + if (file->children_pointer != 0) + set_uint32 (out, file->children_pointer, out->len); + +- append_uint32 (out, g_list_length (file->children), NULL); ++ append_uint32 (out, g_sequence_get_length (file->children), NULL); + +- for (l = file->children; l != NULL; l = l->next) ++ for (iter = g_sequence_get_begin_iter (file->children); ++ iter != g_sequence_get_end_iter (file->children); ++ iter = g_sequence_iter_next (iter)) + { +- child = l->data; ++ child = g_sequence_get (iter); + + /* No mtime, children or metadata, no need for this + to be in the file */ +@@ -756,18 +797,20 @@ write_metadata_for_file (GString *out, + GHashTable *strings, + GHashTable *key_hash) + { +- GList *l; ++ GSequenceIter *iter; + MetaData *data; + guint32 key; + + g_assert (file->metadata_pointer != 0); + set_uint32 (out, file->metadata_pointer, out->len); + +- append_uint32 (out, g_list_length (file->data), NULL); ++ append_uint32 (out, g_sequence_get_length (file->data), NULL); + +- for (l = file->data; l != NULL; l = l->next) ++ for (iter = g_sequence_get_begin_iter (file->data); ++ iter != g_sequence_get_end_iter (file->data); ++ iter = g_sequence_iter_next (iter)) + { +- data = l->data; ++ data = g_sequence_get (iter); + + key = GPOINTER_TO_UINT (g_hash_table_lookup (key_hash, data->key)); + if (data->is_list) +@@ -788,7 +831,7 @@ write_metadata (GString *out, + GHashTable *strings; + GList *stringvs; + MetaFile *child, *file; +- GList *l; ++ GSequenceIter *iter; + GList *files; + + /* Root metadata */ +@@ -816,9 +859,11 @@ write_metadata (GString *out, + strings = string_block_begin (); + stringvs = stringv_block_begin (); + +- for (l = file->children; l != NULL; l = l->next) ++ for (iter = g_sequence_get_begin_iter (file->children); ++ iter != g_sequence_get_end_iter (file->children); ++ iter = g_sequence_iter_next (iter)) + { +- child = l->data; ++ child = g_sequence_get (iter); + + if (child->data != NULL) + write_metadata_for_file (out, child, +--- a/metadata/metabuilder.h ++++ b/metadata/metabuilder.h +@@ -38,9 +38,9 @@ struct _MetaBuilder { + + struct _MetaFile { + char *name; +- GList *children; ++ GSequence *children; + gint64 last_changed; +- GList *data; ++ GSequence *data; + + guint32 metadata_pointer; + guint32 children_pointer; diff -Nru gvfs-1.28.2/debian/patches/series gvfs-1.28.2/debian/patches/series --- gvfs-1.28.2/debian/patches/series 2016-05-10 18:43:35.000000000 -0500 +++ gvfs-1.28.2/debian/patches/series 2017-08-03 23:40:48.000000000 -0500 @@ -4,3 +4,7 @@ dont-crash-on-null-job.patch handle-inactive-vfs.patch ref-jobs-in-thread.patch +lp1133477-metadata-use-sequences-instead-of-lists.patch +lp1133477-metadata-use-queues-instead-of-lists.patch +lp1133477-metadata-fix-bogus-condition.patch +lp1133477-client-use-sync-methods-instead-of-flushing-dbus.patch