tracker r3137 - in trunk: . src/tracker-indexer src/tracker-indexer/modules



Author: carlosg
Date: Wed Mar 25 16:43:51 2009
New Revision: 3137
URL: http://svn.gnome.org/viewvc/tracker?rev=3137&view=rev

Log:
2009-03-25  Carlos Garnacho  <carlos imendio com>

        Make GVolumeMonitor::mount-pre-unmount cancel any ongoing operation in
        the indexer on the removable media. This isn't available yet due to
        GLib not emitting such signal, but it will soon.

        * src/tracker-indexer/tracker-module-file.[ch]
        (tracker_module_file_cancel) (tracker_module_file_is_cancelled): Added
        new API.

        * src/tracker-indexer/tracker-module-metadata-utils.[ch]: Reworked to
        have child processes async+killable.
        (tracker_module_metadata_utils_cancel): New function to kill all
        external processes on a GFile.

        * src/tracker-indexer/modules/files.c: Use new metadata utils function
        to immediately cancel an operation.

        * src/tracker-indexer/tracker-indexer.c (check_mount_removal)
        (mount_pre_unmount_cb) (tracker_indexer_finalize)
        (tracker_indexer_init): Hook to GVolumeMonitor::mount-pre-unmount, so
        any ongoing+future operations on the removable media are cancelled.

        (item_add_or_update) (item_move) (item_process) (process_file):
        Reworked to have a single point of cancellation.

Modified:
   trunk/ChangeLog
   trunk/src/tracker-indexer/modules/files.c
   trunk/src/tracker-indexer/tracker-indexer.c
   trunk/src/tracker-indexer/tracker-module-file.c
   trunk/src/tracker-indexer/tracker-module-file.h
   trunk/src/tracker-indexer/tracker-module-metadata-utils.c
   trunk/src/tracker-indexer/tracker-module-metadata-utils.h

Modified: trunk/src/tracker-indexer/modules/files.c
==============================================================================
--- trunk/src/tracker-indexer/modules/files.c	(original)
+++ trunk/src/tracker-indexer/modules/files.c	Wed Mar 25 16:43:51 2009
@@ -60,6 +60,7 @@
 static const gchar *           tracker_regular_file_get_service_type (TrackerModuleFile *file);
 static gchar *                 tracker_regular_file_get_text         (TrackerModuleFile *file);
 static TrackerModuleMetadata * tracker_regular_file_get_metadata     (TrackerModuleFile *file);
+static void                    tracker_regular_file_cancel           (TrackerModuleFile *file);
 
 
 G_DEFINE_DYNAMIC_TYPE (TrackerRegularFile, tracker_regular_file, TRACKER_TYPE_MODULE_FILE);
@@ -73,6 +74,7 @@
         file_class->get_service_type = tracker_regular_file_get_service_type;
         file_class->get_text = tracker_regular_file_get_text;
         file_class->get_metadata = tracker_regular_file_get_metadata;
+	file_class->cancel = tracker_regular_file_cancel;
 }
 
 static void
@@ -203,6 +205,15 @@
 	return tracker_module_metadata_utils_get_text (tracker_module_file_get_file (file));
 }
 
+static void
+tracker_regular_file_cancel (TrackerModuleFile *file)
+{
+        GFile *f;
+
+        f = tracker_module_file_get_file (file);
+
+	tracker_module_metadata_utils_cancel (f);
+}
 
 void
 indexer_module_initialize (GTypeModule *module)

Modified: trunk/src/tracker-indexer/tracker-indexer.c
==============================================================================
--- trunk/src/tracker-indexer/tracker-indexer.c	(original)
+++ trunk/src/tracker-indexer/tracker-indexer.c	Wed Mar 25 16:43:51 2009
@@ -136,6 +136,8 @@
 
 	GTimer *timer;
 
+	GVolumeMonitor *volume_monitor;
+
 	guint idle_id;
 	guint pause_for_duration_id;
 	guint signal_status_id;
@@ -211,6 +213,11 @@
 static void     check_finished         (TrackerIndexer      *indexer,
 					gboolean             interrupted);
 
+static gboolean item_process           (TrackerIndexer      *indexer,
+					PathInfo            *info,
+					const gchar         *dirname,
+					const gchar         *basename);
+
 
 static guint signals[LAST_SIGNAL] = { 0, };
 
@@ -519,6 +526,66 @@
 }
 
 static void
