[tracker] libtracker-direct: Make singleton connection thread-safe
- From: Jürg Billeter <juergbi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker] libtracker-direct: Make singleton connection thread-safe
- Date: Fri, 26 Nov 2010 10:25:36 +0000 (UTC)
commit 6b15fdc0c937c74806df84a0b543a98ddcf95a4b
Author: Jürg Billeter <j bitron ch>
Date: Wed Nov 24 17:23:10 2010 +0100
libtracker-direct: Make singleton connection thread-safe
Fixes NB#203538.
src/libtracker-data/libtracker-data.vapi | 5 ++-
src/libtracker-data/tracker-data-query.c | 2 +-
src/libtracker-data/tracker-db-interface-sqlite.c | 33 +++++++++------
src/libtracker-data/tracker-db-interface.h | 1 +
src/libtracker-data/tracker-db-manager.c | 21 ++++++++++
src/libtracker-data/tracker-db-manager.h | 4 ++
src/libtracker-data/tracker-sparql-query.vala | 18 ++++----
src/libtracker-direct/tracker-direct.vala | 44 ++++++++++++++++++--
8 files changed, 99 insertions(+), 29 deletions(-)
---
diff --git a/src/libtracker-data/libtracker-data.vapi b/src/libtracker-data/libtracker-data.vapi
index 63c2f6b..bb26b5c 100644
--- a/src/libtracker-data/libtracker-data.vapi
+++ b/src/libtracker-data/libtracker-data.vapi
@@ -61,6 +61,9 @@ namespace Tracker {
[CCode (cheader_filename = "libtracker-data/tracker-db-manager.h")]
namespace DBManager {
public unowned DBInterface get_db_interface ();
+ public void lock ();
+ public bool trylock ();
+ public void unlock ();
}
[CCode (cheader_filename = "libtracker-data/tracker-db-interface.h")]
@@ -79,7 +82,7 @@ namespace Tracker {
public abstract void bind_int (int index, int value);
public abstract void bind_text (int index, string value);
public abstract DBResultSet execute () throws DBInterfaceError;
- public abstract DBCursor start_sparql_cursor (PropertyType[] types, string[] variable_names) throws DBInterfaceError;
+ public abstract DBCursor start_sparql_cursor (PropertyType[] types, string[] variable_names, bool threadsafe) throws DBInterfaceError;
}
[CCode (cheader_filename = "libtracker-data/tracker-class.h")]
diff --git a/src/libtracker-data/tracker-data-query.c b/src/libtracker-data/tracker-data-query.c
index 9e5347a..d2161a9 100644
--- a/src/libtracker-data/tracker-data-query.c
+++ b/src/libtracker-data/tracker-data-query.c
@@ -161,7 +161,7 @@ tracker_data_query_sparql_cursor (const gchar *query,
sparql_query = tracker_sparql_query_new (query);
- cursor = tracker_sparql_query_execute_cursor (sparql_query, error);
+ cursor = tracker_sparql_query_execute_cursor (sparql_query, FALSE, error);
g_object_unref (sparql_query);
diff --git a/src/libtracker-data/tracker-db-interface-sqlite.c b/src/libtracker-data/tracker-db-interface-sqlite.c
index de7089f..349fb3b 100644
--- a/src/libtracker-data/tracker-db-interface-sqlite.c
+++ b/src/libtracker-data/tracker-db-interface-sqlite.c
@@ -37,6 +37,7 @@
#include "tracker-collation.h"
#include "tracker-db-interface-sqlite.h"
+#include "tracker-db-manager.h"
#define UNKNOWN_STATUS 0.5
@@ -65,8 +66,6 @@ struct TrackerDBInterface {
#endif
GCancellable *cancellable;
- /* async operation pending */
- gboolean pending;
GAsyncReadyCallback outstanding_callback;
TrackerDBStatementLru select_stmt_lru;
@@ -90,6 +89,8 @@ struct TrackerDBCursor {
gint n_types;
gchar **variable_names;
gint n_variable_names;
+
+ gboolean threadsafe;
};
struct TrackerDBCursorClass {
@@ -117,7 +118,8 @@ static TrackerDBCursor *tracker_db_cursor_sqlite_new (sqlite3_stmt
TrackerPropertyType *types,
gint n_types,
const gchar **variable_names,
- gint n_variable_names);
+ gint n_variable_names,
+ gboolean threadsafe);
static gboolean tracker_db_cursor_get_boolean (TrackerSparqlCursor *cursor,
guint column);
static gboolean db_cursor_iter_next (TrackerDBCursor *cursor,
@@ -895,7 +897,6 @@ tracker_db_interface_create_statement (TrackerDBInterface *db_interfac
gchar *full_query;
g_return_val_if_fail (TRACKER_IS_DB_INTERFACE (db_interface), NULL);
- g_return_val_if_fail (!db_interface->pending, NULL);
va_start (args, query);
full_query = g_strdup_vprintf (query, args);
@@ -1310,7 +1311,6 @@ async_ready_callback_wrapper (GObject *source_object,
TrackerDBCursor *cursor = TRACKER_DB_CURSOR (source_object);
TrackerDBInterface *iface = cursor->ref_stmt->db_interface;
- iface->pending = FALSE;
if (iface->outstanding_callback) {
GAsyncReadyCallback callback = iface->outstanding_callback;
@@ -1328,8 +1328,6 @@ tracker_db_cursor_iter_next_async (TrackerDBCursor *cursor,
{
GSimpleAsyncResult *res;
- g_return_if_fail (!cursor->ref_stmt->db_interface->pending);
- cursor->ref_stmt->db_interface->pending = TRUE;
cursor->ref_stmt->db_interface->outstanding_callback = callback;
res = g_simple_async_result_new (g_object_ref (cursor), async_ready_callback_wrapper, user_data, tracker_db_cursor_iter_next_async);
@@ -1375,7 +1373,8 @@ tracker_db_cursor_sqlite_new (sqlite3_stmt *sqlite_stmt,
TrackerPropertyType *types,
gint n_types,
const gchar **variable_names,
- gint n_variable_names)
+ gint n_variable_names,
+ gboolean threadsafe)
{
TrackerDBCursor *cursor;
@@ -1384,6 +1383,8 @@ tracker_db_cursor_sqlite_new (sqlite3_stmt *sqlite_stmt,
cursor->stmt = sqlite_stmt;
cursor->finished = FALSE;
+ cursor->threadsafe = threadsafe;
+
if (ref_stmt) {
ref_stmt->stmt_is_sunk = TRUE;
cursor->ref_stmt = g_object_ref (ref_stmt);
@@ -1465,7 +1466,6 @@ void
tracker_db_cursor_rewind (TrackerDBCursor *cursor)
{
g_return_if_fail (TRACKER_IS_DB_CURSOR (cursor));
- g_return_if_fail (!cursor->ref_stmt->db_interface->pending);
sqlite3_reset (cursor->stmt);
cursor->finished = FALSE;
@@ -1476,8 +1476,6 @@ tracker_db_cursor_iter_next (TrackerDBCursor *cursor,
GCancellable *cancellable,
GError **error)
{
- g_return_val_if_fail (!cursor->ref_stmt->db_interface->pending, FALSE);
-
return db_cursor_iter_next (cursor, cancellable, error);
}
@@ -1493,6 +1491,10 @@ db_cursor_iter_next (TrackerDBCursor *cursor,
if (!cursor->finished) {
guint result;
+ if (cursor->threadsafe) {
+ tracker_db_manager_lock ();
+ }
+
if (g_cancellable_is_cancelled (cancellable)) {
result = SQLITE_INTERRUPT;
sqlite3_reset (cursor->stmt);
@@ -1517,6 +1519,10 @@ db_cursor_iter_next (TrackerDBCursor *cursor,
}
cursor->finished = (result != SQLITE_ROW);
+
+ if (cursor->threadsafe) {
+ tracker_db_manager_unlock ();
+ }
}
return (!cursor->finished);
@@ -1652,7 +1658,7 @@ tracker_db_statement_start_cursor (TrackerDBStatement *stmt,
{
g_return_val_if_fail (!stmt->stmt_is_sunk, NULL);
- return tracker_db_cursor_sqlite_new (stmt->stmt, stmt, NULL, 0, NULL, 0);
+ return tracker_db_cursor_sqlite_new (stmt->stmt, stmt, NULL, 0, NULL, 0, FALSE);
}
TrackerDBCursor *
@@ -1661,11 +1667,12 @@ tracker_db_statement_start_sparql_cursor (TrackerDBStatement *stmt,
gint n_types,
const gchar **variable_names,
gint n_variable_names,
+ gboolean threadsafe,
GError **error)
{
g_return_val_if_fail (!stmt->stmt_is_sunk, NULL);
- return tracker_db_cursor_sqlite_new (stmt->stmt, stmt, types, n_types, variable_names, n_variable_names);
+ return tracker_db_cursor_sqlite_new (stmt->stmt, stmt, types, n_types, variable_names, n_variable_names, threadsafe);
}
static void
diff --git a/src/libtracker-data/tracker-db-interface.h b/src/libtracker-data/tracker-db-interface.h
index d80b2c0..1a19171 100644
--- a/src/libtracker-data/tracker-db-interface.h
+++ b/src/libtracker-data/tracker-db-interface.h
@@ -137,6 +137,7 @@ TrackerDBCursor * tracker_db_statement_start_sparql_cursor (TrackerDBS
gint n_types,
const gchar **variable_names,
gint n_variable_names,
+ gboolean threadsafe,
GError **error);
void tracker_db_interface_set_busy_handler (TrackerDBInterface *db_interface,
TrackerBusyCallback busy_callback,
diff --git a/src/libtracker-data/tracker-db-manager.c b/src/libtracker-data/tracker-db-manager.c
index caf4a34..3c3c452 100644
--- a/src/libtracker-data/tracker-db-manager.c
+++ b/src/libtracker-data/tracker-db-manager.c
@@ -158,6 +158,9 @@ static guint u_cache_size;
static GStaticPrivate interface_data_key = G_STATIC_PRIVATE_INIT;
+/* mutex used by singleton connection in libtracker-direct, not used by tracker-store */
+static GStaticMutex global_mutex = G_STATIC_MUTEX_INIT;
+
static const gchar *
location_to_directory (TrackerDBLocation location)
{
@@ -1680,3 +1683,21 @@ tracker_db_manager_set_last_crawl_done (gboolean done)
g_free (filename);
}
+
+void
+tracker_db_manager_lock (void)
+{
+ g_static_mutex_lock (&global_mutex);
+}
+
+gboolean
+tracker_db_manager_trylock (void)
+{
+ return g_static_mutex_trylock (&global_mutex);
+}
+
+void
+tracker_db_manager_unlock (void)
+{
+ g_static_mutex_unlock (&global_mutex);
+}
diff --git a/src/libtracker-data/tracker-db-manager.h b/src/libtracker-data/tracker-db-manager.h
index 70e8977..a82148e 100644
--- a/src/libtracker-data/tracker-db-manager.h
+++ b/src/libtracker-data/tracker-db-manager.h
@@ -69,6 +69,10 @@ void tracker_db_manager_init_locations (void);
gboolean tracker_db_manager_has_enough_space (void);
void tracker_db_manager_remove_version_file (void);
+void tracker_db_manager_lock (void);
+gboolean tracker_db_manager_trylock (void);
+void tracker_db_manager_unlock (void);
+
TrackerDBManagerFlags
tracker_db_manager_get_flags (guint *select_cache_size,
guint *update_cache_size);
diff --git a/src/libtracker-data/tracker-sparql-query.vala b/src/libtracker-data/tracker-sparql-query.vala
index 7e80770..2a19776 100644
--- a/src/libtracker-data/tracker-sparql-query.vala
+++ b/src/libtracker-data/tracker-sparql-query.vala
@@ -415,19 +415,19 @@ public class Tracker.Sparql.Query : Object {
}
- public DBCursor? execute_cursor () throws DBInterfaceError, Sparql.Error, DateError {
+ public DBCursor? execute_cursor (bool threadsafe) throws DBInterfaceError, Sparql.Error, DateError {
prepare_execute ();
switch (current ()) {
case SparqlTokenType.SELECT:
- return execute_select_cursor ();
+ return execute_select_cursor (threadsafe);
case SparqlTokenType.CONSTRUCT:
throw get_internal_error ("CONSTRUCT is not supported");
case SparqlTokenType.DESCRIBE:
throw get_internal_error ("DESCRIBE is not supported");
case SparqlTokenType.ASK:
- return execute_ask_cursor ();
+ return execute_ask_cursor (threadsafe);
case SparqlTokenType.INSERT:
case SparqlTokenType.DELETE:
case SparqlTokenType.DROP:
@@ -523,10 +523,10 @@ public class Tracker.Sparql.Query : Object {
return stmt.execute ();
}
- DBCursor? exec_sql_cursor (string sql, PropertyType[] types, string[] variable_names) throws DBInterfaceError, Sparql.Error, DateError {
+ DBCursor? exec_sql_cursor (string sql, PropertyType[] types, string[] variable_names, bool threadsafe) throws DBInterfaceError, Sparql.Error, DateError {
var stmt = prepare_for_exec (sql);
- return stmt.start_sparql_cursor (types, variable_names);
+ return stmt.start_sparql_cursor (types, variable_names, threadsafe);
}
string get_select_query (out SelectContext context) throws DBInterfaceError, Sparql.Error, DateError {
@@ -546,11 +546,11 @@ public class Tracker.Sparql.Query : Object {
return exec_sql (get_select_query (out context));
}
- DBCursor? execute_select_cursor () throws DBInterfaceError, Sparql.Error, DateError {
+ DBCursor? execute_select_cursor (bool threadsafe) throws DBInterfaceError, Sparql.Error, DateError {
SelectContext context;
string sql = get_select_query (out context);
- return exec_sql_cursor (sql, context.types, context.variable_names);
+ return exec_sql_cursor (sql, context.types, context.variable_names, true);
}
string get_ask_query () throws DBInterfaceError, Sparql.Error, DateError {
@@ -584,8 +584,8 @@ public class Tracker.Sparql.Query : Object {
return exec_sql (get_ask_query ());
}
- DBCursor? execute_ask_cursor () throws DBInterfaceError, Sparql.Error, DateError {
- return exec_sql_cursor (get_ask_query (), new PropertyType[] { PropertyType.BOOLEAN }, new string[] { "result" });
+ DBCursor? execute_ask_cursor (bool threadsafe) throws DBInterfaceError, Sparql.Error, DateError {
+ return exec_sql_cursor (get_ask_query (), new PropertyType[] { PropertyType.BOOLEAN }, new string[] { "result" }, true);
}
private void parse_from_or_into_param () throws Sparql.Error {
diff --git a/src/libtracker-direct/tracker-direct.vala b/src/libtracker-direct/tracker-direct.vala
index 5bf37b8..884b053 100644
--- a/src/libtracker-direct/tracker-direct.vala
+++ b/src/libtracker-direct/tracker-direct.vala
@@ -45,10 +45,10 @@ public class Tracker.Direct.Connection : Tracker.Sparql.Connection {
}
}
- public override Sparql.Cursor query (string sparql, Cancellable? cancellable) throws Sparql.Error, IOError, DBusError {
+ Sparql.Cursor query_unlocked (string sparql, Cancellable? cancellable) throws Sparql.Error, IOError, DBusError {
try {
var query_object = new Sparql.Query (sparql);
- var cursor = query_object.execute_cursor ();
+ var cursor = query_object.execute_cursor (true);
cursor.connection = this;
return cursor;
} catch (DBInterfaceError e) {
@@ -58,9 +58,43 @@ public class Tracker.Direct.Connection : Tracker.Sparql.Connection {
}
}
- public async override Sparql.Cursor query_async (string sparql, Cancellable? cancellable = null) throws Sparql.Error, IOError, DBusError {
- // just creating the cursor won't block
- return query (sparql, cancellable);
+ public override Sparql.Cursor query (string sparql, Cancellable? cancellable) throws Sparql.Error, IOError, DBusError {
+ DBManager.lock ();
+ try {
+ return query_unlocked (sparql, cancellable);
+ } finally {
+ DBManager.unlock ();
+ }
+ }
+
+ public async override Sparql.Cursor query_async (string sparql, Cancellable? cancellable) throws Sparql.Error, IOError, DBusError {
+ if (!DBManager.trylock ()) {
+ // run in a separate thread
+ Error job_error = null;
+ Sparql.Cursor result = null;
+
+ g_io_scheduler_push_job (job => {
+ try {
+ result = query (sparql, cancellable);
+ } catch (Error e) {
+ job_error = e;
+ }
+ query_async.callback ();
+ return false;
+ });
+ yield;
+
+ if (job_error != null) {
+ throw job_error;
+ } else {
+ return result;
+ }
+ }
+ try {
+ return query_unlocked (sparql, cancellable);
+ } finally {
+ DBManager.unlock ();
+ }
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]