[tracker/tracker-0.10] libtracker-sparql: Fix deadlock on initialization



commit 9da32442c08f1d4f26f60e2ae50a95d8e9fe9580
Author: Jürg Billeter <j bitron ch>
Date:   Wed Mar 16 13:02:34 2011 +0100

    libtracker-sparql: Fix deadlock on initialization
    
    Calling Connection.get_async followed by Connection.get in the same
    thread led to a deadlock. This moves all initialization into a separate
    thread when invoked asynchronously instead of just initializing the
    database in a separate thread.

 .../libtracker-sparql-sections.txt                 |    2 -
 src/libtracker-bus/tracker-bus.vala                |    3 -
 src/libtracker-direct/tracker-direct.vala          |   16 -----
 src/libtracker-sparql/tracker-backend.vala         |   34 +---------
 src/libtracker-sparql/tracker-connection.vala      |   72 +++++++++++---------
 5 files changed, 43 insertions(+), 84 deletions(-)
---
diff --git a/docs/reference/libtracker-sparql/libtracker-sparql-sections.txt b/docs/reference/libtracker-sparql/libtracker-sparql-sections.txt
index 27d4cf5..daf848d 100644
--- a/docs/reference/libtracker-sparql/libtracker-sparql-sections.txt
+++ b/docs/reference/libtracker-sparql/libtracker-sparql-sections.txt
@@ -118,8 +118,6 @@ TrackerSparqlConnectionPrivate
 tracker_sparql_error_quark
 tracker_sparql_connection_construct
 tracker_sparql_connection_init
-tracker_sparql_connection_init_async
-tracker_sparql_connection_init_finish
 </SECTION>
 
 