+check_mount_removal (GQueue   *queue,
+		     GFile    *mount_root,
+		     gboolean  remove_first)
+{
+	GList *list, *next;
+	PathInfo *info;
+
+	if (!queue->head) {
+		/* No elements here */
+		return;
+	}
+
+	list = (remove_first) ? queue->head : queue->head->next;
+
+	while (list) {
+		next = list->next;
+		info = list->data;
+
+		if (g_file_has_prefix (info->file, mount_root) ||
+		    (info->source_file && g_file_has_prefix (info->source_file, mount_root))) {
+			g_queue_delete_link (queue, list);
+			path_info_free (info);
+		}
+
+		list = next;
+	}
+}
+
+static void
+mount_pre_unmount_cb (GVolumeMonitor *volume_monitor,
+		      GMount         *mount,
+		      TrackerIndexer *indexer)
+{
+	TrackerIndexerPrivate *priv;
+	GFile *mount_root;
+	PathInfo *current_info;
+	gchar *uri;
+
+	mount_root = g_mount_get_root (mount);
+	priv = indexer->private;
+
+	uri = g_file_get_uri (mount_root);
+	g_debug ("Pre-unmount event for '%s', removing all child elements to be processed", uri);
+	g_free (uri);
+
+	/* Cancel any future elements in the mount */
+	check_mount_removal (priv->dir_queue, mount_root, TRUE);
+	check_mount_removal (priv->file_queue, mount_root, FALSE);
+
+	/* Now cancel current element if it's also in the mount */
+	current_info = g_queue_peek_head (indexer->private->file_queue);
+
+	if (g_file_has_prefix (current_info->file, mount_root)) {
+		tracker_module_file_cancel (current_info->module_file);
+	}
+
+	g_object_unref (mount_root);
+}
+
+static void
 tracker_indexer_finalize (GObject *object)
 {
 	TrackerIndexerPrivate *priv;
@@ -593,6 +660,13 @@
 	g_queue_foreach (priv->file_queue, (GFunc) path_info_free, NULL);
 	g_queue_free (priv->file_queue);
 
+	if (priv->volume_monitor) {
+		g_signal_handlers_disconnect_by_func (priv->volume_monitor,
+						      mount_pre_unmount_cb,
+						      object);
+		g_object_unref (priv->volume_monitor);
+	}
+
 	G_OBJECT_CLASS (tracker_indexer_parent_class)->finalize (object);
 }
 
@@ -984,6 +1058,11 @@
 	priv->email_metadata = tracker_db_manager_get_db_interface (TRACKER_DB_EMAIL_METADATA);
 	priv->email_contents = tracker_db_manager_get_db_interface (TRACKER_DB_EMAIL_CONTENTS);
 
+	/* Set up volume monitor */
+	priv->volume_monitor = g_volume_monitor_get ();
+	g_signal_connect (priv->volume_monitor, "mount-pre-unmount",
+			  G_CALLBACK (mount_pre_unmount_cb), indexer);
+
 	/* Set up idle handler to process files/directories */
 	state_check (indexer);
 }
@@ -1482,10 +1561,10 @@
 		    PathInfo              *info,
 		    const gchar           *dirname,
 		    const gchar           *basename,
-		    TrackerModuleMetadata *metadata)
+		    TrackerModuleMetadata *metadata,
+		    const gchar           *text)
 {
 	TrackerService *service;
-	gchar *text;
 	guint32 id;
 	gchar *mount_point = NULL;
 	gchar *service_path;
@@ -1499,7 +1578,6 @@
 	if (tracker_data_query_service_exists (service, dirname, basename, &id, NULL)) {
 		TrackerDataMetadata *old_metadata_emb, *old_metadata_non_emb;
 		gchar *old_text;
-		gchar *new_text;
 
 		if (tracker_module_file_get_flags (info->module_file) & TRACKER_FILE_CONTENTS_STATIC) {
 			/* According to the module, the metadata can't change for this item */
@@ -1538,9 +1616,8 @@
 		 * difference and add the words.
 		 */
 		old_text = tracker_data_query_content (service, id);
-		new_text = tracker_module_file_get_text (info->module_file);
 
-		item_update_content (indexer, service, id, old_text, new_text);
+		item_update_content (indexer, service, id, old_text, text);
 
 		if (strcmp (tracker_service_get_name (service), "Folders") == 0) {
 			gchar *path;
@@ -1556,7 +1633,6 @@
 		}
 
 		g_free (old_text);
-		g_free (new_text);
 		tracker_data_metadata_free (old_metadata_emb);
 		tracker_data_metadata_free (old_metadata_non_emb);
 	} else {
@@ -1578,8 +1654,6 @@
 
 		index_metadata (indexer, id, service, metadata);
 
-		text = tracker_module_file_get_text (info->module_file);
-
 		if (text) {
 			/* Save in the index */
 			index_text_with_parsing (indexer,
@@ -1590,7 +1664,6 @@
 
 			/* Save in the DB */
 			tracker_data_update_set_content (service, id, text);
-			g_free (text);
 		}
 
 		g_hash_table_destroy (data);
@@ -1831,7 +1904,7 @@
 	schedule_flush (indexer, FALSE);
 }
 
-static void
+static gboolean
 item_move (TrackerIndexer  *indexer,
 	   PathInfo	   *info,
 	   const gchar	   *dirname,
@@ -1847,7 +1920,7 @@
 	service = get_service_for_file (info->module_file, info->module);
 
 	if (!service) {
-		return;
+		return FALSE;
 	}
 
 	path = g_file_get_path (info->file);
@@ -1861,25 +1934,20 @@
 						basename,
 						&service_id,
 						NULL)) {
-		TrackerModuleMetadata *metadata;
 		gchar *dest_dirname, *dest_basename;
+		gboolean res;
 
 		g_message ("Source file '%s' not found in database to move, indexing '%s' from scratch", source_path, path);
 
-		metadata = tracker_module_file_get_metadata (info->module_file);
 		tracker_file_get_path_and_name (path, &dest_dirname, &dest_basename);
-
-		if (metadata) {
-			item_add_or_update (indexer, info, dest_dirname, dest_basename, metadata);
-			g_object_unref (metadata);
-		}
+		res = item_process (indexer, info, dest_dirname, dest_basename);
 
 		g_free (dest_dirname);
 		g_free (dest_basename);
 		g_free (path);
 		g_free (source_path);
 
-		return;
+		return res;
 	}
 
 	tracker_file_get_path_and_name (path, &dest_dirname, &dest_basename);
@@ -1916,7 +1984,7 @@
 			tracker_data_metadata_free (old_metadata);
 		}
 
-		return;
+		return FALSE;
 	}
 
 	/* Update item being moved */
