[tracker/dont-interrupt-create-statement] libtracker-db: Don't interrupt sqlite3_prepare_v2 with sqlite3_interrupt



commit 415997ac4e13906b3930e558bfbc1515a55526be
Author: Philip Van Hoof <philip codeminded be>
Date:   Mon May 24 13:17:34 2010 +0200

    libtracker-db: Don't interrupt sqlite3_prepare_v2 with sqlite3_interrupt
    
    We don't handle create_statement returning NULL due to sqlite3_prepare_v2 being
    interrupted with our interrupt function that calls sqlite3_interrupt. Because
    added interrupt handling for all callers of create_statement is a massive
    undertaking in nearly all levels of the code (ensure_resource_id would need
    error reporting, for example, among many many others) I decided to place a
    simple mutex around sqlite3_interrupt and around the sqlite3_prepare_v2,
    preventing sqlite3_interrupt from ever executing concurrently with
    sqlite3_prepare_v2.

 src/libtracker-db/tracker-db-interface-sqlite.c |   30 +++++++++++++++++++++-
 1 files changed, 28 insertions(+), 2 deletions(-)
---
diff --git a/src/libtracker-db/tracker-db-interface-sqlite.c b/src/libtracker-db/tracker-db-interface-sqlite.c
index c290d16..2c50fb3 100644
--- a/src/libtracker-db/tracker-db-interface-sqlite.c
+++ b/src/libtracker-db/tracker-db-interface-sqlite.c
@@ -61,7 +61,6 @@ typedef struct TrackerDBCursorSqliteClass TrackerDBCursorSqliteClass;
 typedef struct TrackerDBStatementSqlite      TrackerDBStatementSqlite;
 typedef struct TrackerDBStatementSqliteClass TrackerDBStatementSqliteClass;
 
-
 struct TrackerDBCursorSqlite {
 	GObject parent_instance;
 	TrackerDBCursorSqlitePrivate *priv;
@@ -82,6 +81,7 @@ struct TrackerDBInterfaceSqlitePrivate {
 	guint in_transaction : 1;
 	guint ro : 1;
 	guint fts_initialized : 1;
+	GMutex *interrupt_mutex;
 };
 
 struct TrackerDBStatementSqlitePrivate {
@@ -494,6 +494,8 @@ open_database (TrackerDBInterfaceSqlitePrivate *priv)
 {
 	g_assert (priv->filename != NULL);
 
+	priv->interrupt_mutex = g_mutex_new ();
+
 	if (!priv->ro) {
 		if (sqlite3_open (priv->filename, &priv->db) != SQLITE_OK) {
 			g_critical ("Could not open sqlite3 database:'%s'", priv->filename);
@@ -652,6 +654,8 @@ tracker_db_interface_sqlite_finalize (GObject *object)
 
 	g_message ("Closed sqlite3 database:'%s'", priv->filename);
 
+	g_mutex_free (priv->interrupt_mutex);
+
 	g_free (priv->filename);
 
 	G_OBJECT_CLASS (tracker_db_interface_sqlite_parent_class)->finalize (object);
@@ -761,9 +765,21 @@ tracker_db_interface_sqlite_create_statement (TrackerDBInterface *db_interface,
 {
 	TrackerDBInterfaceSqlitePrivate *priv;
 	TrackerDBStatementSqlite *stmt;
+	TrackerDBStatement *ret;
 
 	priv = TRACKER_DB_INTERFACE_SQLITE_GET_PRIVATE (db_interface);
 
+	/* This mutex prevents an interrupt from happening while we are preparing a
+	 * query. We don't have any interrupt handling for create_statement at any
+	 * place in the code, it would be a massive undertaking to support handling
+	 * interrupting while preparing a query. Which is why we block the interrupt
+	 * until after we prepared the query. Because prepared statements end up in
+	 * a cache wont it happen often that this lock is needed. But still, we do
+	 * need to protect against sqlite3_interrupt while sqlite3_prepare_v2 takes
+	 * place, as the 'return NULL' isn't handled anywhere in the code. */
+
+	g_mutex_lock (priv->interrupt_mutex);
+
 	stmt = g_hash_table_lookup (priv->dynamic_statements, query);
 
 	if (!stmt) {
@@ -773,6 +789,9 @@ tracker_db_interface_sqlite_create_statement (TrackerDBInterface *db_interface,
 
 		if (sqlite3_prepare_v2 (priv->db, query, -1, &sqlite_stmt, NULL) != SQLITE_OK) {
 			g_critical ("Unable to prepare query '%s': %s", query, sqlite3_errmsg (priv->db));
+
+			g_mutex_unlock (priv->interrupt_mutex);
+
 			return NULL;
 		}
 
@@ -782,7 +801,11 @@ tracker_db_interface_sqlite_create_statement (TrackerDBInterface *db_interface,
 		tracker_db_statement_sqlite_reset (stmt);
 	}
 
-	return g_object_ref (stmt);
+	ret = g_object_ref (stmt);
+
+	g_mutex_unlock (priv->interrupt_mutex);
+
+	return ret;
 }
 
 static TrackerDBResultSet *
@@ -909,7 +932,10 @@ tracker_db_interface_sqlite_interrupt (TrackerDBInterface *iface)
 	TrackerDBInterfaceSqlitePrivate *priv;
 
 	priv = TRACKER_DB_INTERFACE_SQLITE_GET_PRIVATE (iface);
+
+	g_mutex_lock (priv->interrupt_mutex);
 	sqlite3_interrupt (priv->db);
+	g_mutex_unlock (priv->interrupt_mutex);
 
 	return TRUE;
 }



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