[tracker/extractor-controller-thread: 1/4] tracker-extract: Add controller thread



commit e4fd078dfecc87a1e3d6cddb484e5a0d6f3afb7c
Author: Carlos Garnacho <carlosg gnome org>
Date:   Wed Mar 30 15:52:21 2011 +0200

    tracker-extract: Add controller thread
    
    This thread takes care of DBus dispatching and extractor lifetime
    control, the main thread still carries out metadata extraction in
    a synchronous manner.

 src/tracker-extract/Makefile.am          |    2 +
 src/tracker-extract/tracker-controller.c |  731 ++++++++++++++++++++++++++++++
 src/tracker-extract/tracker-controller.h |   57 +++
 src/tracker-extract/tracker-extract.c    |  568 +++++------------------
 src/tracker-extract/tracker-extract.h    |   18 +-
 src/tracker-extract/tracker-main.c       |   66 +--
 6 files changed, 950 insertions(+), 492 deletions(-)
---
diff --git a/src/tracker-extract/Makefile.am b/src/tracker-extract/Makefile.am
index 12bebd3..4e052a7 100644
--- a/src/tracker-extract/Makefile.am
+++ b/src/tracker-extract/Makefile.am
@@ -433,6 +433,8 @@ tracker_extract_SOURCES = \
 	tracker-albumart.h \
 	tracker-config.c \
 	tracker-config.h \
+	tracker-controller.c \
+	tracker-controller.h \
 	tracker-extract.c \
 	tracker-extract.h \
 	tracker-read.c \