@@ -1957,6 +2025,8 @@
 
 	g_free (source_path);
 	g_free (path);
+
+	return TRUE;
 }
 
 
@@ -2046,6 +2116,46 @@
 	g_free (path);
 }
 
+static gboolean
+item_process (TrackerIndexer *indexer,
+	      PathInfo       *info,
+	      const gchar    *dirname,
+	      const gchar    *basename)
+{
+	TrackerModuleMetadata *metadata;
+	gchar *text;
+
+	metadata = tracker_module_file_get_metadata (info->module_file);
+
+	if (tracker_module_file_is_cancelled (info->module_file)) {
+		if (metadata) {
+			g_object_unref (metadata);
+		}
+
+		return FALSE;
+	}
+
+	if (metadata) {
+		text = tracker_module_file_get_text (info->module_file);
+
+		if (tracker_module_file_is_cancelled (info->module_file)) {
+			g_object_unref (metadata);
+			g_free (text);
+
+			return FALSE;
+		}
+
+		item_add_or_update (indexer, info, dirname, basename, metadata, text);
+
+		g_object_unref (metadata);
+		g_free (text);
+	} else {
+		item_mark_for_removal (indexer, info, dirname, basename);
+	}
+
+	return TRUE;
+}
+
 /*
  * TODO: Check how are we using this functions. 
  *       I think 99% of the time "values" has only 1 element.
@@ -2361,8 +2471,8 @@
 process_file (TrackerIndexer *indexer,
 	      PathInfo	     *info)
 {
-	TrackerModuleMetadata *metadata;
 	gchar *uri, *dirname, *basename;
+	gboolean inc_counters = FALSE;
 
 	/* Note: If info->source_file is set, the PathInfo is for a
 	 * MOVE event not for normal file event.
@@ -2434,26 +2544,26 @@
 	 * a service and set the metadata.
 	 */
 	if (G_UNLIKELY (info->source_file)) {
-		item_move (indexer, info, dirname, basename);
+		if (item_move (indexer, info, dirname, basename)) {
+			inc_counters = TRUE;
+		}
 	} else {
-		metadata = tracker_module_file_get_metadata (info->module_file);
-
-		if (metadata) {
-			item_add_or_update (indexer, info, dirname, basename, metadata);
-			g_object_unref (metadata);
-		} else {
-			item_mark_for_removal (indexer, info, dirname, basename);
+		if (item_process (indexer, info, dirname, basename)) {
+			inc_counters = TRUE;
 		}
 	}
 
-	indexer->private->subelements_processed++;
-	indexer->private->items_processed++;
-	indexer->private->items_to_index++;
+	if (inc_counters) {
+		indexer->private->subelements_processed++;
+		indexer->private->items_processed++;
+		indexer->private->items_to_index++;
+	}
 
 	g_free (dirname);
 	g_free (basename);
 
-	if (TRACKER_IS_MODULE_ITERATABLE (info->module_file)) {
+	if (!tracker_module_file_is_cancelled (info->module_file) &&
+	    TRACKER_IS_MODULE_ITERATABLE (info->module_file)) {
 		return !tracker_module_iteratable_iter_contents (TRACKER_MODULE_ITERATABLE (info->module_file));
 	}
 

Modified: trunk/src/tracker-indexer/tracker-module-file.c
==============================================================================
--- trunk/src/tracker-indexer/tracker-module-file.c	(original)
+++ trunk/src/tracker-indexer/tracker-module-file.c	Wed Mar 25 16:43:51 2009
@@ -31,11 +31,13 @@
 
 struct TrackerModuleFilePrivate {
         GFile *file;
+        guint cancelled : 1;
 };
 
 enum {
         PROP_0,
-        PROP_FILE
+        PROP_FILE,
+        PROP_CANCELLED
 };
 
 
@@ -88,6 +90,13 @@
                                                               "File corresponding to the TrackerModuleFile",
                                                               G_TYPE_FILE,
                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+        g_object_class_install_property (object_class,
+					 PROP_CANCELLED,
+					 g_param_spec_boolean ("cancelled",
+                                                               "Cancelled",
+                                                               "Whether operations on this file were cancelled",
+                                                               FALSE,
+                                                               G_PARAM_READWRITE));
 
         g_type_class_add_private (object_class, sizeof (TrackerModuleFilePrivate));
 }
@@ -158,6 +167,9 @@
         case PROP_FILE:
                 g_value_set_object (value, priv->file);
                 break;
+        case PROP_CANCELLED:
+                g_value_set_boolean (value, priv->cancelled);
+                break;
         default:
                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
         }
@@ -314,3 +326,29 @@
 
         return 0;
 }
