[PATCH] Improve async metadata behavior



I initially hoped to resolve bug 152993 [1] with this patch, but the
issue was actually another subtile metadata issue.
This patch is not very well tested, it's meant to resolve one of the
metadata FIXMES:

+/* if a move/copy operation is in progress and metadata on the target
is set during the
+ * async operation, we have to keep the metadata sets around until the
copy/move operation
+ * is finished */

It may not be a good idea to include it in the 2.14 release unless it is
well tested.

[1] http://bugzilla.gnome.org/show_bug.cgi?id=152993

-- 
Christian Neumair <chris gnome-de org>
Index: libnautilus-private/nautilus-metafile.c
===================================================================
RCS file: /cvs/gnome/nautilus/libnautilus-private/nautilus-metafile.c,v
retrieving revision 1.44
diff -u -p -r1.44 nautilus-metafile.c
--- libnautilus-private/nautilus-metafile.c	12 Dec 2005 16:59:10 -0000	1.44
+++ libnautilus-private/nautilus-metafile.c	29 Jan 2006 21:29:40 -0000
@@ -52,14 +52,13 @@
 
 /* TODO asynchronous copying/moving of metadata
  *
- * - potential metadata loss when a deletion is scheduled, and new metadata is copied to
- *   this location before the old deletion is consumed
- *
  * - if metafile read fails, and a file from that metafile is scheduled for a copy/move operation,
  *   its associated operations are not removed from pending_copies
  *
  * */
 