diff --git a/src/libtracker-bus/tracker-bus.vala b/src/libtracker-bus/tracker-bus.vala
index 4e43bcb..c46fe2d 100644
--- a/src/libtracker-bus/tracker-bus.vala
+++ b/src/libtracker-bus/tracker-bus.vala
@@ -92,9 +92,6 @@ public class Tracker.Bus.Connection : Tracker.Sparql.Connection {
 	public override void init () throws Sparql.Error, IOError, DBusError {
 	}
 
-	public async override void init_async () throws Sparql.Error, IOError, DBusError {
-	}
-
 	~Connection () {
 		initialized = false;
 	}
diff --git a/src/libtracker-direct/tracker-direct.vala b/src/libtracker-direct/tracker-direct.vala
index 4d11e40..d19a3f9 100644
--- a/src/libtracker-direct/tracker-direct.vala
+++ b/src/libtracker-direct/tracker-direct.vala
@@ -42,22 +42,6 @@ public class Tracker.Direct.Connection : Tracker.Sparql.Connection {
 		initialized = true;
 	}
 
-	public async override void init_async () throws Sparql.Error, IOError, DBusError {
-		uint select_cache_size = 100;
-		string env_cache_size = Environment.get_variable ("TRACKER_SPARQL_CACHE_SIZE");
-
-		if (env_cache_size != null) {
-			select_cache_size = env_cache_size.to_int();
-		}
-
-		try {
-			yield Data.Manager.init_async (DBManagerFlags.READONLY, null, false, select_cache_size, 0, null, null);
-		} catch (DBInterfaceError e) {
-			throw new Sparql.Error.INTERNAL (e.message);
-		}
-		initialized = true;
-	}
-
 	~Connection () {
 		// Clean up connection
 		if (initialized) {
diff --git a/src/libtracker-sparql/tracker-backend.vala b/src/libtracker-sparql/tracker-backend.vala
index 758fbb5..6a20714 100644
--- a/src/libtracker-sparql/tracker-backend.vala
+++ b/src/libtracker-sparql/tracker-backend.vala
@@ -20,8 +20,6 @@
 [DBus (name = "org.freedesktop.Tracker1.Status")]
 interface Tracker.Backend.Status : DBusProxy {
 	public abstract void wait () throws DBusError;
-	[DBus (name = "Wait")]
-	public abstract async void wait_async () throws DBusError;
 }
 
 class Tracker.Sparql.Backend : Connection {
@@ -51,14 +49,14 @@ class Tracker.Sparql.Backend : Connection {
 		status.set_default_timeout (int.MAX);
 
 		// Makes sure the sevice is available
-		debug ("Waiting for service to become available synchronously...");
+		debug ("Waiting for service to become available...");
 		status.wait ();
 		debug ("Service is ready");
 
 		try {
 			debug ("Constructing connection, direct_only=%s", direct_only ? "true" : "false");
 			if (load_plugins (direct_only)) {
-				debug ("Waiting for backend to become available synchronously...");
+				debug ("Waiting for backend to become available...");
 				if (direct != null) {
 					direct.init ();
 				} else {
@@ -71,34 +69,6 @@ class Tracker.Sparql.Backend : Connection {
 		}
 	}
 
-	public async override void init_async () throws Sparql.Error, IOError, DBusError {
-		Tracker.Backend.Status status = Bus.get_proxy_sync (BusType.SESSION,
-		                                                    TRACKER_DBUS_SERVICE,
-		                                                    TRACKER_DBUS_OBJECT_STATUS,
-		                                                    DBusProxyFlags.DO_NOT_LOAD_PROPERTIES | DBusProxyFlags.DO_NOT_CONNECT_SIGNALS);
-		status.set_default_timeout (int.MAX);
-
-		// Makes sure the sevice is available
-		debug ("Waiting for service to become available asynchronously...");
-		yield status.wait_async ();
-		debug ("Service is ready");
-
-		try {
-			debug ("Constructing connection, direct_only=%s", direct_only ? "true" : "false");
-			if (load_plugins (direct_only)) {
-				debug ("Waiting for backend to become available asynchronously...");
-				if (direct != null) {
-					yield direct.init_async ();
-				} else {
-					yield bus.init_async ();
-				}
-				debug ("Backend is ready");
-			}
-		} catch (GLib.Error e) {
-			throw new Sparql.Error.INTERNAL (e.message);
-		}
-	}
-
 	public override Cursor query (string sparql, Cancellable? cancellable = null) throws Sparql.Error, IOError, DBusError
 	requires (bus != null || direct != null) {
 		debug ("%s(): '%s'", Log.METHOD, sparql);
diff --git a/src/libtracker-sparql/tracker-connection.vala b/src/libtracker-sparql/tracker-connection.vala
index 64b6aec..f1a2a32 100644
--- a/src/libtracker-sparql/tracker-connection.vala
+++ b/src/libtracker-sparql/tracker-connection.vala
@@ -117,34 +117,52 @@ public abstract class Tracker.Sparql.Connection : Object {
 	}
 
 	private async static new Connection get_internal_async (bool is_direct_only = false, Cancellable? cancellable = null) throws Sparql.Error, IOError, DBusError {
-		door.lock ();
+		// fast path: avoid extra thread if connection is already available
+		if (door.trylock ()) {
+			// assign to owned variable to ensure it doesn't get freed between unlock and return
+			var result = singleton;
 
-		// assign to owned variable to ensure it doesn't get freed between unlock and return
-		var result = singleton;
-		if (result != null) {
-			assert (direct_only == is_direct_only);
 			door.unlock ();
-			return result;
-		}
 
-		log_init ();
-
-		/* the True is to assert that direct only is required */
-		result = new Backend (is_direct_only);
-		yield result.init_async ();
-
-		if (cancellable != null && cancellable.is_cancelled ()) {
-			door.unlock ();
-			throw new IOError.CANCELLED ("Operation was cancelled");
+			if (result != null) {
+				assert (direct_only == is_direct_only);
+				return result;
+			}
 		}
 
-		direct_only = is_direct_only;
-		singleton = result;
-		result.add_weak_pointer ((void**) (&singleton));
-
-		door.unlock ();
-
-		return singleton;
+		// run in a separate thread
+		Sparql.Error sparql_error = null;
+		IOError io_error = null;
+		DBusError dbus_error = null;
+		Connection result = null;
+
+		g_io_scheduler_push_job (job => {
+			try {
+				result = get_internal (is_direct_only, cancellable);
+			} catch (IOError e_io) {
+				io_error = e_io;
+			} catch (Sparql.Error e_spql) {
+				sparql_error = e_spql;
+			} catch (DBusError e_dbus) {
+				dbus_error = e_dbus;
+			}
+			Idle.add (() => {
+				get_internal_async.callback ();
+				return false;
+			});
+			return false;
+		});
+		yield;
+
+		if (sparql_error != null) {
+			throw sparql_error;
+		} else if (io_error != null) {
+			throw io_error;
+		} else if (dbus_error != null) {
+			throw dbus_error;
+		} else {
+			return result;
+		}
 	}
 
 	/**
@@ -203,10 +221,6 @@ public abstract class Tracker.Sparql.Connection : Object {
 	 * these functions, a mutex is used to protect the loading of backends
 	 * against potential race conditions. For synchronous calls, this function
 	 * will always block if a previous connection get method has been called.
-	 * For asynchronous calls, this <emphasis>may</emphasis> block if another
-	 * synchronous or asynchronous call has been previously dispatched and is
-	 * still pending. We don't expect this to be a normal programming model when
-	 * using this API.
 	 *
 	 * All backends will call the D-Bus tracker-store API Wait() to make sure
 	 * the store and databases are in the right state before any user based
@@ -332,10 +346,6 @@ public abstract class Tracker.Sparql.Connection : Object {
 		warning ("Interface 'init' not implemented");
 	}
 
-	public async virtual void init_async () throws Sparql.Error, IOError, DBusError {
-		warning ("Interface 'init_async' not implemented");
-	}
-
 	/**
 	 * tracker_sparql_connection_query:
 	 * @self: a #TrackerSparqlConnection



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