+
+void
+tracker_module_file_cancel (TrackerModuleFile *file)
+{
+        TrackerModuleFilePrivate *priv;
+
+        priv = TRACKER_MODULE_FILE_GET_PRIVATE (file);
+
+        if (!priv->cancelled) {
+                priv->cancelled = TRUE;
+
+                if (TRACKER_MODULE_FILE_GET_CLASS (file)->cancel != NULL) {
+                        TRACKER_MODULE_FILE_GET_CLASS (file)->cancel (file);
+                }
+        }
+}
+
+gboolean
+tracker_module_file_is_cancelled (TrackerModuleFile *file)
+{
+        TrackerModuleFilePrivate *priv;
+
+        priv = TRACKER_MODULE_FILE_GET_PRIVATE (file);
+
+        return priv->cancelled;
+}

Modified: trunk/src/tracker-indexer/tracker-module-file.h
==============================================================================
--- trunk/src/tracker-indexer/tracker-module-file.h	(original)
+++ trunk/src/tracker-indexer/tracker-module-file.h	Wed Mar 25 16:43:51 2009
@@ -60,6 +60,7 @@
         gchar * (* get_text) (TrackerModuleFile *file);
         TrackerModuleMetadata * (* get_metadata) (TrackerModuleFile *file);
         TrackerModuleFlags (* get_flags) (TrackerModuleFile *file);
+        void (* cancel) (TrackerModuleFile *file);
 };
 
 GType tracker_module_flags_get_type (void) G_GNUC_CONST;
@@ -72,6 +73,9 @@
 TrackerModuleMetadata * tracker_module_file_get_metadata     (TrackerModuleFile *file);
 TrackerModuleFlags      tracker_module_file_get_flags        (TrackerModuleFile *file);
 
+void                    tracker_module_file_cancel           (TrackerModuleFile *file);
+gboolean                tracker_module_file_is_cancelled     (TrackerModuleFile *file);
+
 
 G_END_DECLS
 

Modified: trunk/src/tracker-indexer/tracker-module-metadata-utils.c
==============================================================================
--- trunk/src/tracker-indexer/tracker-module-metadata-utils.c	(original)
+++ trunk/src/tracker-indexer/tracker-module-metadata-utils.c	Wed Mar 25 16:43:51 2009
@@ -43,323 +43,383 @@
 #include "tracker-dbus.h"
 
 #define METADATA_FILE_NAME_DELIMITED "File:NameDelimited"
-#define METADATA_FILE_EXT	     "File:Ext"
-#define METADATA_FILE_PATH	     "File:Path"
-#define METADATA_FILE_NAME	     "File:Name"
-#define METADATA_FILE_LINK	     "File:Link"
-#define METADATA_FILE_MIMETYPE	     "File:Mime"
-#define METADATA_FILE_SIZE	     "File:Size"
-#define METADATA_FILE_MODIFIED	     "File:Modified"
-#define METADATA_FILE_ACCESSED	     "File:Accessed"
-
-#undef	TRY_LOCALE_TO_UTF8_CONVERSION
-#define TEXT_MAX_SIZE		     1048576  /* bytes */
-#define TEXT_CHECK_SIZE		     65535    /* bytes */
+#define METADATA_FILE_EXT            "File:Ext"
+#define METADATA_FILE_PATH           "File:Path"
+#define METADATA_FILE_NAME           "File:Name"
+#define METADATA_FILE_LINK           "File:Link"
+#define METADATA_FILE_MIMETYPE       "File:Mime"
+#define METADATA_FILE_SIZE           "File:Size"
+#define METADATA_FILE_MODIFIED       "File:Modified"
+#define METADATA_FILE_ACCESSED       "File:Accessed"
+
+#undef  TRY_LOCALE_TO_UTF8_CONVERSION
+#define TEXT_MAX_SIZE                1048576  /* bytes */
+#define TEXT_CHECK_SIZE              65535    /* bytes */
 
 #define TEXT_EXTRACTION_TIMEOUT      10
 
 typedef struct {
-	GPid pid;
-	guint stdout_watch_id;
-	GIOChannel *stdin_channel;
-	GIOChannel *stdout_channel;
-	GMainLoop  *data_incoming_loop;
-	gpointer data;
+        GPid pid;
+        guint stdout_watch_id;
+        GIOChannel *stdin_channel;
+        GIOChannel *stdout_channel;
+        GMainLoop  *data_incoming_loop;
+        gpointer data;
 } ProcessContext;
 
