[tracker/async-queries-wip: 4/23] libtracker-db: Add TrackerDBInterfacePool.



commit 7b7be15a5002176fae704316e0b51be03cf469b7
Author: Carlos Garnacho <carlosg gnome org>
Date:   Tue Apr 13 14:57:58 2010 +0200

    libtracker-db: Add TrackerDBInterfacePool.
    
    TrackerDBInterfacePool allows threaded execution of select queries, so shorter queries don't
    starve and misbehaving queries may be cancelled.

 src/libtracker-db/tracker-db-manager.c |  271 ++++++++++++++++++++++++++++++++
 src/libtracker-db/tracker-db-manager.h |   36 +++++
 2 files changed, 307 insertions(+), 0 deletions(-)
---
diff --git a/src/libtracker-db/tracker-db-manager.c b/src/libtracker-db/tracker-db-manager.c
index 13b3996..82c5367 100644
--- a/src/libtracker-db/tracker-db-manager.c
+++ b/src/libtracker-db/tracker-db-manager.c
@@ -142,6 +142,24 @@ static TrackerDBDefinition dbs[] = {
 	  0 },
 };
 
+
+typedef struct TrackerDBInterfacePoolPrivate TrackerDBInterfacePoolPrivate;
+typedef struct PoolJob PoolJob;
+
+struct TrackerDBInterfacePoolPrivate {
+	GThreadPool *interface_pool;
+};
+
+struct PoolJob {
+	guint priority;
+	GSimpleAsyncResult *async_result;
+	GCancellable *cancellable;
+	GAsyncReadyCallback callback;
+	gpointer user_data;
+	gchar *query;
+	GValueArray *bind_values;
+};
+
 static gboolean            db_exec_no_reply    (TrackerDBInterface *iface,
                                                 const gchar        *query,
                                                 ...);
@@ -159,6 +177,11 @@ static gpointer              db_type_enum_class_pointer;
 static TrackerDBInterface   *resources_iface;
 static TrackerDBManagerFlags old_flags = 0;
 
