[tracker/tracker-store-queue] Introduced TrackerStoreQueue, a queue for querying and updating



commit 26359f740c471bb73f9a3c43b421cc32713113f1
Author: Philip Van Hoof <philip codeminded be>
Date:   Thu May 21 10:40:37 2009 +0200

    Introduced TrackerStoreQueue, a queue for querying and updating
    
    TrackerStoreQueue is or will be the internal API for most data access and
    storage. This current implementation uses the GMainLoop and a  GQueue with no
    priority sorting whatsoever. At a later point in time we want to implement
    queue_sorter in a more meaningful way. For example meaning that batch_commits
    have precedence on all others, that queries get precedence after the batch
    commits, etcetera.
    
    Due to its use of the GMainLoop the API is going to block the mainloop, but it
    wont block the caller's code. It will instead find a nice slot during the
    GMainLoop the execute itself on. When finished it'll execute first your
    callback and then your GDestroyNotify. All parameters that you receive in the
    callback that aren't user_data must not be freed (they are to be considered
    read-only in your callback).
---
 src/tracker-store/Makefile.am           |    4 +-
 src/tracker-store/tracker-main.c        |    3 +
 src/tracker-store/tracker-resources.c   |  287 ++++++++++++++++++++++-------
 src/tracker-store/tracker-store-queue.c |  304 +++++++++++++++++++++++++++++++
 src/tracker-store/tracker-store-queue.h |   60 ++++++
 5 files changed, 588 insertions(+), 70 deletions(-)

diff --git a/src/tracker-store/Makefile.am b/src/tracker-store/Makefile.am
index 8005bf1..a96b918 100644
--- a/src/tracker-store/Makefile.am
+++ b/src/tracker-store/Makefile.am
@@ -63,7 +63,9 @@ tracker_store_SOURCES =							\
 	tracker-push-registrar.c					\
 	tracker-push-registrar.h					\
 	tracker-resource-class.c					\
-	tracker-resource-class.h
+	tracker-resource-class.h					\
+	tracker-store-queue.c						\
+	tracker-store-queue.h
 
 if OS_WIN32
 tracker_store_win_libs = -lws2_32 -lkernel32
diff --git a/src/tracker-store/tracker-main.c b/src/tracker-store/tracker-main.c
index ea53621..151e246 100644
--- a/src/tracker-store/tracker-main.c
+++ b/src/tracker-store/tracker-main.c
@@ -75,6 +75,7 @@
 #include "tracker-volume-cleanup.h"
 #include "tracker-backup.h"
 #include "tracker-daemon.h"
+#include "tracker-store-queue.h"
 
 #ifdef G_OS_WIN32
 #include <windows.h>
@@ -982,6 +983,7 @@ main (gint argc, gchar *argv[])
 			  NULL);
 #endif /* HAVE_HAL */
 
+	tracker_store_queue_init ();
 	tracker_status_init (config, hal_power);
 
 	tracker_module_config_init ();
@@ -1124,6 +1126,7 @@ main (gint argc, gchar *argv[])
 	tracker_nfs_lock_shutdown ();
 	tracker_status_shutdown ();
 	tracker_turtle_shutdown ();
+	tracker_store_queue_shutdown ();
 	tracker_thumbnailer_shutdown ();
 	tracker_log_shutdown ();
 
diff --git a/src/tracker-store/tracker-resources.c b/src/tracker-store/tracker-resources.c
index 783162d..0753183 100644
--- a/src/tracker-store/tracker-resources.c
+++ b/src/tracker-store/tracker-resources.c
@@ -41,6 +41,7 @@
 #include "tracker-resources.h"
 #include "tracker-resource-class.h"
 #include "tracker-events.h"
+#include "tracker-store-queue.h"
 
 #define RDF_PREFIX TRACKER_RDF_PREFIX
 #define RDF_TYPE RDF_PREFIX "type"
@@ -59,6 +60,12 @@ typedef struct {
 	GSList     *event_sources;
 } TrackerResourcesPrivate;
 