+typedef struct {
+        GHashTable *metadata;
+        GMainLoop *main_loop;
+        GPid pid;
+} ExtractorContext;
+
 static DBusGProxy *
 get_dbus_extract_proxy (void)
 {
-	static DBusGProxy *proxy = NULL;
-	DBusGConnection *connection;
-	GError *error = NULL;
-
-	/* FIXME: Not perfect, we leak */
-	if (G_LIKELY (proxy)) {
-		return proxy;
-	}
-
-	connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+        static DBusGProxy *proxy = NULL;
+        DBusGConnection *connection;
+        GError *error = NULL;
+
+        /* FIXME: Not perfect, we leak */
+        if (G_LIKELY (proxy)) {
+                return proxy;
+        }
+
+        connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+
+        if (!connection) {
+                g_critical ("Could not connect to the DBus session bus, %s",
+                            error ? error->message : "no error given.");
+                g_clear_error (&error);
+                return FALSE;
+        }
+
+        /* Get proxy for Service / Path / Interface of the indexer */
+        proxy = dbus_g_proxy_new_for_name (connection,
+                                           "org.freedesktop.Tracker.Extract",
+                                           "/org/freedesktop/Tracker/Extract",
+                                           "org.freedesktop.Tracker.Extract");
+
+        if (!proxy) {
+                g_critical ("Could not create a DBusGProxy to the extract service");
+        }
 
-	if (!connection) {
-		g_critical ("Could not connect to the DBus session bus, %s",
-			    error ? error->message : "no error given.");
-		g_clear_error (&error);
-		return FALSE;
-	}
-
-	/* Get proxy for Service / Path / Interface of the indexer */
-	proxy = dbus_g_proxy_new_for_name (connection,
-					   "org.freedesktop.Tracker.Extract",
-					   "/org/freedesktop/Tracker/Extract",
-					   "org.freedesktop.Tracker.Extract");
-
-	if (!proxy) {
-		g_critical ("Could not create a DBusGProxy to the extract service");
-	}
-
-	return proxy;
+        return proxy;
 }
 
 static void
 process_context_destroy (ProcessContext *context)
 {
-	if (context->stdin_channel) {
-		g_io_channel_shutdown (context->stdin_channel, FALSE, NULL);
-		g_io_channel_unref (context->stdin_channel);
-		context->stdin_channel = NULL;
-	}
-
-	if (context->stdout_watch_id != 0) {
-		g_source_remove (context->stdout_watch_id);
-		context->stdout_watch_id = 0;
-	}
-
-	if (context->stdout_channel) {
-		g_io_channel_shutdown (context->stdout_channel, FALSE, NULL);
-		g_io_channel_unref (context->stdout_channel);
-		context->stdout_channel = NULL;
-	}
+        if (context->stdin_channel) {
+                g_io_channel_shutdown (context->stdin_channel, FALSE, NULL);
+                g_io_channel_unref (context->stdin_channel);
+                context->stdin_channel = NULL;
+        }
+
+        if (context->stdout_watch_id != 0) {
+                g_source_remove (context->stdout_watch_id);
+                context->stdout_watch_id = 0;
+        }
+
+        if (context->stdout_channel) {
+                g_io_channel_shutdown (context->stdout_channel, FALSE, NULL);
+                g_io_channel_unref (context->stdout_channel);
+                context->stdout_channel = NULL;
+        }
+
+        if (context->data_incoming_loop) {
+                if (g_main_loop_is_running (context->data_incoming_loop)) {
+                        g_main_loop_quit (context->data_incoming_loop);
+                }
+
+                g_main_loop_unref (context->data_incoming_loop);
+                context->data_incoming_loop = NULL;
+        }
+
+        if (context->pid != 0) {
+                g_spawn_close_pid (context->pid);
+                context->pid = 0;
+        }
 
-	if (context->data_incoming_loop) {
-		if (g_main_loop_is_running (context->data_incoming_loop)) {
-			g_main_loop_quit (context->data_incoming_loop);
-		}
+        g_free (context);
+}
 
-		g_main_loop_unref (context->data_incoming_loop);
-		context->data_incoming_loop = NULL;
-	}
+static void
+process_context_kill (ProcessContext *context)
+{
+        g_message ("Attempting to kill text filter with SIGKILL");
 
-	if (context->pid != 0) {
-		g_spawn_close_pid (context->pid);
-		context->pid = 0;
-	}
+        if (kill (context->pid, SIGKILL) == -1) {
+                const gchar *str = g_strerror (errno);
 
-	g_free (context);
+                g_message ("  Could not kill process %d, %s",
+                           context->pid,
+                           str ? str : "no error given");
+        } else {
+                g_message ("  Killed process %d", context->pid);
+        }
 }
 
 static void