+typedef struct _MetadataValue MetadataValue;
+
 static char    *get_file_metadata                  (NautilusMetafile *metafile,
 						    const char       *file_name,
 						    const char       *key,
@@ -105,6 +104,14 @@ static void     async_read_cancel       
 static void     set_metafile_contents              (NautilusMetafile *metafile,
 						    xmlDocPtr         metafile_contents);
 
+static MetadataValue *metadata_value_dup     (const MetadataValue *value);
+static void           metadata_value_destroy (MetadataValue       *value);
+
+static gboolean nautilus_metadata_has_scheduled_copy_as_source      (NautilusMetafile *metafile,
+								     const char       *file_name);
+static gboolean nautilus_metadata_has_scheduled_copy_as_destination (NautilusMetafile *metafile,
+								     const char       *file_name);
+
 BONOBO_CLASS_BOILERPLATE_FULL (NautilusMetafile, nautilus_metafile,
 			       Nautilus_Metafile,
 			       BonoboObject, BONOBO_OBJECT_TYPE)
@@ -140,6 +147,15 @@ struct NautilusMetafileDetails {
 	GnomeVFSURI *directory_vfs_uri;
 };
 
+struct _MetadataValue {
+	gboolean is_list;
+	union {
+		char *string;
+		GList *string_list;
+	} value;
+	char *default_value;
+};
+
 static GHashTable *metafiles;
 
 static void
@@ -281,6 +297,127 @@ nautilus_metafile_get (const char *direc
 	return metafile;
 }
 
+/* if a move/copy operation is in progress and metadata on the target is set during the
+ * async operation, we have to keep the metadata sets around until the copy/move operation
+ * is finished */
+static GList *pending_sets;
+
+typedef struct {
+	NautilusMetafile *metafile;
+	char             *file_name;
+	char             *key;
+	char	         *subkey;
+	MetadataValue    *value;
+} NautilusMetadataSet;
+
+static void
+nautilus_metadata_set_destroy (NautilusMetadataSet *set)
+{
+	bonobo_object_unref (set->metafile);
+	g_free (set->file_name);
+	g_free (set->key);
+	g_free (set->subkey);
+	metadata_value_destroy (set->value);
+	g_free (set);
+}
+
+static void
+nautilus_metadata_schedule_set (NautilusMetafile *metafile,
+				const char       *file_name,
+				const char       *key,
+				const char       *subkey,
+				MetadataValue    *value)
+{
+	GList *l;
+	NautilusMetadataSet *set;
+
+	g_assert (metafile != NULL);
+
+	set = NULL;
+
+	for (l = pending_sets; l != NULL; l = l->next) {
+		set = l->data;
+		if (set->metafile == metafile) {
+			break;
+		}
+	}
+
+	if (set == NULL) {
+		set = g_new (NautilusMetadataSet, 1);
+		set->metafile = bonobo_object_ref (metafile);
+		set->file_name = g_strdup (file_name);
+		set->key = g_strdup (key);
+		set->subkey = g_strdup (subkey);
+		set->value = metadata_value_dup (value);
+		pending_sets = g_list_prepend (pending_sets, set);
+	} else {
+		metadata_value_destroy (set->value);
+		set->value = metadata_value_dup (value);
+	}
+}
+
+static int
+changed_set_compare (gconstpointer a,
+		     gconstpointer b)
+{
+	const NautilusMetadataSet *a_set = a;
+	const NautilusMetadataSet *b_set = b;
+
+	if (a_set == b_set) {
+		return 0;
+	}
+
+	if (a_set->metafile == b_set->metafile) {
+		return 0;
+	}
+
+	return strcmp (a_set->file_name, b_set->file_name);
+}
+
+static void
+nautilus_metadata_process_ready_sets (void)
+{
+	NautilusMetadataSet *set;
+	GList *l, *next;
+	GList *changed_sets;
+	gboolean success;
+
+	changed_sets = NULL;
+
+	l = pending_sets;
+	while (l != NULL) {
+		set = l->data;
+
+		next = l->next;
+
+		if (!nautilus_metadata_has_scheduled_copy_as_destination (set->metafile, set->file_name)) {
+			if (set->value->is_list) {
+				success = set_file_metadata_list (set->metafile, set->file_name, set->key, set->subkey, set->value->value.string_list);
+			} else {
+				success = set_file_metadata (set->metafile, set->file_name, set->key, set->value->default_value, set->value->value.string);
+			}
+
+			if (!success) {
+				nautilus_metadata_set_destroy (set);
+			} else if (!g_list_find_custom (changed_sets, set, changed_set_compare)) {
+				changed_sets = g_list_prepend (changed_sets, set);
+			}
+
+			pending_sets = g_list_delete_link (pending_sets, l);
+		}
+
+		l = next;
+	}
+
+	for (l = changed_sets; l != NULL; l = l->next) {
+		set = l->data;
+		call_metafile_changed_for_one_file (set->metafile, set->file_name);
+		nautilus_metadata_set_destroy (set);
+	}
+
+	g_list_free (changed_sets);
+}
+
 static GList *pending_copies;
 
 typedef struct {
@@ -326,8 +463,27 @@ nautilus_metadata_get_scheduled_copy (Na
 }
 
 static gboolean
-nautilus_metadata_has_scheduled_copy (NautilusMetafile *source_metafile,
-				      const char       *source_file_name)
+nautilus_metadata_has_scheduled_copy_as_source (NautilusMetafile *metafile,
+						const char       *file_name)
+{
+	NautilusMetadataCopy *copy;
+	GList *l;
+
+	for (l = pending_copies; l != NULL; l = l->next) {
+		copy = l->data;
+
+		if ((copy->source_metafile == metafile)
+		    && (strcmp (copy->source_file_name, file_name) == 0)) {
+			return TRUE;
+		}
+	}
+
+	return FALSE;
+}
+
+static gboolean
+nautilus_metadata_has_scheduled_copy_as_destination (NautilusMetafile *metafile,
+						     const char       *file_name)
 {
 	NautilusMetadataCopy *copy;
 	GList *l;
@@ -335,8 +491,8 @@ nautilus_metadata_has_scheduled_copy (Na
 	for (l = pending_copies; l != NULL; l = l->next) {
 		copy = l->data;
 
-		if ((copy->source_metafile == source_metafile)
-		    && (strcmp (copy->source_file_name, source_file_name) == 0)) {
+		if ((copy->destination_metafile == metafile)
+		    && (strcmp (copy->destination_file_name, file_name) == 0)) {
 			return TRUE;
 		}
 	}
@@ -444,7 +600,7 @@ nautilus_metadata_schedule_removal (Naut
 {
 	NautilusMetadataRemoval *removal;
 
-	g_assert (nautilus_metadata_has_scheduled_copy (metafile, file_name));
+	g_assert (nautilus_metadata_has_scheduled_copy_as_source (metafile, file_name));
 
 	removal = nautilus_metadata_get_scheduled_removal (metafile, file_name);
 	if (removal == NULL) {
@@ -468,7 +624,7 @@ nautilus_metadata_process_ready_removals
 
 		next = l->next;
 
-		if (!nautilus_metadata_has_scheduled_copy (removal->metafile, removal->file_name)) {
+		if (!nautilus_metadata_has_scheduled_copy_as_source (removal->metafile, removal->file_name)) {
 			real_remove_file_metadata (removal->metafile, removal->file_name);
 
 			pending_removals = g_list_delete_link (pending_removals, l);
@@ -897,15 +1053,6 @@ call_metafile_changed_for_one_file (Naut
 	call_metafile_changed (metafile, &file_names);
 }
 
-typedef struct {
-	gboolean is_list;
-	union {
-		char *string;
-		GList *string_list;
-	} value;
-	char *default_value;
-} MetadataValue;
-
 static char *
 get_metadata_from_node (xmlNode *node,
 			const char *key,
@@ -1154,6 +1303,18 @@ metadata_value_new_list (GList *metadata
 	return value;
 }
 
+static MetadataValue *
+metadata_value_dup (const MetadataValue *value)
+{
+	if (value == NULL) {
+		return NULL;
+	} else if (value->is_list) {
+		return metadata_value_new_list (value->value.string_list);
+	} else {
+		return metadata_value_new (value->default_value, value->value.string);
+	}
+}
+
 static void
 metadata_value_destroy (MetadataValue *value)
 {
@@ -1454,7 +1615,14 @@ set_file_metadata (NautilusMetafile *met
 	g_return_val_if_fail (!eel_str_is_empty (file_name), FALSE);
 	g_return_val_if_fail (!eel_str_is_empty (key), FALSE);
 
-	if (metafile->details->is_read) {
+
+	if (nautilus_metadata_has_scheduled_copy_as_destination (metafile, file_name)) {
+		value = metadata_value_new (default_metadata, metadata);
+		nautilus_metadata_schedule_set (metafile, file_name,
+						key, NULL, value);
+		metadata_value_destroy (value);
+		return FALSE;
+	} else if (metafile->details->is_read) {
 		return set_metadata_string_in_metafile (metafile, file_name, key,
 							default_metadata, metadata);
 	} else {
@@ -1478,7 +1646,14 @@ set_file_metadata_list (NautilusMetafile
 	g_return_val_if_fail (!eel_str_is_empty (list_key), FALSE);
 	g_return_val_if_fail (!eel_str_is_empty (list_subkey), FALSE);
 
-	if (metafile->details->is_read) {
+
+	if (nautilus_metadata_has_scheduled_copy_as_destination (metafile, file_name)) {
+		value = metadata_value_new_list (list);
+		nautilus_metadata_schedule_set (metafile, file_name,
+						list_key, list_subkey, value);
+		metadata_value_destroy (value);
+		return FALSE;
+	} else if (metafile->details->is_read) {
 		return set_metadata_list_in_metafile (metafile, file_name,
 						      list_key, list_subkey, list);
 	} else {
@@ -1753,7 +1930,7 @@ remove_file_metadata (NautilusMetafile *
 	g_return_if_fail (NAUTILUS_IS_METAFILE (metafile));
 	g_return_if_fail (file_name != NULL);
 
-	if (nautilus_metadata_has_scheduled_copy (metafile, file_name)) {
+	if (nautilus_metadata_has_scheduled_copy_as_source (metafile, file_name)) {
 		nautilus_metadata_schedule_removal (metafile, file_name);
 	} else {
 		real_remove_file_metadata (metafile, file_name);
@@ -1836,6 +2013,7 @@ metafile_read_done (NautilusMetafile *me
 	metafile_read_mark_done (metafile);
 
 	nautilus_metadata_process_ready_copies ();
+	nautilus_metadata_process_ready_sets ();
 	nautilus_metadata_process_ready_removals ();
 }
 

Attachment: signature.asc
Description: Dies ist ein digital signierter Nachrichtenteil



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