[tracker/tracker-0.10] libtracker-sparql: Fix deadlock on initialization
- From: Martyn James Russell <mr src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker/tracker-0.10] libtracker-sparql: Fix deadlock on initialization
- Date: Thu, 17 Mar 2011 11:25:38 +0000 (UTC)
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]