-process_context_child_watch_cb (GPid	 pid,
-				gint	 status,
-				gpointer user_data)
-{
-	ProcessContext *context;
-
-	g_debug ("Process '%d' exited with code %d",
-		 pid,
-		 status);
+process_context_child_watch_cb (GPid     pid,
+                                gint     status,
+                                gpointer user_data)
+{
+        ProcessContext *context;
+
+        g_debug ("Process '%d' exited with code %d",
+                 pid,
+                 status);
 
-	context = (ProcessContext *) user_data;
-	process_context_destroy (context);
+        context = (ProcessContext *) user_data;
+        process_context_destroy (context);
 }
 
 static ProcessContext *
 process_context_create (const gchar **argv,
-			GIOFunc       stdout_watch_func)
+                        GIOFunc       stdout_watch_func)
 {
-	ProcessContext *context;
-	GIOChannel *stdin_channel, *stdout_channel;
-	GIOFlags flags;
-	GPid pid;
-
-	if (!tracker_spawn_async_with_channels (argv,
-						TEXT_EXTRACTION_TIMEOUT,
-						&pid,
-						&stdin_channel,
-						&stdout_channel,
-						NULL)) {
-		return NULL;
-	}
+        ProcessContext *context;
+        GIOChannel *stdin_channel, *stdout_channel;
+        GIOFlags flags;
+        GPid pid;
+
+        if (!tracker_spawn_async_with_channels (argv,
+                                                TEXT_EXTRACTION_TIMEOUT,
+                                                &pid,
+                                                &stdin_channel,
+                                                &stdout_channel,
+                                                NULL)) {
+                return NULL;
+        }
+
+        g_debug ("Process '%d' spawned for command:'%s'",
+                 pid,
+                 argv[0]);
+
+        context = g_new0 (ProcessContext, 1);
+        context->pid = pid;
+        context->stdin_channel = stdin_channel;
+        context->stdout_channel = stdout_channel;
+        context->data_incoming_loop = g_main_loop_new (NULL, FALSE);
+        context->stdout_watch_id = g_io_add_watch (stdout_channel,
+                                                   G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP,
+                                                   stdout_watch_func,
+                                                   context);
+
+        flags = g_io_channel_get_flags (context->stdout_channel);
+        flags |= G_IO_FLAG_NONBLOCK;
+
+        g_io_channel_set_flags (context->stdout_channel, flags, NULL);
+
+        g_child_watch_add (context->pid, process_context_child_watch_cb, context);
+
+        return context;
+}
+
+static ExtractorContext *
+extractor_context_create (TrackerModuleMetadata *metadata)
+{
+        ExtractorContext *context;
+        GError *error = NULL;
+        pid_t pid;
+
+        /* Call extractor to get PID so we can kill it if anything goes wrong. */
+        if (!org_freedesktop_Tracker_Extract_get_pid (get_dbus_extract_proxy (),
+                                                      &pid,
+                                                      &error)) {
+                g_message ("Couldn't get PID from tracker-extract, %s",
+                           error ? error->message : "no error given");
+                g_clear_error (&error);
+                return NULL;
+        }
+
+        context = g_slice_new0 (ExtractorContext);
+        context->main_loop = g_main_loop_new (NULL, FALSE);
+        context->metadata = g_object_ref (metadata);
+        context->pid = pid;
 
-	g_debug ("Process '%d' spawned for command:'%s'",
-		 pid,
-		 argv[0]);
-
-	context = g_new0 (ProcessContext, 1);
-	context->pid = pid;
-	context->stdin_channel = stdin_channel;
-	context->stdout_channel = stdout_channel;
-	context->data_incoming_loop = g_main_loop_new (NULL, FALSE);
-	context->stdout_watch_id = g_io_add_watch (stdout_channel,
-						   G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP,
-						   stdout_watch_func,
-						   context);
+        return context;
+}
 
-	flags = g_io_channel_get_flags (context->stdout_channel);
-	flags |= G_IO_FLAG_NONBLOCK;
+static void
+extractor_context_destroy (ExtractorContext *context)
+{
+        g_object_unref (context->metadata);
+        g_main_loop_unref (context->main_loop);
+        g_slice_free (ExtractorContext, context);
+}
 
-	g_io_channel_set_flags (context->stdout_channel, flags, NULL);
+static void
+extractor_context_kill (ExtractorContext *context)
+{
+        g_message ("Attempting to kill tracker-extract with SIGKILL");
 
-	g_child_watch_add (context->pid, process_context_child_watch_cb, context);
+        if (kill (context->pid, SIGKILL) == -1) {
+                const gchar *str = g_strerror (errno);
 
-	return context;
+                g_message ("  Could not kill process %d, %s",
+                           context->pid,
+                           str ? str : "no error given");
+        } else {
+                g_message ("  Killed process %d", context->pid);
+        }
 }
 
 static void
 metadata_utils_add_embedded_data (TrackerModuleMetadata *metadata,
-				  TrackerField          *field,
-				  const gchar           *value)
+                                  TrackerField          *field,
+                                  const gchar           *value)
 {
-	gchar *utf_value;
-
-	if (!g_utf8_validate (value, -1, NULL)) {
-		utf_value = g_locale_to_utf8 (value, -1, NULL, NULL, NULL);
-	} else {
-		utf_value = g_strdup (value);
-	}
-
-	if (utf_value) {
-		const gchar *name;
-
-		name = tracker_field_get_name (field);
-
-		if (tracker_field_get_data_type (field) == TRACKER_FIELD_TYPE_DATE) {
-			gchar *time_str;
+        gchar *utf_value;
 
-			/* Dates come in ISO 8601 format, we handle them as time_t */
-			time_str = tracker_date_to_time_string (utf_value);
-			tracker_module_metadata_add_string (metadata, name, time_str);
-			g_free (time_str);
-		} else {
-			tracker_module_metadata_add_string (metadata, name, utf_value);
-		}
+        if (!g_utf8_validate (value, -1, NULL)) {
+                utf_value = g_locale_to_utf8 (value, -1, NULL, NULL, NULL);
+        } else {
+                utf_value = g_strdup (value);
+        }
+
+        if (utf_value) {
+                const gchar *name;
+
+                name = tracker_field_get_name (field);
+
+                if (tracker_field_get_data_type (field) == TRACKER_FIELD_TYPE_DATE) {
+                        gchar *time_str;
+
+                        /* Dates come in ISO 8601 format, we handle them as time_t */
+                        time_str = tracker_date_to_time_string (utf_value);
+                        tracker_module_metadata_add_string (metadata, name, time_str);
+                        g_free (time_str);
+                } else {
+                        tracker_module_metadata_add_string (metadata, name, utf_value);
+                }
 
-		g_free (utf_value);
-	}
+                g_free (utf_value);
+        }
 }
 
 static void
 metadata_utils_get_embedded_foreach (gpointer key,
-				     gpointer value,
-				     gpointer user_data)
+                                     gpointer value,
+                                     gpointer user_data)
 {
-	TrackerModuleMetadata *metadata;
-	TrackerField *field;
-	gchar *key_str;
-	gchar *value_str;
-
-	metadata = user_data;
-	key_str = key;
-	value_str = value;
-	
-	if (!key || !value) {
-		return;
-	}
-	
-	field = tracker_ontology_get_field_by_name (key_str);
-	if (!field) {
-		g_warning ("Field name '%s' isn't described in the ontology", key_str);
-		return;
-	}
-	
-	if (tracker_field_get_multiple_values (field)) {
-		GStrv strv;
-		guint i;
-		
-		strv = g_strsplit (value_str, "|", -1);
-		
-		for (i = 0; strv[i]; i++) {
-			metadata_utils_add_embedded_data (metadata, field, strv[i]);
-		}
-		
-		g_strfreev (strv);
-	} else {
-		metadata_utils_add_embedded_data (metadata, field, value_str);
-	}
+        TrackerModuleMetadata *metadata;
+        TrackerField *field;
+        gchar *key_str;
+        gchar *value_str;
+
+        metadata = user_data;
+        key_str = key;
+        value_str = value;
+        
+        if (!key || !value) {
+                return;
+        }
+        
+        field = tracker_ontology_get_field_by_name (key_str);
+        if (!field) {
+                g_warning ("Field name '%s' isn't described in the ontology", key_str);
+                return;
+        }
+        
+        if (tracker_field_get_multiple_values (field)) {
+                GStrv strv;
+                guint i;
+                
+                strv = g_strsplit (value_str, "|", -1);
+                
+                for (i = 0; strv[i]; i++) {
+                        metadata_utils_add_embedded_data (metadata, field, strv[i]);
+                }
+                
+                g_strfreev (strv);
+        } else {
+                metadata_utils_add_embedded_data (metadata, field, value_str);
+        }
 }
 
 static void