diff --git a/src/tracker-extract/tracker-controller.c b/src/tracker-extract/tracker-controller.c
new file mode 100644
index 0000000..5487c08
--- /dev/null
+++ b/src/tracker-extract/tracker-controller.c
@@ -0,0 +1,731 @@
+/*
+ * Copyright (C) 2011, Nokia <ivan frade nokia com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ */
+
+#include "tracker-controller.h"
+#include "tracker-extract.h"
+
+#include <gio/gunixoutputstream.h>
+#include <gio/gunixinputstream.h>
+#include <gio/gunixfdlist.h>
+
+#include <libtracker-common/tracker-common.h>
+#include <libtracker-extract/tracker-extract.h>
+#include <libtracker-miner/tracker-miner.h>
+#include <gio/gio.h>
+
+typedef struct TrackerControllerPrivate TrackerControllerPrivate;
+typedef struct GetMetadataData GetMetadataData;
+
+struct TrackerControllerPrivate {
+	GMainContext *context;
+	GMainLoop *main_loop;
+
+	TrackerStorage *storage;
+	TrackerExtract *extractor;
+
+	GDBusConnection *connection;
+	GDBusNodeInfo *introspection_data;
+	guint registration_id;
+
+	guint shutdown_timeout;
+	guint shutdown_timeout_id;
+
+	GCond *initialization_cond;
+	GMutex *initialization_mutex;
+	GError *initialization_error;
+
+	guint initialized : 1;
+};
+
+struct GetMetadataData {
+	TrackerController *controller;
+	GCancellable *cancellable;
+	GDBusMethodInvocation *invocation;
+	TrackerDBusRequest *request;
+	gchar *uri;
+	gchar *mimetype;
+	gint fd; /* Only for fast queries */
+};
+
+#define TRACKER_EXTRACT_SERVICE	       "org.freedesktop.Tracker1.Extract"
+#define TRACKER_EXTRACT_PATH	       "/org/freedesktop/Tracker1/Extract"
+#define TRACKER_EXTRACT_INTERFACE      "org.freedesktop.Tracker1.Extract"
+
+#define MAX_EXTRACT_TIME 10
+
+static const gchar *introspection_xml =
+	"<node>"
+	"  <interface name='org.freedesktop.Tracker1.Extract'>"
+	"    <method name='GetPid'>"
+	"      <arg type='i' name='value' direction='out' />"
+	"    </method>"
+	"    <method name='GetMetadata'>"
+	"      <arg type='s' name='uri' direction='in' />"
+	"      <arg type='s' name='mime' direction='in' />"
+	"      <arg type='s' name='preupdate' direction='out' />"
+	"      <arg type='s' name='embedded' direction='out' />"
+	"      <arg type='s' name='where' direction='out' />"
+	"    </method>"
+	"    <method name='GetMetadataFast'>"
+	"      <arg type='s' name='uri' direction='in' />"
+	"      <arg type='s' name='mime' direction='in' />"
+	"      <arg type='h' name='fd' direction='in' />"
+	"    </method>"
+	"  </interface>"
+	"</node>";
+
+enum {
+	PROP_0,
+	PROP_SHUTDOWN_TIMEOUT,
+	PROP_EXTRACTOR
+};
+
+static void	tracker_controller_initable_iface_init (GInitableIface	   *iface);
+static gboolean tracker_controller_dbus_start          (TrackerController  *controller,
+                                                        GError	          **error);
+static void	tracker_controller_dbus_stop           (TrackerController  *controller);
+
+
+G_DEFINE_TYPE_WITH_CODE (TrackerController, tracker_controller, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+                                                tracker_controller_initable_iface_init));
+
+static gboolean
+tracker_controller_initable_init (GInitable	*initable,
+                                  GCancellable	*cancellable,
+                                  GError       **error)
+{
+	return tracker_controller_start (TRACKER_CONTROLLER (initable), error);
+}
+
+static void
+tracker_controller_initable_iface_init (GInitableIface *iface)
+{
+	iface->init = tracker_controller_initable_init;
+}
+
+
+static void
+tracker_controller_finalize (GObject *object)
+{
+	TrackerControllerPrivate *priv;
+	TrackerController *controller;
+
+	controller = TRACKER_CONTROLLER (object);
+	priv = controller->priv;
+
+	if (priv->shutdown_timeout_id) {
+		g_source_remove (priv->shutdown_timeout_id);
+		priv->shutdown_timeout_id = 0;
+	}
+
+	tracker_controller_dbus_stop (controller);
+
+	g_object_unref (priv->storage);
+
+	g_main_loop_unref (priv->main_loop);
+	g_main_context_unref (priv->context);
+
+	g_cond_free (priv->initialization_cond);
+	g_mutex_free (priv->initialization_mutex);
+
+	G_OBJECT_CLASS (tracker_controller_parent_class)->finalize (object);
+}
+
+static void
+tracker_controller_get_property (GObject    *object,
+                                 guint	     param_id,
+                                 GValue	    *value,
+                                 GParamSpec *pspec)
+{
+	TrackerControllerPrivate *priv = TRACKER_CONTROLLER (object)->priv;
+
+	switch (param_id) {
+	case PROP_SHUTDOWN_TIMEOUT:
+		g_value_set_uint (value, priv->shutdown_timeout);
+		break;
+	case PROP_EXTRACTOR:
+		g_value_set_object (value, priv->extractor);
+		break;
+	}
+}
+
+static void
+tracker_controller_set_property (GObject      *object,
+                                 guint	       param_id,
+                                 const GValue *value,
+                                 GParamSpec   *pspec)
+{
+	TrackerControllerPrivate *priv = TRACKER_CONTROLLER (object)->priv;
+
+	switch (param_id) {
+	case PROP_SHUTDOWN_TIMEOUT:
+		priv->shutdown_timeout = g_value_get_uint (value);
+		break;
+	case PROP_EXTRACTOR:
+		priv->extractor = g_value_get_object (value);
+		break;
+	}
+}
+
+static void
+tracker_controller_class_init (TrackerControllerClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->finalize = tracker_controller_finalize;
+	object_class->get_property = tracker_controller_get_property;
+	object_class->set_property = tracker_controller_set_property;
+
+	g_object_class_install_property (object_class,
+	                                 PROP_SHUTDOWN_TIMEOUT,
+	                                 g_param_spec_uint ("shutdown-timeout",
+	                                                    "Shutdown timeout",
+	                                                    "Shutdown timeout, 0 to disable",
+	                                                    0, 1000, 0,
+	                                                    G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+	g_object_class_install_property (object_class,
+	                                 PROP_EXTRACTOR,
+	                                 g_param_spec_object ("extractor",
+	                                                      "Extractor",
+	                                                      "Extractor",
+	                                                      TRACKER_TYPE_EXTRACT,
+	                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_type_class_add_private (object_class, sizeof (TrackerControllerPrivate));
+}
+
+static GetMetadataData *
+metadata_data_new (TrackerController     *controller,
+                   const gchar           *uri,
+                   const gchar           *mime,
+                   GDBusMethodInvocation *invocation,
+                   TrackerDBusRequest    *request)
+{
+	GetMetadataData *data;
+
+	data = g_slice_new (GetMetadataData);
+	data->cancellable = g_cancellable_new ();
+	data->controller = controller;
+	data->uri = g_strdup (uri);
+	data->mimetype = g_strdup (mime);
+	data->invocation = invocation;
+	data->request = request;
+
+	return data;
+}
+
+static void
+metadata_data_free (GetMetadataData *data)
+{
+	/* We rely on data->invocation being freed through
+	 * the g_dbus_method_invocation_return_* methods
+	 */
+	g_free (data->uri);
+	g_free (data->mimetype);
+	g_object_unref (data->cancellable);
+	g_slice_free (GetMetadataData, data);
+}
+
+static gboolean
+reset_shutdown_timeout_cb (gpointer user_data)
+{
+	TrackerControllerPrivate *priv;
+
+	g_message ("Extractor lifetime has expired");
+
+	priv = TRACKER_CONTROLLER (user_data)->priv;
+	g_main_loop_quit (priv->main_loop);
+
+	return TRUE;
+}
+
+static void
+reset_shutdown_timeout (TrackerController *controller)
+{
+	TrackerControllerPrivate *priv;
+	GSource *source;
+
+	priv = controller->priv;
+
+	if (priv->shutdown_timeout == 0) {
+		return;
+	}
+
+	g_message ("(Re)setting shutdown timeout");
+
+	if (priv->shutdown_timeout_id != 0) {
+		g_source_remove (priv->shutdown_timeout_id);
+	}
+
+	source = g_timeout_source_new_seconds (priv->shutdown_timeout);
+	g_source_set_callback (source,
+	                       reset_shutdown_timeout_cb,
+	                       controller, NULL);
+
+	priv->shutdown_timeout_id = g_source_attach (source, priv->context);
+}
+
+static void
+tracker_controller_init (TrackerController *controller)
+{
+	TrackerControllerPrivate *priv;
+
+	priv = controller->priv = G_TYPE_INSTANCE_GET_PRIVATE (controller,
+	                                                       TRACKER_TYPE_CONTROLLER,
+	                                                       TrackerControllerPrivate);
+
+	priv->context = g_main_context_new ();
+	priv->main_loop = g_main_loop_new (priv->context, FALSE);
+
+	priv->storage = tracker_storage_new ();
+
+	priv->initialization_cond = g_cond_new ();
+	priv->initialization_mutex = g_mutex_new ();
+}
+
+static void
+handle_method_call_get_pid (TrackerController	  *controller,
+                            GDBusMethodInvocation *invocation,
+                            GVariant		  *parameters)
+{
+	TrackerDBusRequest *request;
+	pid_t value;
+
+	request = tracker_g_dbus_request_begin (invocation,
+	                                        "%s()",
+	                                        __FUNCTION__);
+
+	reset_shutdown_timeout (controller);
+	value = getpid ();
+	tracker_dbus_request_debug (request,
+	                            "PID is %d",
+	                            value);
+
+	tracker_dbus_request_end (request, NULL);
+
+	g_dbus_method_invocation_return_value (invocation,
+	                                       g_variant_new ("(i)", (gint) value));
+}
+
+static void
+get_metadata_cb (GObject      *object,
+                 GAsyncResult *res,
+                 gpointer      user_data)
+{
+	GetMetadataData *data;
+	TrackerExtractInfo *info;
+
+	data = user_data;
+	info = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
+
+	if (info) {
+		if (tracker_sparql_builder_get_length (info->statements) > 0) {
+			const gchar *preupdate_str = NULL;
+
+			if (tracker_sparql_builder_get_length (info->preupdate) > 0) {
+				preupdate_str = tracker_sparql_builder_get_result (info->preupdate);
+			}
+
+			g_dbus_method_invocation_return_value (data->invocation,
+			                                       g_variant_new ("(sss)",
+			                                                      preupdate_str ? preupdate_str : "",
+			                                                      tracker_sparql_builder_get_result (info->statements),
+			                                                      info->where ? info->where : ""));
+		} else {
+			g_dbus_method_invocation_return_value (data->invocation,
+			                                       g_variant_new ("(sss)", "", "", ""));
+		}
+
+		tracker_dbus_request_end (data->request, NULL);
+	} else {
+		GError *error = NULL;
+
+		g_message ("Controller thread (%p) got error back", g_thread_self ());
+		g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), &error);
+		tracker_dbus_request_end (data->request, error);
+		g_dbus_method_invocation_return_gerror (data->invocation, error);
+		g_error_free (error);
+	}
+
+	metadata_data_free (data);
+}
+
+static void
+handle_method_call_get_metadata (TrackerController     *controller,
+                                 GDBusMethodInvocation *invocation,
+                                 GVariant              *parameters)
+{
+	TrackerControllerPrivate *priv;
+	GetMetadataData *data;
+	TrackerDBusRequest *request;
+	const gchar *uri, *mime;
+
+	priv = controller->priv;
+	g_variant_get (parameters, "(&s&s)", &uri, &mime);
+
+	reset_shutdown_timeout (controller);
+	request = tracker_dbus_request_begin (NULL, "%s (%s, %s)", __FUNCTION__, uri, mime);
+
+	data = metadata_data_new (controller, uri, mime, invocation, request);
+	tracker_extract_file (priv->extractor, uri, mime, data->cancellable,
+	                      get_metadata_cb, data);
+}
+
+static void
+get_metadata_fast_cb (GObject      *object,
+                      GAsyncResult *res,
+                      gpointer      user_data)
+{
+	GetMetadataData *data;
+	TrackerExtractInfo *info;
+
+	data = user_data;
+	info = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
+
+	if (info) {
+		GOutputStream *unix_output_stream;
+		GOutputStream *buffered_output_stream;
+		GDataOutputStream *data_output_stream;
+		GError *error = NULL;
+
+		g_message ("Controller thread (%p) got metadata back", g_thread_self ());
+
+		unix_output_stream = g_unix_output_stream_new (data->fd, TRUE);
+		buffered_output_stream = g_buffered_output_stream_new_sized (unix_output_stream,
+		                                                             64 * 1024);
+		data_output_stream = g_data_output_stream_new (buffered_output_stream);
+		g_data_output_stream_set_byte_order (G_DATA_OUTPUT_STREAM (data_output_stream),
+		                                     G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN);
+
+		if (tracker_sparql_builder_get_length (info->statements) > 0) {
+			const gchar *preupdate_str = NULL;
+
+			if (tracker_sparql_builder_get_length (info->preupdate) > 0) {
+				preupdate_str = tracker_sparql_builder_get_result (info->preupdate);
+			}
+
+			g_data_output_stream_put_string (data_output_stream,
+			                                 preupdate_str ? preupdate_str : "",
+			                                 NULL,
+			                                 &error);
+
+			if (!error) {
+				g_data_output_stream_put_byte (data_output_stream,
+				                               0,
+				                               NULL,
+				                               &error);
+			}
+
+			if (!error) {
+				g_data_output_stream_put_string (data_output_stream,
+				                                 tracker_sparql_builder_get_result (info->statements),
+				                                 NULL,
+				                                 &error);
+			}
+
+			if (!error) {
+				g_data_output_stream_put_byte (data_output_stream,
+				                               0,
+				                               NULL,
+				                               &error);
+			}
+
+			if (!error && info->where) {
+				g_data_output_stream_put_string (data_output_stream,
+				                                 info->where,
+				                                 NULL,
+				                                 &error);
+			}
+
+			if (!error) {
+				g_data_output_stream_put_byte (data_output_stream,
+				                               0,
+				                               NULL,
+				                               &error);
+			}
+		}
+
+		g_object_unref (data_output_stream);
+		g_object_unref (buffered_output_stream);
+		g_object_unref (unix_output_stream);
+
+		if (error) {
+			tracker_dbus_request_end (data->request, error);
+			g_dbus_method_invocation_return_gerror (data->invocation, error);
+			g_error_free (error);
+		} else {
+			tracker_dbus_request_end (data->request, NULL);
+			g_dbus_method_invocation_return_value (data->invocation, NULL);
+		}
+	} else {
+		GError *error = NULL;
+
+		g_message ("Controller thread (%p) got error back", g_thread_self ());
+		g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), &error);
+		tracker_dbus_request_end (data->request, error);
+		g_dbus_method_invocation_return_gerror (data->invocation, error);
+		g_error_free (error);
+
+		close (data->fd);
+	}
+
+	metadata_data_free (data);
+}
+
+static void
+handle_method_call_get_metadata_fast (TrackerController	    *controller,
+                                      GDBusMethodInvocation *invocation,
+                                      GVariant		    *parameters)
+{
+	GDBusConnection *connection;
+	GDBusMessage *method_message;
+	TrackerDBusRequest *request;
+
+	connection = g_dbus_method_invocation_get_connection (invocation);
+	method_message = g_dbus_method_invocation_get_message (invocation);
+
+	reset_shutdown_timeout (controller);
+	request = tracker_dbus_request_begin (NULL, "%s", __FUNCTION__);
+
+	if (g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING) {
+		TrackerControllerPrivate *priv;
+		GetMetadataData *data;
+		const gchar *uri, *mime;
+		gint index_fd, fd;
+		GUnixFDList *fd_list;
+		GError *error = NULL;
+
+		priv = controller->priv;
+		g_variant_get (parameters, "(&s&sh)", &uri, &mime, &index_fd);
+
+		fd_list = g_dbus_message_get_unix_fd_list (method_message);
+
+		if ((fd = g_unix_fd_list_get (fd_list, index_fd, &error)) != -1) {
+			data = metadata_data_new (controller, uri, mime, invocation, request);
+			data->fd = fd;
+
+			tracker_extract_file (priv->extractor, uri, mime, data->cancellable,
+			                      get_metadata_fast_cb, data);
+		} else {
+			tracker_dbus_request_end (request, error);
+			g_dbus_method_invocation_return_dbus_error (invocation,
+			                                            TRACKER_EXTRACT_SERVICE ".GetMetadataFastError",
+			                                            "No FD list");
+			g_error_free (error);
+		}
+	} else {
+		tracker_dbus_request_end (request, NULL);
+		g_dbus_method_invocation_return_dbus_error (invocation,
+		                                            TRACKER_EXTRACT_SERVICE ".GetMetadataFastError",
+		                                            "No FD passing capabilities");
+	}
+}
+
+static void
+handle_method_call (GDBusConnection	  *connection,
+		    const gchar		  *sender,
+		    const gchar		  *object_path,
+		    const gchar		  *interface_name,
+		    const gchar		  *method_name,
+		    GVariant		  *parameters,
+		    GDBusMethodInvocation *invocation,
+		    gpointer		   user_data)
+{
+	TrackerController *controller = user_data;
+
+	if (g_strcmp0 (method_name, "GetPid") == 0) {
+		handle_method_call_get_pid (controller, invocation, parameters);
+	} else if (g_strcmp0 (method_name, "GetMetadataFast") == 0) {
+		handle_method_call_get_metadata_fast (controller, invocation, parameters);
+	} else if (g_strcmp0 (method_name, "GetMetadata") == 0) {
+		handle_method_call_get_metadata (controller, invocation, parameters);
+	} else {
+		g_warning ("Unknown method '%s' called", method_name);
+	}
+}
+
+static gboolean
+tracker_controller_dbus_start (TrackerController  *controller,
+			       GError		 **error)
+{
+	TrackerControllerPrivate *priv;
+	GError *err = NULL;
+	GDBusInterfaceVTable interface_vtable = {
+		handle_method_call,
+		NULL, NULL
+	};
+
+	priv = controller->priv;
+	priv->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &err);
+
+	if (!priv->connection) {
+		g_critical ("Could not connect to the D-Bus session bus, %s",
+		            err ? err->message : "no error given.");
+		g_propagate_error (error, err);
+		return FALSE;
+	}
+
+	priv->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, &err);
+	if (!priv->introspection_data) {
+		g_critical ("Could not create node info from introspection XML, %s",
+		            err ? err->message : "no error given.");
+		g_propagate_error (error, err);
+		return FALSE;
+	}
+
+	g_message ("Registering D-Bus object...");
+	g_message ("  Path:'" TRACKER_EXTRACT_PATH "'");
+	g_message ("  Object Type:'%s'", G_OBJECT_TYPE_NAME (controller));
+
+	g_bus_own_name_on_connection (priv->connection,
+	                              TRACKER_EXTRACT_SERVICE,
+	                              G_BUS_NAME_OWNER_FLAGS_NONE,
+	                              NULL, NULL, NULL, NULL);
+
+	priv->registration_id =
+		g_dbus_connection_register_object (priv->connection,
+		                                   TRACKER_EXTRACT_PATH,
+		                                   priv->introspection_data->interfaces[0],
+		                                   &interface_vtable,
+		                                   controller,
+		                                   NULL,
+		                                   &err);
+
+	if (err) {
+		g_critical ("Could not register the D-Bus object "TRACKER_EXTRACT_PATH", %s",
+		            err ? err->message : "no error given.");
+		g_propagate_error (error, err);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void
+tracker_controller_dbus_stop (TrackerController *controller)
+{
+	TrackerControllerPrivate *priv;
+
+	priv = controller->priv;
+
+	if (priv->registration_id != 0) {
+		g_dbus_connection_unregister_object (priv->connection,
+		                                     priv->registration_id);
+	}
+
+	if (priv->introspection_data) {
+		g_dbus_node_info_unref (priv->introspection_data);
+	}
+
+	if (priv->connection) {
+		g_object_unref (priv->connection);
+	}
+}
+
+TrackerController *
+tracker_controller_new (TrackerExtract  *extractor,
+                        guint	         shutdown_timeout,
+			GError         **error)
+{
+	return g_initable_new (TRACKER_TYPE_CONTROLLER,
+	                       NULL, error,
+	                       "extractor", extractor,
+	                       "shutdown-timeout", shutdown_timeout,
+	                       NULL);
+}
+
+static gpointer
+tracker_controller_thread_func (gpointer user_data)
+{
+	TrackerController *controller;
+	TrackerControllerPrivate *priv;
+	gboolean success;
+
+	g_message ("Controller thread '%p' created, dispatching...", g_thread_self ());
+
+	controller = user_data;
+	priv = controller->priv;
+	g_main_context_push_thread_default (priv->context);
+
+	reset_shutdown_timeout (controller);
+
+	success = tracker_controller_dbus_start (controller, &priv->initialization_error);
+	priv->initialized = TRUE;
+
+	/* Notify about the initialization */
+	g_mutex_lock (priv->initialization_mutex);
+	g_cond_signal (priv->initialization_cond);
+	g_mutex_unlock (priv->initialization_mutex);
+
+	if (!success) {
+		/* Return here, the main thread will
+		 * be notified about the error and exit
+		 */
+		return NULL;
+	}
+
+	g_main_loop_run (priv->main_loop);
+
+	g_message ("Shutting down...");
+
+	g_object_unref (controller);
+
+	/* This is where tracker-extract exits, be it
+	 * either through umount events on monitored
+	 * files' volumes or the timeout being reached
+	 */
+	exit (0);
+	return NULL;
+}
+
+gboolean
+tracker_controller_start (TrackerController  *controller,
+                          GError            **error)
+{
+	TrackerControllerPrivate *priv;
+
+	if (!g_thread_create (tracker_controller_thread_func,
+	                      controller, FALSE, error)) {
+		return FALSE;
+	}
+
+	priv = controller->priv;
+
+	g_message ("Waiting for controller thread to initialize...");
+
+	/* Wait for the controller thread to notify initialization */
+	g_mutex_lock (priv->initialization_mutex);
+
+	while (!priv->initialized) {
+		g_cond_wait (priv->initialization_cond, priv->initialization_mutex);
+	}
+
+	g_mutex_unlock (priv->initialization_mutex);
+
+	/* If there was any error resulting from initialization, propagate it */
+	if (priv->initialization_error != NULL) {
+		g_propagate_error (error, priv->initialization_error);
+		return FALSE;
+	}
+
+	g_message ("Controller thread initialized");
+
+	return TRUE;
+}
diff --git a/src/tracker-extract/tracker-controller.h b/src/tracker-extract/tracker-controller.h
new file mode 100644
index 0000000..67ef5d5
--- /dev/null
+++ b/src/tracker-extract/tracker-controller.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011, Nokia <ivan frade nokia com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __TRACKER_CONTROLLER_H__
+#define __TRACKER_CONTROLLER_H__
+
+#include "tracker-extract.h"
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define TRACKER_TYPE_CONTROLLER         (tracker_controller_get_type ())
+#define TRACKER_CONTROLLER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), TRACKER_TYPE_CONTROLLER, TrackerController))
+#define TRACKER_CONTROLLER_CLASS(c)     (G_TYPE_CHECK_CLASS_CAST ((c), TRACKER_TYPE_CONTROLLER, TrackerControllerClass))
+#define TRACKER_IS_CONTROLLER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), TRACKER_TYPE_CONTROLLER))
+#define TRACKER_IS_CONTROLLER_CLASS(c)  (G_TYPE_CHECK_CLASS_TYPE ((c), TRACKER_TYPE_CONTROLLER))
+#define TRACKER_CONTROLLER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TRACKER_TYPE_CONTROLLER, TrackerControllerClass))
+
+typedef struct TrackerController TrackerController;
+typedef struct TrackerControllerClass TrackerControllerClass;
+
+struct TrackerController {
+        GObject parent_instance;
+        gpointer priv;
+};
+
+struct TrackerControllerClass {
+        GObjectClass parent_class;
+};
+
+GType               tracker_controller_get_type (void) G_GNUC_CONST;
+
+TrackerController * tracker_controller_new   (TrackerExtract     *extractor,
+                                              guint               shutdown_timeout,
+                                              GError            **error);
+gboolean            tracker_controller_start (TrackerController  *controller,
+                                              GError            **error);
+
+G_END_DECLS
+
+#endif /* __TRACKER_CONTROLLER_H__ */
diff --git a/src/tracker-extract/tracker-extract.c b/src/tracker-extract/tracker-extract.c
index 67b705e..66aa320 100644
--- a/src/tracker-extract/tracker-extract.c
+++ b/src/tracker-extract/tracker-extract.c
@@ -82,13 +82,18 @@ typedef struct {
 	gboolean disable_shutdown;
 	gboolean force_internal_extractors;
 	gboolean disable_summary_on_finalize;
-	GDBusConnection *d_connection;
-	GDBusNodeInfo *introspection_data;
-	guint registration_id;
 
 	gint unhandled_count;
 } TrackerExtractPrivate;
 
+typedef struct {
+	TrackerExtract *extract;
+	GCancellable *cancellable;
+	GAsyncResult *res;
+	gchar *file;
+	gchar *mimetype;
+} TrackerExtractTask;
+
 static void tracker_extract_finalize (GObject *object);
 static void report_statistics        (GObject *object);
 
@@ -205,8 +210,6 @@ tracker_extract_new (gboolean     disable_shutdown,
 
 static gboolean
 get_file_metadata (TrackerExtract         *extract,
-                   TrackerDBusRequest     *request,
-                   GDBusMethodInvocation  *invocation,
                    const gchar            *uri,
                    const gchar            *mime,
                    TrackerSparqlBuilder  **preupdate_out,
@@ -288,9 +291,7 @@ get_file_metadata (TrackerExtract         *extract,
 		                          &error);
 
 		if (error || !info) {
-			tracker_dbus_request_comment (request,
-			                              "  Could not create GFileInfo for file size check, %s",
-			                              error ? error->message : "no error given");
+			/* FIXME: Propagate error */
 			g_error_free (error);
 
 			if (info) {
@@ -307,11 +308,6 @@ get_file_metadata (TrackerExtract         *extract,
 
 		mime_used = g_strdup (g_file_info_get_content_type (info));
 
-		tracker_dbus_request_comment (request,
-		                              "  Guessing mime type as '%s' for uri:'%s'",
-		                              mime_used,
-		                              uri);
-
 		g_object_unref (info);
 		g_object_unref (file);
 	}
@@ -333,10 +329,6 @@ get_file_metadata (TrackerExtract         *extract,
 
 			items = tracker_sparql_builder_get_length (statements);
 
-			tracker_dbus_request_comment (request,
-			                              "  Found %d metadata items",
-			                              items);
-
 			data = g_hash_table_lookup (priv->statistics_data, module);
 
 			if (!data) {
@@ -360,14 +352,6 @@ get_file_metadata (TrackerExtract         *extract,
 		} else {
 			priv->unhandled_count++;
 		}
-
-		tracker_dbus_request_comment (request,
-		                              "  Could not find any extractors to handle metadata type "
-		                              "(mime: %s)",
-		                              mime_used);
-	} else {
-		tracker_dbus_request_comment (request,
-		                              "  No mime available, not extracting data");
 	}
 
 	if (tracker_sparql_builder_get_length (statements) > 0) {
@@ -378,474 +362,156 @@ get_file_metadata (TrackerExtract         *extract,
 	*statements_out = statements;
 	*where_out = g_string_free (where, FALSE);
 
-	return TRUE;
+	return FALSE;
 }
 
-void
-tracker_extract_get_metadata_by_cmdline (TrackerExtract *object,
-                                         const gchar    *uri,
-                                         const gchar    *mime)
+static void
+tracker_extract_info_free (TrackerExtractInfo *info)
 {
-	TrackerDBusRequest *request;
-	TrackerSparqlBuilder *statements, *preupdate;
-	gchar *where;
-	TrackerExtractPrivate *priv;
-
-	priv = TRACKER_EXTRACT_GET_PRIVATE (object);
-	priv->disable_summary_on_finalize = TRUE;
-
-	g_return_if_fail (uri != NULL);
-
-	request = tracker_dbus_request_begin (NULL,
-	                                      "%s(uri:'%s', mime:%s)",
-	                                      __FUNCTION__,
-	                                      uri,
-	                                      mime);
-
-	/* NOTE: Don't reset the timeout to shutdown here */
-
-	if (get_file_metadata (object, request,
-			       NULL, uri, mime,
-			       &preupdate, &statements, &where)) {
-		const gchar *preupdate_str, *statements_str;
-
-		preupdate_str = statements_str = NULL;
-
-		if (tracker_sparql_builder_get_length (statements) > 0) {
-			statements_str = tracker_sparql_builder_get_result (statements);
-		}
-
-		if (tracker_sparql_builder_get_length (preupdate) > 0) {
-			preupdate_str = tracker_sparql_builder_get_result (preupdate);
-		}
-
-		tracker_dbus_request_info (request, "%s",
-		                           preupdate_str ? preupdate_str : "");
-		tracker_dbus_request_info (request, "%s",
-		                           statements_str ? statements_str : "");
-		tracker_dbus_request_info (request, "%s",
-		                           where ? where : "");
+	if (info->statements) {
+		g_object_unref (info->statements);
+	}
 
-		g_object_unref (statements);
-		g_object_unref (preupdate);
-		g_free (where);
+	if (info->preupdate) {
+		g_object_unref (info->preupdate);
 	}
 
-	tracker_dbus_request_end (request, NULL);
+	g_free (info->where);
+	g_slice_free (TrackerExtractInfo, info);
 }
 
-static void
-handle_method_call_get_pid (TrackerExtract        *object,
-                            GDBusMethodInvocation *invocation,
-                            GVariant              *parameters)
+static TrackerExtractTask *
+extract_task_new (TrackerExtract *extract,
+                  const gchar    *file,
+                  const gchar    *mimetype,
+                  GCancellable   *cancellable,
+                  GAsyncResult   *res)
 {
-	TrackerDBusRequest *request;
-	pid_t value;
-
-	request = tracker_g_dbus_request_begin (invocation,
-	                                        "%s()",
-	                                        __FUNCTION__);
+	TrackerExtractTask *task;
 
-	value = getpid ();
-	tracker_dbus_request_debug (request,
-	                            "PID is %d",
-	                            value);
+	task = g_slice_new0 (TrackerExtractTask);
+	task->cancellable = cancellable;
+	task->res = g_object_ref (res);
+	task->file = g_strdup (file);
+	task->mimetype = g_strdup (mimetype);
+	task->extract = extract;
 
-	tracker_dbus_request_end (request, NULL);
-
-	g_dbus_method_invocation_return_value (invocation,
-	                                       g_variant_new ("(i)", (gint) value));
+	return task;
 }
 
 static void
-handle_method_call_get_metadata (TrackerExtract        *object,
-                                 GDBusMethodInvocation *invocation,
-                                 GVariant              *parameters)
+extract_task_free (TrackerExtractTask *task)
 {
-	TrackerDBusRequest *request;
-	TrackerExtractPrivate *priv;
-	TrackerSparqlBuilder *sparql, *preupdate;
-	gchar *where;
-	gboolean extracted = FALSE;
-	const gchar *uri = NULL, *mime = NULL;
-
-	g_variant_get (parameters, "(&s&s)", &uri, &mime);
-
-	tracker_gdbus_async_return_if_fail (uri != NULL, invocation);
-
-	request = tracker_g_dbus_request_begin (invocation,
-	                                        "%s(uri:'%s', mime:%s)",
-	                                        __FUNCTION__,
-	                                        uri,
-	                                        mime);
-
-	tracker_dbus_request_debug (request,
-	                            "  Resetting shutdown timeout");
-
-	priv = TRACKER_EXTRACT_GET_PRIVATE (object);
-
-	tracker_main_quit_timeout_reset ();
-	if (!priv->disable_shutdown) {
-		alarm (MAX_EXTRACT_TIME);
-	}
-
-	extracted = get_file_metadata (object,
-	                               request,
-	                               invocation,
-	                               uri,
-	                               mime,
-	                               &preupdate,
-	                               &sparql,
-	                               &where);
-
-	if (extracted) {
-		tracker_dbus_request_end (request, NULL);
-
-		if (tracker_sparql_builder_get_length (sparql) > 0) {
-			const gchar *preupdate_str = NULL;
-
-			if (tracker_sparql_builder_get_length (preupdate) > 0) {
-				preupdate_str = tracker_sparql_builder_get_result (preupdate);
-			}
-
-			g_dbus_method_invocation_return_value (invocation,
-			                                       g_variant_new ("(sss)",
-			                                                      preupdate_str ? preupdate_str : "",
-			                                                      tracker_sparql_builder_get_result (sparql),
-			                                                      where ? where : ""));
-		} else {
-			g_dbus_method_invocation_return_value (invocation,
-			                                       g_variant_new ("(sss)", "", "", ""));
-		}
-
-		g_object_unref (sparql);
-		g_object_unref (preupdate);
-		g_free (where);
-	} else {
-		GError *actual_error;
-
-		actual_error = g_error_new (TRACKER_DBUS_ERROR, 0,
-		                            "Could not get any metadata for uri:'%s' and mime:'%s'",
-		                            uri,
-		                            mime);
-		tracker_dbus_request_end (request, actual_error);
-		g_dbus_method_invocation_return_gerror (invocation, actual_error);
-		g_error_free (actual_error);
-	}
-
-	if (!priv->disable_shutdown) {
-		/* Unset alarm so the extractor doesn't die when it's idle */
-		alarm (0);
-	}
+	g_object_unref (task->res);
+	g_free (task->file);
+	g_free (task->mimetype);
+	g_slice_free (TrackerExtractTask, task);
 }
 
-static void
-handle_method_call_get_metadata_fast (TrackerExtract        *object,
-                                      GDBusMethodInvocation *invocation,
-                                      GVariant              *parameters)
+static gboolean
+get_metadata_cb (gpointer user_data)
 {
-	TrackerDBusRequest *request;
-	TrackerExtractPrivate *priv;
-	GDBusMessage *reply;
-	const gchar *uri, *mime;
-	int fd, index_fd;
-	GOutputStream *unix_output_stream;
-	GOutputStream *buffered_output_stream;
-	GDataOutputStream *data_output_stream;
-	GError *error = NULL;
-	TrackerSparqlBuilder *sparql, *preupdate;
-	gchar *where;
-	gboolean extracted = FALSE;
-	GDBusMessage *method_message;
-	GDBusConnection *connection;
-	GUnixFDList *fd_list;
-
-	connection = g_dbus_method_invocation_get_connection (invocation);
-	method_message = g_dbus_method_invocation_get_message (invocation);
-
-	g_variant_get (parameters, "(&s&sh)", &uri, &mime, &index_fd);
-
-	fd_list = g_dbus_message_get_unix_fd_list (method_message);
-
-	request = tracker_g_dbus_request_begin (invocation,
-	                                        "%s(uri:'%s', mime:%s)",
-	                                        __FUNCTION__,
-	                                        uri,
-	                                        mime);
-
-	if ((fd = g_unix_fd_list_get (fd_list, index_fd, &error)) == -1) {
-		tracker_dbus_request_end (request, error);
-		reply = g_dbus_message_new_method_error_literal (method_message,
-		                                                 TRACKER_EXTRACT_SERVICE ".GetMetadataFastError",
-		                                                 error->message);
-		g_error_free (error);
-		goto bail_out;
+	TrackerExtractTask *task = user_data;
+	TrackerExtractInfo *info;
+
+	g_message ("Main thread (%p) got file to get metadata from: %s", g_thread_self (), task->file);
+
+	if (task->cancellable &&
+	    g_cancellable_is_cancelled (task->cancellable)) {
+		g_simple_async_result_set_error ((GSimpleAsyncResult *) task->res,
+		                                 TRACKER_DBUS_ERROR, 0,
+		                                 "Extraction of '%s' was cancelled",
+		                                 task->file);
+		extract_task_free (task);
+		return FALSE;
 	}
 
-	tracker_dbus_request_debug (request,
-	                            "  Resetting shutdown timeout");
-
-	priv = TRACKER_EXTRACT_GET_PRIVATE (object);
+	info = g_slice_new (TrackerExtractInfo);
 
-	tracker_main_quit_timeout_reset ();
-	if (!priv->disable_shutdown) {
-		alarm (MAX_EXTRACT_TIME);
-	}
-
-	extracted = get_file_metadata (object, request, NULL, uri, mime, &preupdate, &sparql, &where);
-
-	if (extracted) {
-		unix_output_stream = g_unix_output_stream_new (fd, TRUE);
-		buffered_output_stream = g_buffered_output_stream_new_sized (unix_output_stream,
-		                                                             64*1024);
-		data_output_stream = g_data_output_stream_new (buffered_output_stream);
-		g_data_output_stream_set_byte_order (G_DATA_OUTPUT_STREAM (data_output_stream),
-		                                     G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN);
-
-		if (tracker_sparql_builder_get_length (sparql) > 0) {
-			const gchar *preupdate_str = NULL;
-
-			if (tracker_sparql_builder_get_length (preupdate) > 0) {
-				preupdate_str = tracker_sparql_builder_get_result (preupdate);
-			}
-
-			g_data_output_stream_put_string (data_output_stream,
-			                                 preupdate_str ? preupdate_str : "",
-			                                 NULL,
-			                                 &error);
-
-			if (!error) {
-				g_data_output_stream_put_byte (data_output_stream,
-				                               0,
-				                               NULL,
-				                               &error);
-			}
-
-			if (!error) {
-				g_data_output_stream_put_string (data_output_stream,
-				                                 tracker_sparql_builder_get_result (sparql),
-				                                 NULL,
-				                                 &error);
-			}
-
-			if (!error) {
-				g_data_output_stream_put_byte (data_output_stream,
-				                               0,
-				                               NULL,
-				                               &error);
-			}
-
-			if (!error && where) {
-				g_data_output_stream_put_string (data_output_stream,
-				                                 where,
-				                                 NULL,
-				                                 &error);
-			}
-
-			if (!error) {
-				g_data_output_stream_put_byte (data_output_stream,
-				                               0,
-				                               NULL,
-				                               &error);
-			}
-		}
-
-		g_object_unref (sparql);
-		g_object_unref (preupdate);
-		g_free (where);
-		g_object_unref (data_output_stream);
-		g_object_unref (buffered_output_stream);
-		g_object_unref (unix_output_stream);
-
-		if (error) {
-			tracker_dbus_request_end (request, error);
-			reply = g_dbus_message_new_method_error_literal (method_message,
-			                                                 TRACKER_EXTRACT_SERVICE ".GetMetadataFastError",
-			                                                 error->message);
-			g_error_free (error);
-		} else {
-			tracker_dbus_request_end (request, NULL);
-			reply = g_dbus_message_new_method_reply (method_message);
-		}
+	if (get_file_metadata (task->extract,
+	                       task->file, task->mimetype,
+	                       &info->preupdate,
+	                       &info->statements,
+	                       &info->where)) {
+		g_simple_async_result_set_op_res_gpointer ((GSimpleAsyncResult *) task->res, info,
+		                                           (GDestroyNotify) tracker_extract_info_free);
 	} else {
-		error = g_error_new (TRACKER_DBUS_ERROR, 0,
-		                     "Could not get any metadata for uri:'%s' and mime:'%s'", uri, mime);
-		tracker_dbus_request_end (request, error);
-		reply = g_dbus_message_new_method_error_literal (method_message,
-		                                                 TRACKER_EXTRACT_SERVICE ".GetMetadataFastError",
-		                                                 error->message);
-		g_error_free (error);
-		close (fd);
+		g_simple_async_result_set_error ((GSimpleAsyncResult *) task->res,
+		                                 TRACKER_DBUS_ERROR, 0,
+		                                 "Could not get any metadata for uri:'%s' and mime:'%s'",
+		                                 task->file, task->mimetype);
+		tracker_extract_info_free (info);
 	}
 
-bail_out:
-
-	g_dbus_connection_send_message (connection, reply,
-	                                G_DBUS_SEND_MESSAGE_FLAGS_NONE,
-	                                NULL, NULL);
+	g_simple_async_result_complete_in_idle ((GSimpleAsyncResult *) task->res);
+	extract_task_free (task);
 
-	g_object_unref (fd_list);
-	g_object_unref (reply);
-
-	/* We are replying ourselves to the
-	 * message, so just unref the invocation
-	 */
-	g_object_unref (invocation);
-
-	if (!priv->disable_shutdown) {
-		/* Unset alarm so the extractor doesn't die when it's idle */
-		alarm (0);
-	}
+	return FALSE;
 }
 
-static void
-handle_method_call (GDBusConnection       *connection,
-                    const gchar           *sender,
-                    const gchar           *object_path,
-                    const gchar           *interface_name,
-                    const gchar           *method_name,
-                    GVariant              *parameters,
-                    GDBusMethodInvocation *invocation,
-                    gpointer               user_data)
+/* This function can be called in any thread */
+void
+tracker_extract_file (TrackerExtract      *extract,
+                      const gchar         *file,
+                      const gchar         *mimetype,
+                      GCancellable        *cancellable,
+                      GAsyncReadyCallback  cb,
+                      gpointer             user_data)
 {
-	TrackerExtract *extract = user_data;
-
-	if (g_strcmp0 (method_name, "GetPid") == 0) {
-		handle_method_call_get_pid (extract, invocation, parameters);
-	} else
-	if (g_strcmp0 (method_name, "GetMetadataFast") == 0) {
-		handle_method_call_get_metadata_fast (extract, invocation, parameters);
-	} else
-	if (g_strcmp0 (method_name, "GetMetadata") == 0) {
-		handle_method_call_get_metadata (extract, invocation, parameters);
-	} else {
-		g_assert_not_reached ();
-	}
-}
+	GSimpleAsyncResult *res;
+	TrackerExtractTask *task;
 
-static GVariant *
-handle_get_property (GDBusConnection  *connection,
-                     const gchar      *sender,
-                     const gchar      *object_path,
-                     const gchar      *interface_name,
-                     const gchar      *property_name,
-                     GError          **error,
-                     gpointer          user_data)
-{
-	g_assert_not_reached ();
-	return NULL;
-}
+	g_return_if_fail (TRACKER_IS_EXTRACT (extract));
+	g_return_if_fail (file != NULL);
+	g_return_if_fail (cb != NULL);
 
-static gboolean
-handle_set_property (GDBusConnection  *connection,
-                     const gchar      *sender,
-                     const gchar      *object_path,
-                     const gchar      *interface_name,
-                     const gchar      *property_name,
-                     GVariant         *value,
-                     GError          **error,
-                     gpointer          user_data)
-{
-	g_assert_not_reached ();
-	return TRUE;
+	g_message ("Extract file on thread %p\n", g_thread_self ());
+	res = g_simple_async_result_new (G_OBJECT (extract), cb, user_data, NULL);
+
+	task = extract_task_new (extract, file, mimetype, cancellable,
+	                         G_ASYNC_RESULT (res));
+	g_idle_add (get_metadata_cb, task);
+
+	/* task takes a ref */
+	g_object_unref (res);
 }
 
 void
-tracker_extract_dbus_start (TrackerExtract *extract)
+tracker_extract_get_metadata_by_cmdline (TrackerExtract *object,
+                                         const gchar    *uri,
+                                         const gchar    *mime)
 {
+	TrackerSparqlBuilder *statements, *preupdate;
+	gchar *where;
 	TrackerExtractPrivate *priv;
-	GVariant *reply;
-	guint32 rval;
-	GError *error = NULL;
-	GDBusInterfaceVTable interface_vtable = {
-		handle_method_call,
-		handle_get_property,
-		handle_set_property
-	};
-
-	priv = TRACKER_EXTRACT_GET_PRIVATE (extract);
-
-	priv->d_connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
-	if (!priv->d_connection) {
-		g_critical ("Could not connect to the D-Bus session bus, %s",
-		            error ? error->message : "no error given.");
-		g_clear_error (&error);
-		return;
-	}
 
-	priv->introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, &error);
-	if (!priv->introspection_data) {
-		g_critical ("Could not create node info from introspection XML, %s",
-		            error ? error->message : "no error given.");
-		g_clear_error (&error);
-		return;
-	}
-
-	g_message ("Registering D-Bus object...");
-	g_message ("  Path:'" TRACKER_EXTRACT_PATH "'");
-	g_message ("  Object Type:'%s'", G_OBJECT_TYPE_NAME (extract));
-
-	priv->registration_id =
-		g_dbus_connection_register_object (priv->d_connection,
-		                                   TRACKER_EXTRACT_PATH,
-		                                   priv->introspection_data->interfaces[0],
-		                                   &interface_vtable,
-		                                   extract,
-		                                   NULL,
-		                                   &error);
-
-	if (error) {
-		g_critical ("Could not register the D-Bus object "TRACKER_EXTRACT_PATH", %s",
-		            error ? error->message : "no error given.");
-		g_clear_error (&error);
-		return;
-	}
-
-	reply = g_dbus_connection_call_sync (priv->d_connection,
-	                                     "org.freedesktop.DBus",
-	                                     "/org/freedesktop/DBus",
-	                                     "org.freedesktop.DBus",
-	                                     "RequestName",
-	                                     g_variant_new ("(su)", TRACKER_EXTRACT_SERVICE, 0x4 /* DBUS_NAME_FLAG_DO_NOT_QUEUE */),
-	                                     G_VARIANT_TYPE ("(u)"),
-	                                     0, -1, NULL, &error);
-
-	if (error) {
-		g_critical ("Could not acquire name:'%s', %s",
-		            TRACKER_EXTRACT_SERVICE,
-		            error->message);
-		g_clear_error (&error);
-		return;
-	}
+	priv = TRACKER_EXTRACT_GET_PRIVATE (object);
+	priv->disable_summary_on_finalize = TRUE;
 
-	g_variant_get (reply, "(u)", &rval);
-	g_variant_unref (reply);
+	g_return_if_fail (uri != NULL);
 
-	if (rval != 1 /* DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER */) {
-		g_critical ("D-Bus service name:'%s' is already taken, "
-		            "perhaps the application is already running?",
-		            TRACKER_EXTRACT_SERVICE);
-		return;
-	}
-}
+	if (get_file_metadata (object, uri, mime,
+			       &preupdate, &statements, &where)) {
+		const gchar *preupdate_str, *statements_str;
 
-void
-tracker_extract_dbus_stop (TrackerExtract *extract)
-{
-	TrackerExtractPrivate *priv;
+		preupdate_str = statements_str = NULL;
 
-	priv = TRACKER_EXTRACT_GET_PRIVATE (extract);
+		if (tracker_sparql_builder_get_length (statements) > 0) {
+			statements_str = tracker_sparql_builder_get_result (statements);
+		}
 
-	if (priv->registration_id != 0) {
-		g_dbus_connection_unregister_object (priv->d_connection,
-		                                     priv->registration_id);
-	}
+		if (tracker_sparql_builder_get_length (preupdate) > 0) {
+			preupdate_str = tracker_sparql_builder_get_result (preupdate);
+		}
 
-	if (priv->introspection_data) {
-		g_dbus_node_info_unref (priv->introspection_data);
-	}
+		g_print ("Preupdate SPARQL:\n%s\n",
+		         preupdate_str ? preupdate_str : "");
+		g_print ("Item SPARQL:\n%s\n",
+		         statements_str ? statements_str : "");
+		g_print ("Where clause: %s\n", where ? where : "");
 
-	if (priv->d_connection) {
-		g_object_unref (priv->d_connection);
+		g_object_unref (statements);
+		g_object_unref (preupdate);
+		g_free (where);
 	}
 }
diff --git a/src/tracker-extract/tracker-extract.h b/src/tracker-extract/tracker-extract.h
index 9cc0132..77c3680 100644
--- a/src/tracker-extract/tracker-extract.h
+++ b/src/tracker-extract/tracker-extract.h
@@ -20,7 +20,9 @@
 #ifndef __TRACKERD_EXTRACT_H__
 #define __TRACKERD_EXTRACT_H__
 
-#include <glib-object.h>
+#include <gio/gio.h>
+#include <libtracker-common/tracker-common.h>
+#include <libtracker-extract/tracker-extract.h>
 
 #define TRACKER_EXTRACT_SERVICE        "org.freedesktop.Tracker1.Extract"
 #define TRACKER_EXTRACT_PATH           "/org/freedesktop/Tracker1/Extract"
@@ -37,6 +39,7 @@ G_BEGIN_DECLS
 
 typedef struct TrackerExtract      TrackerExtract;
 typedef struct TrackerExtractClass TrackerExtractClass;
+typedef struct TrackerExtractInfo  TrackerExtractInfo;
 
 struct TrackerExtract {
 	GObject parent;
@@ -46,11 +49,24 @@ struct TrackerExtractClass {
 	GObjectClass parent;
 };
 
+struct TrackerExtractInfo {
+	TrackerSparqlBuilder *preupdate;
+	TrackerSparqlBuilder *statements;
+	gchar *where;
+};
+
 GType           tracker_extract_get_type                (void);
 TrackerExtract *tracker_extract_new                     (gboolean                disable_shutdown,
                                                          gboolean                force_internal_extractors,
                                                          const gchar            *force_module);
 
+void            tracker_extract_file                    (TrackerExtract         *extract,
+                                                         const gchar            *file,
+                                                         const gchar            *mimetype,
+                                                         GCancellable           *cancellable,
+                                                         GAsyncReadyCallback     cb,
+                                                         gpointer                user_data);
+
 void            tracker_extract_dbus_start              (TrackerExtract         *extract);
 void            tracker_extract_dbus_stop               (TrackerExtract         *extract);
 
diff --git a/src/tracker-extract/tracker-main.c b/src/tracker-extract/tracker-main.c
index 6c23309..e0adfc0 100644
--- a/src/tracker-extract/tracker-main.c
+++ b/src/tracker-extract/tracker-main.c
@@ -52,6 +52,7 @@
 #include "tracker-config.h"
 #include "tracker-main.h"
 #include "tracker-extract.h"
+#include "tracker-controller.h"
 
 #define ABOUT	  \
 	"Tracker " PACKAGE_VERSION "\n"
@@ -66,7 +67,6 @@
 #define QUIT_TIMEOUT 30 /* 1/2 minutes worth of seconds */
 
 static GMainLoop *main_loop;
-static guint quit_timeout_id = 0;
 
 static gint verbosity = -1;
 static gchar *filename;
@@ -113,34 +113,6 @@ static GOptionEntry entries[] = {
 	{ NULL }
 };
 
-static gboolean
-quit_timeout_cb (gpointer user_data)
-{
-	quit_timeout_id = 0;
-
-	if (!disable_shutdown) {
-		if (main_loop) {
-			g_main_loop_quit (main_loop);
-		}
-	} else {
-		g_debug ("Would have quit the mainloop");
-	}
-
-	return FALSE;
-}
-
-void
-tracker_main_quit_timeout_reset (void)
-{
-	if (quit_timeout_id != 0) {
-		g_source_remove (quit_timeout_id);
-	}
-
-	quit_timeout_id = g_timeout_add_seconds (QUIT_TIMEOUT,
-	                                         quit_timeout_cb,
-	                                         NULL);
-}
-
 static void
 initialize_priority (void)
 {
@@ -202,7 +174,8 @@ signal_handler (int signo)
 	case SIGINT:
 		in_loop = TRUE;
 		disable_shutdown = FALSE;
-		quit_timeout_cb (NULL);
+		g_main_loop_quit (main_loop);
+
 		/* Fall through */
 	default:
 		if (g_strsignal (signo)) {
@@ -319,8 +292,10 @@ main (int argc, char *argv[])
 	GOptionContext *context;
 	GError         *error = NULL;
 	TrackerExtract *object;
+        TrackerController *controller;
 	gchar          *log_filename = NULL;
 	GMainLoop      *my_main_loop;
+        guint           shutdown_timeout;
 
 	bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
 	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
@@ -371,7 +346,7 @@ main (int argc, char *argv[])
 	g_print ("Initializing tracker-extract...\n");
 
 	if (!filename) {
-		g_print ("  Shutdown after 30 seconds of inactivitiy is %s\n",
+		g_print ("  Shutdown after 30 seconds of inactivity is %s\n",
 		         disable_shutdown ? "disabled" : "enabled");
 	}
 
@@ -379,10 +354,6 @@ main (int argc, char *argv[])
 
 	g_type_init ();
 
-	if (!g_thread_supported ()) {
-		g_thread_init (NULL);
-	}
-
 	g_set_application_name ("tracker-extract");
 
 	setlocale (LC_ALL, "");
@@ -408,6 +379,13 @@ main (int argc, char *argv[])
 
 	/* This makes sure we don't steal all the system's resources */
 	initialize_priority ();
+	tracker_memory_setrlimits ();
+
+        if (disable_shutdown) {
+                shutdown_timeout = 0;
+        } else {
+                shutdown_timeout = QUIT_TIMEOUT;
+        }
 
 	object = tracker_extract_new (disable_shutdown,
 	                              force_internal_extractors,
@@ -419,18 +397,26 @@ main (int argc, char *argv[])
 		return EXIT_FAILURE;
 	}
 
-	tracker_memory_setrlimits ();
+	controller = tracker_controller_new (object, shutdown_timeout, &error);
+
+        if (!controller) {
+	        g_critical ("Controller thread failed to initialize: %s\n", error->message);
 
-	tracker_extract_dbus_start (object);
+	        g_error_free (error);
+	        g_object_unref (config);
+		g_object_unref (object);
+		tracker_log_shutdown ();
+
+		return EXIT_FAILURE;
+        }
 
-	g_message ("Waiting for D-Bus requests...");
+	g_message ("Main thread (%p) waiting for extract requests...", g_thread_self ());
 
 	tracker_locale_init ();
 	tracker_albumart_init ();
 
 	/* Main loop */
 	main_loop = g_main_loop_new (NULL, FALSE);
-	tracker_main_quit_timeout_reset ();
 	g_main_loop_run (main_loop);
 
 	my_main_loop = main_loop;
@@ -443,8 +429,8 @@ main (int argc, char *argv[])
 	tracker_albumart_shutdown ();
 	tracker_locale_shutdown ();
 
-	tracker_extract_dbus_stop (object);
 	g_object_unref (object);
+	g_object_unref (controller);
 
 	tracker_log_shutdown ();
 



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