+#define TRACKER_DB_INTERFACE_POOL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TRACKER_TYPE_DB_INTERFACE_POOL, TrackerDBInterfacePoolPrivate))
+
+G_DEFINE_TYPE (TrackerDBInterfacePool, tracker_db_interface_pool, G_TYPE_OBJECT)
+
+
 static const gchar *
 location_to_directory (TrackerDBLocation location)
 {
@@ -1195,3 +1218,251 @@ tracker_db_manager_has_enough_space  (void)
 {
 	return tracker_file_system_has_enough_space (data_dir, TRACKER_DB_MIN_REQUIRED_SPACE, FALSE);
 }
+
+static void
+tracker_db_interface_pool_finalize (GObject *object)
+{
+	TrackerDBInterfacePoolPrivate *priv;
+
+	priv = TRACKER_DB_INTERFACE_POOL_GET_PRIVATE (object);
+
+	G_OBJECT_CLASS (tracker_db_interface_pool_parent_class)->finalize (object);
+}
+
+static void
+tracker_db_interface_pool_class_init (TrackerDBInterfacePoolClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->finalize = tracker_db_interface_pool_finalize;
+
+	g_type_class_add_private (object_class,
+	                          sizeof (TrackerDBInterfacePoolPrivate));
+}
+
+static void
+pool_job_destroy (PoolJob *job)
+{
+	if (job->cancellable) {
+		g_object_unref (job->cancellable);
+	}
+
+	if (job->bind_values) {
+		g_value_array_free (job->bind_values);
+	}
+
+	g_object_unref (job->async_result);
+	g_free (job->query);
+
+	g_slice_free (PoolJob, job);
+}
+
+static void
+interface_pool_dispatch_cb (gpointer data,
+                            gpointer user_data)
+{
+	static GStaticPrivate interface_data_key = G_STATIC_PRIVATE_INIT;
+	TrackerDBInterface *interface;
+	TrackerDBStatement *statement;
+	TrackerDBCursor *cursor;
+	GError *error = NULL;
+	PoolJob *job;
+	gint i, n_bind_values;
+
+	interface = g_static_private_get (&interface_data_key);
+	job = data;
+
+	if (job->cancellable) {
+		g_cancellable_push_current (job->cancellable);
+	}
+
+	/* Ensure the interface is there */
+	if (!interface) {
+		interface = tracker_db_manager_get_db_interfaces (3,
+		                                                  TRACKER_DB_METADATA,
+		                                                  TRACKER_DB_FULLTEXT,
+		                                                  TRACKER_DB_CONTENTS);
+
+		g_static_private_set (&interface_data_key,
+		                      interface,
+		                      (GDestroyNotify) g_object_unref);
+	}
+
+	statement = tracker_db_interface_create_statement (interface, "%s", job->query);
+
+	if (job->bind_values) {
+		n_bind_values = job->bind_values->n_values;
+	} else {
+		n_bind_values = 0;
+	}
+
+	for (i = 0; i < n_bind_values; i++) {
+		GType type;
+		GValue *val;
+
+		val = g_value_array_get_nth (job->bind_values, i);
+		type = G_VALUE_TYPE (val);
+
+		if (type == G_TYPE_STRING) {
+			tracker_db_statement_bind_text (statement, i,
+			                                g_value_get_string (val));
+		} else if (type == G_TYPE_DOUBLE) {
+			tracker_db_statement_bind_double (statement, i,
+			                                  g_value_get_double (val));
+		} else if (type == G_TYPE_INT) {
+			tracker_db_statement_bind_int (statement, i,
+			                               g_value_get_int (val));
+		} else if (type == G_TYPE_INT64) {
+			tracker_db_statement_bind_int64 (statement, i,
+			                                 g_value_get_int64 (val));
+		} else {
+			tracker_db_statement_bind_null (statement, i);
+		}
+	}
+
+	cursor = tracker_db_statement_start_cursor (statement, &error);
+
+	if (error) {
+		g_simple_async_result_set_from_error (G_SIMPLE_ASYNC_RESULT (job->async_result), error);
+		g_error_free (error);
+	} else {
+		TrackerDBResultSet *result_set;
+		guint n_columns;
+
+		n_columns = tracker_db_cursor_get_n_columns (cursor);
+		result_set = _tracker_db_result_set_new (n_columns);
+
+		do {
+			GValue val = { 0 };
+
+			_tracker_db_result_set_append (result_set);
+
+			for (i = 0; i < n_columns; i++) {
+				tracker_db_cursor_get_value (cursor, i, &val);
+
+				if (G_IS_VALUE (&val)) {
+					_tracker_db_result_set_set_value (result_set, i, &val);
+					g_value_unset (&val);
+				}
+
+				if (job->cancellable &&
+				    g_cancellable_is_cancelled (job->cancellable)) {
+					break;
+				}
+			}
+
+			if (job->cancellable &&
+			    g_cancellable_is_cancelled (job->cancellable)) {
+				break;
+			}
+		} while (tracker_db_cursor_iter_next (cursor));
+
+		g_object_unref (cursor);
+
+		if (job->cancellable &&
+		    g_cancellable_set_error_if_cancelled (job->cancellable, &error)) {
+			g_simple_async_result_set_from_error (G_SIMPLE_ASYNC_RESULT (job->async_result), error);
+			g_error_free (error);
+		} else {
+			g_simple_async_result_set_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (job->async_result),
+			                                           result_set, (GDestroyNotify) g_object_unref);
+		}
+	}
+
+	g_object_unref (statement);
+
+	g_simple_async_result_complete_in_idle (G_SIMPLE_ASYNC_RESULT (job->async_result));
+
+	if (job->cancellable) {
+		g_cancellable_pop_current (job->cancellable);
+	}
+
+	pool_job_destroy (job);
+}
+
+static void
+tracker_db_interface_pool_init (TrackerDBInterfacePool *pool)
+{
+	TrackerDBInterfacePoolPrivate *priv;
+
+	priv = TRACKER_DB_INTERFACE_POOL_GET_PRIVATE (pool);
+
+	priv->interface_pool = g_thread_pool_new (interface_pool_dispatch_cb,
+	                                          NULL, 10,
+	                                          FALSE, NULL);
+}
+
+TrackerDBInterfacePool *
+tracker_db_interface_pool_new (void)
+{
+	return g_object_new (TRACKER_TYPE_DB_INTERFACE_POOL, NULL);
+}
+
+TrackerDBResultSet *
+tracker_db_interface_pool_execute_query_finish (TrackerDBInterfacePool	*pool,
+                                                GAsyncResult            *res,
+                                                GError                 **error)
+{
+	GSimpleAsyncResult *result;
+	TrackerDBResultSet *result_set;
+
+	g_return_val_if_fail (TRACKER_IS_DB_INTERFACE_POOL (pool), NULL);
+	g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (res), NULL);
+
+	result = G_SIMPLE_ASYNC_RESULT (res);
+
+	if (g_simple_async_result_propagate_error (result, error)) {
+		return NULL;
+	}
+
+	result_set = TRACKER_DB_RESULT_SET (g_simple_async_result_get_op_res_gpointer (result));
+
+	return g_object_ref (result_set);
+}
+
+void
+tracker_db_interface_pool_execute_query_async (TrackerDBInterfacePool *pool,
+                                               guint                   priority,
+                                               const gchar            *query,
+                                               GValueArray            *bind_values,
+                                               GCancellable           *cancellable,
+                                               GAsyncReadyCallback     callback,
+                                               gpointer                user_data)
+{
+	TrackerDBInterfacePoolPrivate *priv;
+	GError *error = NULL;
+	PoolJob *job;
+
+	g_return_if_fail (TRACKER_IS_DB_INTERFACE_POOL (pool));
+	g_return_if_fail (callback != NULL);
+	g_return_if_fail (query != NULL);
+
+	priv = TRACKER_DB_INTERFACE_POOL_GET_PRIVATE (pool);
+
+	job = g_slice_new0 (PoolJob);
+
+	job->async_result = g_simple_async_result_new (G_OBJECT (pool), callback, user_data,
+	                                               tracker_db_interface_pool_execute_query_async);
+	g_simple_async_result_set_handle_cancellation (job->async_result, TRUE);
+
+	job->priority = priority;
+	job->callback = callback;
+	job->user_data = user_data;
+	job->query = g_strdup (query);
+
+	if (bind_values) {
+		job->bind_values = g_value_array_copy (bind_values);
+	}
+
+	if (cancellable) {
+		job->cancellable = g_object_ref (cancellable);
+	}
+
+	g_thread_pool_push (priv->interface_pool, job, &error);
+
+	if (error) {
+		g_simple_async_report_gerror_in_idle (G_OBJECT (pool), callback, user_data, error);
+		g_error_free (error);
+		pool_job_destroy (job);
+	}
+}
diff --git a/src/libtracker-db/tracker-db-manager.h b/src/libtracker-db/tracker-db-manager.h
index 520daba..1d3874a 100644
--- a/src/libtracker-db/tracker-db-manager.h
+++ b/src/libtracker-db/tracker-db-manager.h
@@ -21,6 +21,7 @@
 #define __LIBTRACKER_DB_MANAGER_H__
 
 #include <glib-object.h>