-metadata_utils_get_embedded (const char            *path,
-			     const char            *mime_type,
-			     TrackerModuleMetadata *metadata)
-{
-	GHashTable *values = NULL;
-	GError *error = NULL;
-	const gchar *service_type;
-	pid_t pid;
-
-	service_type = tracker_ontology_get_service_by_mime (mime_type);
-	if (!service_type) {
-		return;
-	}
-
-	if (!tracker_ontology_service_has_metadata (service_type)) {
-		return;
-	}
-
-	/* Call extractor to get PID so we can kill it if anything goes wrong. */
-	if (!org_freedesktop_Tracker_Extract_get_pid (get_dbus_extract_proxy (),
-						      &pid, 
-						      &error)) {
-		g_message ("Couldn't get PID from tracker-extract, %s",
-			   error ? error->message : "no error given");
-		g_clear_error (&error);
-		return;
-	}
-
-	/* Call extractor to get data here */
-	if (!org_freedesktop_Tracker_Extract_get_metadata (get_dbus_extract_proxy (),
-							   path, 
-							   mime_type, 
-							   &values, 
-							   &error)) {
-		gboolean should_kill = TRUE;
-
-		if (G_LIKELY (error)) {
-			switch (error->code) {
-			case DBUS_GERROR_FAILED:
-			case DBUS_GERROR_NO_MEMORY:
-			case DBUS_GERROR_NO_REPLY:
-			case DBUS_GERROR_IO_ERROR:
-			case DBUS_GERROR_LIMITS_EXCEEDED:
-			case DBUS_GERROR_TIMEOUT:
-			case DBUS_GERROR_DISCONNECTED:
-			case DBUS_GERROR_TIMED_OUT:
-			case DBUS_GERROR_REMOTE_EXCEPTION:
-				break;
-
-			default:
-				should_kill = FALSE;
-				break;
-			}
-		}
-
-		g_message ("Couldn't extract metadata for path:'%s' and mime:'%s', %s",
-			   path,
-			   mime_type,
-			   error ? error->message : "no error given");
-
-		g_clear_error (&error);
-
-		if (!should_kill) {
-			return;
-		}
+get_metadata_async_cb (DBusGProxy *proxy,
+                       GHashTable *values,
+                       GError     *error,
+                       gpointer    user_data)
+{
+        ExtractorContext *context;
+        gboolean should_kill = TRUE;
+
+        context = (ExtractorContext *) user_data;
+
+        if (error) {
+                switch (error->code) {
+                case DBUS_GERROR_FAILED:
+                case DBUS_GERROR_NO_MEMORY:
+                case DBUS_GERROR_NO_REPLY:
+                case DBUS_GERROR_IO_ERROR:
+                case DBUS_GERROR_LIMITS_EXCEEDED:
+                case DBUS_GERROR_TIMEOUT:
+                case DBUS_GERROR_DISCONNECTED:
+                case DBUS_GERROR_TIMED_OUT:
+                case DBUS_GERROR_REMOTE_EXCEPTION:
+                        break;
+
+                default:
+                        should_kill = FALSE;
+                        break;
+                }
+
+                g_message ("Couldn't extract metadata, %s",
+                           error->message);
+
+                g_clear_error (&error);
+
+                if (should_kill) {
+                        extractor_context_kill (context);
+                }
+        } else if (values) {
+                g_hash_table_foreach (values,
+                                      metadata_utils_get_embedded_foreach,
+                                      context->metadata);
 
-		/* Kill extractor, most likely it got stuck */
-		g_message ("Attempting to kill tracker-extract with SIGKILL");
+                g_hash_table_destroy (values);
+        }
 
-		if (kill (pid, SIGKILL) == -1) {
-			const gchar *str = g_strerror (errno);
-			
-			g_message ("  Could not kill process %d, %s",
-				   pid,
-				   str ? str : "no error given");
-		} else {
-			g_message ("  Killed process %d", pid);
-		}
-		
-		return;
-	}
-
-	if (!values) {
-		return;
-	}
-
-	g_hash_table_foreach (values,
-			      metadata_utils_get_embedded_foreach,
-			      metadata);
+        g_main_loop_quit (context->main_loop);
+}
 
-	g_hash_table_destroy (values);
+static void
+metadata_utils_get_embedded (GFile                 *file,
+                             const char            *mime_type,
+                             TrackerModuleMetadata *metadata)
+{
+        ExtractorContext *context;
+        const gchar *service_type;
+        gchar *path;
+
+        service_type = tracker_ontology_get_service_by_mime (mime_type);
+        if (!service_type) {
+                return;
+        }
+
+        if (!tracker_ontology_service_has_metadata (service_type)) {
+                return;
+        }
+
+        context = extractor_context_create (metadata);
+        g_object_set_data (G_OBJECT (file), "extractor-context", context);
+        path = g_file_get_path (file);
+
+        org_freedesktop_Tracker_Extract_get_metadata_async (get_dbus_extract_proxy (),
+                                                            path,
+                                                            mime_type,
+                                                            get_metadata_async_cb,
+                                                            context);
+
+        g_main_loop_run (context->main_loop);
+
+        g_object_set_data (G_OBJECT (file), "extractor-context", NULL);
+        extractor_context_destroy (context);
+        g_free (path);
 }
 
 static gboolean
@@ -635,7 +695,7 @@
 }
 
 static gchar *