+typedef struct {
+	DBusGMethodInvocation *context;
+	guint request_id;
+	TrackerResources *self;
+} TrackerDBusMethodInfo;
+
 static void
 free_event_sources (TrackerResourcesPrivate *priv)
 {
@@ -111,6 +118,31 @@ tracker_resources_new (void)
  * Functions
  */
 
+static void
+destroy_method_info (gpointer user_data)
+{
+	g_slice_free (TrackerDBusMethodInfo, user_data);
+}
+
+
+static void
+update_callback (GError *error, gpointer user_data)
+{
+	TrackerDBusMethodInfo *info = user_data;
+
+	if (error) {
+		tracker_dbus_request_failed (info->request_id,
+					     &error,
+					     NULL);
+		dbus_g_method_return_error (info->context, error);
+		return;
+	}
+
+	dbus_g_method_return (info->context);
+
+	tracker_dbus_request_success (info->request_id);
+}
+
 void
 tracker_resources_insert (TrackerResources	     *self,
 			  const gchar                *subject,
@@ -119,7 +151,10 @@ tracker_resources_insert (TrackerResources	     *self,
 			  DBusGMethodInvocation      *context,
 			  GError		    **error)
 {
-	guint		    request_id;
+	TrackerResourcesPrivate *priv;
+	guint		         request_id;
+	TrackerDBusMethodInfo   *info;
+	gchar                   *update;
 
 	request_id = tracker_dbus_get_next_request_id ();
 
@@ -132,11 +167,35 @@ tracker_resources_insert (TrackerResources	     *self,
 				  "'%s' '%s' '%s'",
 				  subject, predicate, object);
 
-	tracker_data_insert_statement (subject, predicate, object);
+	priv = TRACKER_RESOURCES_GET_PRIVATE (self);
 
-	dbus_g_method_return (context);
+	if (priv->batch_mode) {
+		/* commit pending batch items */
+
+		tracker_store_queue_batch_commit (NULL, NULL, NULL);
+
+		/* Question, must we wait here until callback of commit is
+		 * completed? I guess this just depends on the priority rules
+		 * of a single update vs. a commit of a batch. If a commit 
+		 * comes first, we don't need to await its callback. Right? */
+
+		priv->batch_mode = FALSE;
+		priv->batch_count = 0;
+	}
+
+
+	info = g_slice_new (TrackerDBusMethodInfo);
+
+	info->request_id = request_id;
+	info->context = context;
+
+	update = g_strdup_printf ("INSERT { <%s> %s \"%s\" }", subject, predicate, object);
+
+	tracker_store_queue_sparql_update (update, update_callback, info,
+					   destroy_method_info);
+
+	g_free (update);
 
-	tracker_dbus_request_success (request_id);
 }
 
 void
@@ -147,7 +206,10 @@ tracker_resources_delete (TrackerResources	     *self,
 			  DBusGMethodInvocation      *context,
 			  GError		    **error)
 {
-	guint		    request_id;
+	TrackerResourcesPrivate *priv;
+	guint		         request_id;
+	TrackerDBusMethodInfo   *info;
+	gchar                   *update;
 
 	request_id = tracker_dbus_get_next_request_id ();
 
@@ -156,15 +218,39 @@ tracker_resources_delete (TrackerResources	     *self,
 	tracker_dbus_async_return_if_fail (object != NULL, context);
 
 	tracker_dbus_request_new (request_id,
-				  "DBus request to delete statement: "
+				  "DBus request to insert statement: "
 				  "'%s' '%s' '%s'",
 				  subject, predicate, object);
 
-	tracker_data_delete_statement (subject, predicate, object);
+	priv = TRACKER_RESOURCES_GET_PRIVATE (self);
 
-	dbus_g_method_return (context);
+	if (priv->batch_mode) {
+		/* commit pending batch items */
+
+		tracker_store_queue_batch_commit (NULL, NULL, NULL);
+
+		/* Question, must we wait here until callback of commit is
+		 * completed? I guess this just depends on the priority rules
+		 * of a single update vs. a commit of a batch. If a commit 
+		 * comes first, we don't need to await its callback. Right? */
+
+		priv->batch_mode = FALSE;
+		priv->batch_count = 0;
+	}
+
+
+	info = g_slice_new (TrackerDBusMethodInfo);
+
+	info->request_id = request_id;
+	info->context = context;
+
+	update = g_strdup_printf ("DELETE { <%s> %s \"%s\" }", subject, predicate, object);
+
+	tracker_store_queue_sparql_update (update, update_callback, info,
+					   destroy_method_info);
+
+	g_free (update);
 
-	tracker_dbus_request_success (request_id);
 }
 
 void
@@ -209,16 +295,41 @@ tracker_resources_load (TrackerResources	 *object,
 	tracker_dbus_request_success (request_id);
 }
 
+
+static void 
+query_callback (TrackerDBResultSet *result_set, 
+		GError *error, 
+		gpointer user_data)
+{
+	TrackerDBusMethodInfo *info = user_data;
+	GPtrArray      *values;
+
+	if (error) {
+		tracker_dbus_request_failed (info->request_id,
+					     &error,
+					     NULL);
+		dbus_g_method_return_error (info->context, error);
+		return;
+	}
+
+	values = tracker_dbus_query_result_to_ptr_array (result_set);
+
+	dbus_g_method_return (info->context, values);
+
+	tracker_dbus_results_ptr_array_free (&values);
+
+	tracker_dbus_request_success (info->request_id);
+}
+
+
 void
 tracker_resources_sparql_query (TrackerResources	 *self,
 				const gchar	         *query,
 				DBusGMethodInvocation	 *context,
 				GError			**error)
 {
-	TrackerDBResultSet   *result_set;
-	GError 		     *actual_error = NULL;
-	guint		      request_id;
-	GPtrArray            *values;
+	TrackerDBusMethodInfo *info;
+	guint           request_id;
 
 	request_id = tracker_dbus_get_next_request_id ();
 
@@ -229,30 +340,16 @@ tracker_resources_sparql_query (TrackerResources	 *self,
 				  "query:'%s'",
 				  query);
 
-	result_set = tracker_data_query_sparql (query, &actual_error);
+	info = g_slice_new (TrackerDBusMethodInfo);
 
-	if (actual_error) {
-		tracker_dbus_request_failed (request_id,
-					     &actual_error,
-					     NULL);
-		dbus_g_method_return_error (context, actual_error);
-		g_error_free (actual_error);
-		return;
-	}
-
-	values = tracker_dbus_query_result_to_ptr_array (result_set);
-
-	dbus_g_method_return (context, values);
-
-	tracker_dbus_results_ptr_array_free (&values);
+	info->request_id = request_id;
+	info->context = context;
 
-	if (result_set) {
-		g_object_unref (result_set);
-	}
-
-	tracker_dbus_request_success (request_id);
+	tracker_store_queue_sparql_query (query, query_callback, info, 
+					  destroy_method_info);
 }
 
+
 void
 tracker_resources_sparql_update (TrackerResources	 *self,
 				 const gchar	         *update,
@@ -260,8 +357,8 @@ tracker_resources_sparql_update (TrackerResources	 *self,
 				 GError			**error)
 {
 	TrackerResourcesPrivate *priv;
-	GError 		     *actual_error = NULL;
-	guint		      request_id;
+	guint		         request_id;
+	TrackerDBusMethodInfo          *info;
 
 	priv = TRACKER_RESOURCES_GET_PRIVATE (self);
 
@@ -271,7 +368,14 @@ tracker_resources_sparql_update (TrackerResources	 *self,
 
 	if (priv->batch_mode) {
 		/* commit pending batch items */
-		tracker_data_commit_transaction ();
+
+		tracker_store_queue_batch_commit (NULL, NULL, NULL);
+
+		/* Question, must we wait here until callback of commit is
+		 * completed? I guess this just depends on the priority rules
+		 * of a single update vs. a commit of a batch. If a commit 
+		 * comes first, we don't need to await its callback. Right? */
+
 		priv->batch_mode = FALSE;
 		priv->batch_count = 0;
 	}
@@ -281,20 +385,52 @@ tracker_resources_sparql_update (TrackerResources	 *self,
 				  "update:'%s'",
 				  update);
 
-	tracker_data_update_sparql (update, &actual_error);
+	info = g_slice_new (TrackerDBusMethodInfo);
 
-	if (actual_error) {
-		tracker_dbus_request_failed (request_id,
-					     &actual_error,
+	info->request_id = request_id;
+	info->context = context;
+
+	tracker_store_queue_sparql_update (update, update_callback, info,
+					   destroy_method_info);
+
+}
+
+static void
+batch_update_callback (GError *error, gpointer user_data)
+{
+	TrackerDBusMethodInfo *info = user_data;
+	TrackerResourcesPrivate *priv;
+
+	if (error) {
+		tracker_dbus_request_failed (info->request_id,
+					     &error,
 					     NULL);
-		dbus_g_method_return_error (context, actual_error);
-		g_error_free (actual_error);
+		dbus_g_method_return_error (info->context, error);
+		g_object_unref (info->self);
 		return;
 	}
 
-	dbus_g_method_return (context);
+	priv = TRACKER_RESOURCES_GET_PRIVATE (info->self);
 
-	tracker_dbus_request_success (request_id);
+	if (++priv->batch_count >= TRACKER_STORE_TRANSACTION_MAX) {
+		/* commit pending batch items */
+
+		tracker_store_queue_batch_commit (NULL, NULL, NULL);
+
+		/* Question, must we wait here until callback of commit is
+		 * completed? I guess this just depends on the priority rules
+		 * of a single update vs. a commit of a batch. If a commit 
+		 * comes first, we don't need to await its callback. Right? */
+
+		priv->batch_mode = FALSE;
+		priv->batch_count = 0;
+	}
+
+	dbus_g_method_return (info->context);
+
+	g_object_unref (info->self);
+
+	tracker_dbus_request_success (info->request_id);
 }
 
 void
@@ -303,9 +439,9 @@ tracker_resources_batch_sparql_update (TrackerResources          *self,
 				       DBusGMethodInvocation	 *context,
 				       GError			**error)
 {
+	TrackerDBusMethodInfo   *info;
 	TrackerResourcesPrivate *priv;
-	GError 		     *actual_error = NULL;
-	guint		      request_id;
+	guint		         request_id;
 
 	priv = TRACKER_RESOURCES_GET_PRIVATE (self);
 
@@ -323,30 +459,29 @@ tracker_resources_batch_sparql_update (TrackerResources          *self,
 		   delays database commits to improve performance */
 		priv->batch_mode = TRUE;
 		priv->batch_count = 0;
-		tracker_data_begin_transaction ();
+
+		/* Transaction start is implicit in the queue */
 	}
 
-	tracker_data_update_sparql (update, &actual_error);
+	info = g_slice_new (TrackerDBusMethodInfo);
 
-	if (actual_error) {
-		tracker_dbus_request_failed (request_id,
-					     &actual_error,
-					     NULL);
-		dbus_g_method_return_error (context, actual_error);
-		g_error_free (actual_error);
-		return;
-	}
+	info->self = g_object_ref (self);
+	info->request_id = request_id;
+	info->context = context;
 
-	if (++priv->batch_count >= TRACKER_STORE_TRANSACTION_MAX) {
-		/* commit pending batch items */
-		tracker_data_commit_transaction ();
-		priv->batch_mode = FALSE;
-		priv->batch_count = 0;
-	}
+	tracker_store_queue_batch_sparql_update (update, batch_update_callback,
+						 info, destroy_method_info);
 
-	dbus_g_method_return (context);
 
-	tracker_dbus_request_success (request_id);
+}
+
+static void
+batch_commit_callback (gpointer user_data)
+{
+	TrackerDBusMethodInfo *info = user_data;
+
+	dbus_g_method_return (info->context);
+	tracker_dbus_request_success (info->request_id);
 }
 
 void
@@ -365,15 +500,29 @@ tracker_resources_batch_commit (TrackerResources	 *self,
 				  "DBus request for batch commit");
 
 	if (priv->batch_mode) {
+		TrackerDBusMethodInfo *info;
+
 		/* commit pending batch items */
-		tracker_data_commit_transaction ();
+
+		info = g_slice_new (TrackerDBusMethodInfo);
+
+		info->request_id = request_id;
+		info->context = context;
+
+		tracker_store_queue_batch_commit (batch_commit_callback, info,
+						  destroy_method_info);
+
+		/* Question, must we wait here until callback of commit is
+		 * completed? I guess this just depends on the priority rules
+		 * of a single update vs. a commit of a batch. If a commit 
+		 * comes first, we don't need to await its callback. Right? */
+
 		priv->batch_mode = FALSE;
 		priv->batch_count = 0;
+	} else {
+		dbus_g_method_return (context);
+		tracker_dbus_request_success (request_id);
 	}
-
-	dbus_g_method_return (context);
-
-	tracker_dbus_request_success (request_id);
 }
 
 
diff --git a/src/tracker-store/tracker-store-queue.c b/src/tracker-store/tracker-store-queue.c
new file mode 100644
index 0000000..89d9513
--- /dev/null
+++ b/src/tracker-store/tracker-store-queue.c
@@ -0,0 +1,304 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008, Nokia
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Author: Philip Van Hoof <philip codeminded be>
+ */
+
+#include "config.h"
+
+#include <libtracker-common/tracker-dbus.h>
+#include <libtracker-db/tracker-db-dbus.h>
+
+#include <libtracker-data/tracker-data-update.h>
+#include <libtracker-data/tracker-data-query.h>
+
+#include "tracker-store-queue.h"
+
+typedef struct {
+	gboolean  have_handler;
+	gboolean  final;
+	gboolean  in_batch;
+	GQueue   *queue;
+} TrackerStoreQueuePrivate;
+
+typedef enum {
+	TRACKER_STORE_QUEUE_TASK_TYPE_QUERY,
+	TRACKER_STORE_QUEUE_TASK_TYPE_UPDATE,
+	TRACKER_STORE_QUEUE_TASK_TYPE_COMMIT,
+} TrackerStoreQueueTaskType;
+
+typedef struct {
+	TrackerStoreQueueTaskType  type;
+	gchar                     *query;
+	gpointer                   user_data;
+	gboolean                   in_batch;
+	GDestroyNotify             destroy;
+	union {
+		TrackerStoreQueueSparqlUpdateCallback update_callback;
+		TrackerStoreQueueCommitCallback       commit_callback;
+		TrackerStoreQueueSparqlQueryCallback  query_callback;
+	} callback;
+} TrackerStoreQueueTask;
+
+static GStaticPrivate private_key = G_STATIC_PRIVATE_INIT;
+
+
+static void
+private_free (gpointer data)
+{
+	TrackerStoreQueuePrivate *private = data;
+
+	g_queue_free (private->queue);
+	g_free (private);
+}
+
+static void
+tracker_store_queue_task_free (TrackerStoreQueueTask *task)
+{
+	g_free (task->query);
+	g_slice_free (TrackerStoreQueueTask, task);
+}
+
+static gboolean
+queue_idle_handler (gpointer user_data)
+{
+	TrackerStoreQueuePrivate *private = user_data;
+	TrackerStoreQueueTask    *task;
+	GError                   *error = NULL;
+	TrackerDBResultSet       *result_set;
+
+	task = g_queue_pop_head (private->queue);
+
+	if (!task) {
+		return FALSE;
+	}
+
+	if (task->in_batch && !private->in_batch) {
+		tracker_data_begin_transaction ();
+	}
+
+	switch (task->type) {
+		case TRACKER_STORE_QUEUE_TASK_TYPE_QUERY:
+			result_set = tracker_data_query_sparql (task->query, &error);
+			if (task->callback.query_callback) {
+				task->callback.query_callback (result_set, error,
+				                               task->user_data);
+			}
+			if (result_set) {
+				g_object_unref (result_set);
+			}
+		break;
+
+		case TRACKER_STORE_QUEUE_TASK_TYPE_COMMIT:
+
+			tracker_data_commit_transaction ();
+			private->in_batch = FALSE;
+
+			if (task->callback.commit_callback) {
+				task->callback.commit_callback (task->user_data);
+			}
+
+			break;
+
+		case TRACKER_STORE_QUEUE_TASK_TYPE_UPDATE:
+			tracker_data_update_sparql (task->query, &error);
+			if (task->callback.update_callback) {
+				task->callback.update_callback (error, task->user_data);
+			}
+		default:
+		break;
+	}
+
+	if (task->destroy) {
+		task->destroy (task->user_data);
+	}
+
+	if (error) {
+		g_clear_error (&error);
+	}
+
+	tracker_store_queue_task_free (task);
+
+	return TRUE;
+}
+
+static void
+queue_idle_destroy (gpointer user_data)
+{
+	TrackerStoreQueuePrivate *private = user_data;
+
+	private->have_handler = FALSE;
+
+	if (private->final) {
+		g_static_private_set (&private_key, NULL, NULL);
+	}
+}
+
+void
+tracker_store_queue_init (void)
+{
+	TrackerStoreQueuePrivate *private;
+
+	private = g_new0 (TrackerStoreQueuePrivate, 1);
+
+	private->final = FALSE;
+	private->queue = g_queue_new ();
+
+	g_static_private_set (&private_key,
+	                      private,
+	                      private_free);
+}
+
+void
+tracker_store_queue_shutdown (void)
+{
+	TrackerStoreQueuePrivate *private;
+
+	private = g_static_private_get (&private_key);
+	g_return_if_fail (private != NULL);
+
+	private->final = TRUE;
+}
+
+static void
+start_handler (TrackerStoreQueuePrivate *private) 
+{
+	g_idle_add_full (G_PRIORITY_DEFAULT,
+	                 queue_idle_handler,
+	                 private,
+	                 queue_idle_destroy);
+}
+
+
+static gint 
+queue_sorter (gconstpointer a,
+              gconstpointer b,
+              gpointer user_data)
+{
+	return TRUE;
+}
+
+void
+tracker_store_queue_batch_commit (TrackerStoreQueueCommitCallback callback, 
+                                  gpointer user_data,
+                                  GDestroyNotify destroy)
+{
+	TrackerStoreQueuePrivate *private;
+	TrackerStoreQueueTask    *task;
+
+	private = g_static_private_get (&private_key);
+	g_return_if_fail (private != NULL);
+
+	task = g_slice_new0 (TrackerStoreQueueTask);
+	task->type = TRACKER_STORE_QUEUE_TASK_TYPE_COMMIT;
+	task->user_data = user_data;
+	task->callback.commit_callback = callback;
+	task->in_batch = TRUE;
+	task->destroy = destroy;
+
+	g_queue_insert_sorted (private->queue, task,
+	                       queue_sorter, NULL);
+
+	if (!private->have_handler) {
+		start_handler (private);
+	}
+}
+
+
+void
+tracker_store_queue_batch_sparql_update (const gchar *sparql, 
+                                         TrackerStoreQueueSparqlUpdateCallback callback,
+                                         gpointer user_data,
+                                         GDestroyNotify destroy)
+{
+	TrackerStoreQueuePrivate *private;
+	TrackerStoreQueueTask    *task;
+
+	private = g_static_private_get (&private_key);
+	g_return_if_fail (private != NULL);
+
+	task = g_slice_new0 (TrackerStoreQueueTask);
+	task->type = TRACKER_STORE_QUEUE_TASK_TYPE_UPDATE;
+	task->query = g_strdup (sparql);
+	task->user_data = user_data;
+	task->callback.update_callback = callback;
+	task->in_batch = TRUE;
+	task->destroy = destroy;
+
+	g_queue_insert_sorted (private->queue, task,
+	                       queue_sorter, NULL);
+
+	if (!private->have_handler) {
+		start_handler (private);
+	}
+}
+
+void
+tracker_store_queue_sparql_update (const gchar *sparql, 
+                                  TrackerStoreQueueSparqlUpdateCallback callback,
+                                  gpointer user_data,
+                                  GDestroyNotify destroy)
+{
+	TrackerStoreQueueTask    *task;
+	TrackerStoreQueuePrivate *private;
+
+	private = g_static_private_get (&private_key);
+	g_return_if_fail (private != NULL);
+
+	task = g_slice_new0 (TrackerStoreQueueTask);
+	task->type = TRACKER_STORE_QUEUE_TASK_TYPE_UPDATE;
+	task->query = g_strdup (sparql);
+	task->user_data = user_data;
+	task->callback.update_callback = callback;
+	task->destroy = destroy;
+
+	g_queue_insert_sorted (private->queue, task,
+	                       queue_sorter, NULL);
+
+	if (!private->have_handler) {
+		start_handler (private);
+	}
+}
+
+void
+tracker_store_queue_sparql_query (const gchar *sparql, 
+                                 TrackerStoreQueueSparqlQueryCallback callback,
+                                 gpointer user_data,
+                                 GDestroyNotify destroy)
+{
+	TrackerStoreQueueTask    *task;
+	TrackerStoreQueuePrivate *private;
+
+	private = g_static_private_get (&private_key);
+	g_return_if_fail (private != NULL);
+
+	task = g_slice_new0 (TrackerStoreQueueTask);
+	task->type = TRACKER_STORE_QUEUE_TASK_TYPE_QUERY;
+	task->query = g_strdup (sparql);
+	task->user_data = user_data;
+	task->callback.query_callback = callback;
+	task->destroy = destroy;
+
+	g_queue_insert_sorted (private->queue, task,
+	                       queue_sorter, NULL);
+
+	if (!private->have_handler) {
+		start_handler (private);
+	}
+}
diff --git a/src/tracker-store/tracker-store-queue.h b/src/tracker-store/tracker-store-queue.h
new file mode 100644
index 0000000..a87dcf0
--- /dev/null
+++ b/src/tracker-store/tracker-store-queue.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2008, Nokia
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Author: Philip Van Hoof <philip codeminded be>
+ */
+
+#ifndef __TRACKER_STORE_QUEUE_H__
+#define __TRACKER_STORE_QUEUE_H__
+
+#include <stdio.h>
+
+#include <libtracker-common/tracker-common.h>
+#include <libtracker-db/tracker-db-interface.h>
+
+G_BEGIN_DECLS
+
+typedef void (* TrackerStoreQueueSparqlUpdateCallback) (GError          *error,
+                                                        gpointer         user_data);
+typedef void (* TrackerStoreQueueCommitCallback)       (gpointer         user_data);
+typedef void (* TrackerStoreQueueSparqlQueryCallback)  (TrackerDBResultSet *results,
+                                                        GError          *error,
+                                                        gpointer         user_data);
+
+void         tracker_store_queue_init                  (void);
+void         tracker_store_queue_shutdown              (void);
+void         tracker_store_queue_batch_commit          (TrackerStoreQueueCommitCallback       callback,
+                                                        gpointer       user_data,
+                                                        GDestroyNotify destroy);
+void         tracker_store_queue_batch_sparql_update   (const gchar   *sparql, 
+                                                        TrackerStoreQueueSparqlUpdateCallback callback,
+                                                        gpointer       user_data,
+                                                        GDestroyNotify destroy);
+void         tracker_store_queue_sparql_update         (const gchar   *sparql, 
+                                                        TrackerStoreQueueSparqlUpdateCallback callback,
+                                                        gpointer       user_data,
+                                                        GDestroyNotify destroy);
+void         tracker_store_queue_sparql_query          (const gchar   *sparql, 
+                                                        TrackerStoreQueueSparqlQueryCallback  callback,
+                                                        gpointer       user_data,
+                                                        GDestroyNotify destroy);
+
+G_END_DECLS
+
+#endif /* __TRACKER_STORE_QUEUE_H__ */



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