+#include <gio/gio.h>
 
 #include "tracker-db-interface.h"
 
@@ -32,6 +33,24 @@ G_BEGIN_DECLS
 
 #define TRACKER_TYPE_DB (tracker_db_get_type ())
 
+#define TRACKER_TYPE_DB_INTERFACE_POOL          (tracker_db_interface_pool_get_type ())
+#define TRACKER_DB_INTERFACE_POOL(o)            (G_TYPE_CHECK_INSTANCE_CAST ((o), TRACKER_TYPE_DB_INTERFACE_POOL, TrackerDBInterfacePool))
+#define TRACKER_DB_INTERFACE_POOL_CLASS(c)      (G_TYPE_CHECK_CLASS_CAST ((c),    TRACKER_TYPE_DB_INTERFACE_POOL, TrackerDBInterfacePoolClass))
+#define TRACKER_IS_DB_INTERFACE_POOL(o)         (G_TYPE_CHECK_INSTANCE_TYPE ((o), TRACKER_TYPE_DB_INTERFACE_POOL))
+#define TRACKER_IS_DB_INTERFACE_POOL_CLASS(c)   (G_TYPE_CHECK_CLASS_TYPE ((o),    TRACKER_TYPE_DB_INTERFACE_POOL))
+#define TRACKER_DB_INTERFACE_POOL_GET_CLASS(o)  (G_TYPE_INSTANCE_GET_CLASS ((o),  TRACKER_TYPE_DB_INTERFACE_POOL, TrackerDBInterfacePoolClass))
+
+typedef struct TrackerDBInterfacePool TrackerDBInterfacePool;
+typedef struct TrackerDBInterfacePoolClass TrackerDBInterfacePoolClass;
+
+struct TrackerDBInterfacePool {
+	GObject parent_instance;
+};
+
+struct TrackerDBInterfacePoolClass {
+	GObjectClass parent_class;
+};
+
 typedef enum {
 	TRACKER_DB_UNKNOWN,
 	TRACKER_DB_METADATA,
@@ -65,6 +84,23 @@ gboolean            tracker_db_manager_has_enough_space  (void);
 TrackerDBManagerFlags
                     tracker_db_manager_get_flags         (void);
 
+/* TrackerDBInterfacePool methods */
+GType  tracker_db_interface_pool_get_type (void) G_GNUC_CONST;
+
+TrackerDBInterfacePool * tracker_db_interface_pool_new (void);
+
+TrackerDBResultSet * tracker_db_interface_pool_execute_query_finish (TrackerDBInterfacePool  *pool,
+                                                                     GAsyncResult            *res,
+                                                                     GError                 **error);
+
+void                 tracker_db_interface_pool_execute_query_async  (TrackerDBInterfacePool *pool,
+                                                                     guint                   priority,
+                                                                     const gchar            *query,
+                                                                     GValueArray            *bind_values,
+                                                                     GCancellable           *cancellable,
+                                                                     GAsyncReadyCallback     callback,
+                                                                     gpointer                user_data);
+
 G_END_DECLS
 
 #endif /* __LIBTRACKER_DB_MANAGER_H__ */



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