-get_file_content_by_filter (const gchar *path,
+get_file_content_by_filter (GFile       *file,
 			    const gchar *mime)
 {
 	ProcessContext *context;
@@ -664,15 +724,15 @@
 
 	argv = g_new0 (gchar *, 3);
 	argv[0] = text_filter_file;
-	argv[1] = (gchar *) path;
+	argv[1] = g_file_get_path (file);
 
 	g_message ("Extracting text for:'%s' using filter:'%s'", argv[1], argv[0]);
 
 	context = process_context_create ((const gchar **) argv,
 					  get_file_content_read_cb);
 
-	g_free (text_filter_file);
-	g_free (argv);
+	g_strfreev (argv);
+	g_object_set_data (G_OBJECT (file), "text-filter-context", context);
 
 	if (!context) {
 		return NULL;
@@ -686,6 +746,8 @@
 	 */
 	g_main_loop_run (context->data_incoming_loop);
 
+	g_object_set_data (G_OBJECT (file), "text-filter-context", NULL);
+
 	return g_string_free (text, FALSE);
 }
 
@@ -716,7 +778,7 @@
 	     strcmp (service_type, "Development") == 0)) {
 		text = get_file_content (path);
 	} else {
-		text = get_file_content_by_filter (path, mime_type);
+		text = get_file_content_by_filter (file, mime_type);
 	}
 
 	g_free (mime_type);
@@ -790,10 +852,29 @@
 	tracker_module_metadata_add_date (metadata, METADATA_FILE_MODIFIED, st.st_mtime);
 	tracker_module_metadata_add_date (metadata, METADATA_FILE_ACCESSED, st.st_atime);
 
-	metadata_utils_get_embedded (path, mime_type, metadata);
+	metadata_utils_get_embedded (file, mime_type, metadata);
 
 	g_free (mime_type);
 	g_free (path);
 
 	return metadata;
 }
+
+void
+tracker_module_metadata_utils_cancel (GFile *file)
+{
+	ProcessContext *process_context;
+	ExtractorContext *extractor_context;
+
+	process_context = g_object_get_data (G_OBJECT (file), "text-filter-context");
+
+	if (process_context) {
+		process_context_kill (process_context);
+	}
+
+	extractor_context = g_object_get_data (G_OBJECT (file), "extractor-context");
+
+	if (extractor_context) {
+		extractor_context_kill (extractor_context);
+	}
+}

Modified: trunk/src/tracker-indexer/tracker-module-metadata-utils.h
==============================================================================
--- trunk/src/tracker-indexer/tracker-module-metadata-utils.h	(original)
+++ trunk/src/tracker-indexer/tracker-module-metadata-utils.h	Wed Mar 25 16:43:51 2009
@@ -34,6 +34,7 @@
 
 TrackerModuleMetadata *tracker_module_metadata_utils_get_data (GFile *file);
 gchar *		       tracker_module_metadata_utils_get_text (GFile *file);
+void                   tracker_module_metadata_utils_cancel   (GFile *file);
 
 G_END_DECLS
 



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