[tracker] tracker_decorator_next(): Queue tasks when a query is needed



commit 94d4a8512cd330edd60a75f4b9bc839c277e7d08
Author: Xavier Claessens <xavier claessens collabora co uk>
Date:   Thu Jan 30 14:08:00 2014 -0500

    tracker_decorator_next(): Queue tasks when a query is needed
    
    This avoid double query when calling tracker_decorator_next()
    multiple times consecutively.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=719802

 src/libtracker-miner/tracker-decorator.c |  220 ++++++++++-------------------
 1 files changed, 76 insertions(+), 144 deletions(-)
---
diff --git a/src/libtracker-miner/tracker-decorator.c b/src/libtracker-miner/tracker-decorator.c
index 1e6d364..b0c6934 100644
--- a/src/libtracker-miner/tracker-decorator.c
+++ b/src/libtracker-miner/tracker-decorator.c
@@ -42,7 +42,6 @@
 **/
 
 typedef struct _TrackerDecoratorPrivate TrackerDecoratorPrivate;
-typedef struct _TaskData TaskData;
 typedef struct _ElemNode ElemNode;
 
 struct _TrackerDecoratorInfo {
@@ -53,12 +52,6 @@ struct _TrackerDecoratorInfo {
        gint ref_count;
 };
 
-struct _TaskData {
-       TrackerDecorator *decorator;
-       GList *first;
-       GList *last;
-};
-
 struct _ElemNode {
        TrackerDecoratorInfo *info;
        gint id;
@@ -73,6 +66,7 @@ struct _TrackerDecoratorPrivate {
        GHashTable *elems;
        GPtrArray *sparql_buffer;
        GTimer *timer;
+       GQueue next_elem_queue;
 
        GArray *class_name_ids;
        gint rdf_type_id;
@@ -105,8 +99,6 @@ static GInitableIface *parent_initable_iface;
 
 static GQuark tracker_decorator_error_quark         (void);
 static void   tracker_decorator_initable_iface_init (GInitableIface   *iface);
-static void   query_next_items                      (TrackerDecorator *decorator,
-                                                     GTask            *task);
 
 G_DEFINE_QUARK (TrackerDecoratorError, tracker_decorator_error)
 
@@ -148,31 +140,6 @@ tracker_decorator_info_unref (TrackerDecoratorInfo *info)
        g_slice_free (TrackerDecoratorInfo, info);
 }
 
-static TaskData *
-task_data_new (TrackerDecorator *decorator,
-               GList            *first,
-               GList            *last)
-{
-       TaskData *data;
-
-       data = g_slice_new0 (TaskData);
-       data->decorator = decorator;
-       data->first = first;
-       data->last = last;
-
-       return data;
-}
-
-static void
-task_data_free (TaskData *data)
-{
-       if (!data) {
-               return;
-       }
-
-       g_slice_free (TaskData, data);
-}
-
 static void
 decorator_update_state (TrackerDecorator *decorator,
                         const gchar      *message,
@@ -1035,92 +1002,32 @@ tracker_decorator_delete_id (TrackerDecorator *decorator,
        element_remove_by_id (decorator, id);
 }
 
-static GList *
-find_first_free_node (TrackerDecorator *decorator)
-{
-       TrackerDecoratorPrivate *priv;
-       GList *l;
-
-       priv = decorator->priv;
-
-       if (!priv->elem_queue->head)
-               return NULL;
-
-       for (l = priv->elem_queue->head; l; l = l->next) {
-               ElemNode *node = l->data;
-
-               if (!node->info || !node->info->task)
-                       return l;
-       }
-
-       return NULL;
-}
-
-static void
-complete_task (GTask    *task,
-               ElemNode *node)
-{
-       g_assert (node->info);
-
-       element_ensure_task (node, g_task_get_source_object (task));
-       g_task_return_pointer (task, node->info,
-                              (GDestroyNotify) tracker_decorator_info_unref);
-       g_object_unref (task);
-}
-
-static void
-check_task_complete (TrackerDecorator *decorator,
-                     GTask            *task)
-{
-       GList *first, *last;
-       TaskData *data;
-
-       data = g_task_get_task_data (task);
-       first = data->first;
-       last = data->last->next;
-
-       while (first != last) {
-               ElemNode *node;
-               GList *next;
-
-               node = first->data;
-               next = first->next;
-
-               if (node->info) {
-                       complete_task (task, node);
-                       return;
-               }
-
-               element_remove_link (decorator, first, TRUE);
-               first = next;
-       }
-
-       /* If this is reached, no queried IDs
-        * got data in the query, so try again.
-        */
-       query_next_items (decorator, task);
-}
+static void complete_tasks_or_query (TrackerDecorator *decorator);
 
 static void
 query_next_items_cb (GObject      *object,
                      GAsyncResult *result,
                      gpointer      user_data)
 {
+       TrackerDecorator *decorator = user_data;
        TrackerDecoratorPrivate *priv;
        TrackerSparqlConnection *conn;
        TrackerSparqlCursor *cursor;
-       GTask *task = user_data;
        GError *error = NULL;
-       TaskData *data;
 
        conn = TRACKER_SPARQL_CONNECTION (object);
        cursor = tracker_sparql_connection_query_finish (conn, result, &error);
-       data = g_task_get_task_data (task);
-       priv = data->decorator->priv;
+       priv = decorator->priv;
 
        if (error) {
-               g_task_return_error (task, error);
-               g_object_unref (task);
+               GTask *task;
+
+               while ((task = g_queue_pop_head (&priv->next_elem_queue))) {
+                       g_task_return_error (task, g_error_copy (error));
+                       g_object_unref (task);
+               }
+
+               g_clear_error (&error);
                return;
        }
 
@@ -1137,51 +1044,37 @@ query_next_items_cb (GObject      *object,
 
        g_object_unref (cursor);
 
-       check_task_complete (data->decorator, task);
+       complete_tasks_or_query (decorator);
 }
 
 static void
 query_next_items (TrackerDecorator *decorator,
-                  GTask            *task)
+                  GList            *l)
 {
        TrackerSparqlConnection *sparql_conn;
        TrackerDecoratorPrivate *priv;
-       GList *items, *last;
        GString *id_string;
-       TaskData *data;
        gchar *query;
-       gint i;
+       guint count = 0;
 
        priv = decorator->priv;
-       items = find_first_free_node (decorator);
-
-       if (!items) {
-               GError *error;
-
-               error = g_error_new (tracker_decorator_error_quark (),
-                                    TRACKER_DECORATOR_ERROR_EMPTY,
-                                    "There are no items left");
-               g_task_return_error (task, error);
-               g_object_unref (task);
-               return;
-       }
 
-       sparql_conn = tracker_miner_get_connection (TRACKER_MINER (decorator));
        id_string = g_string_new (NULL);
+       for (; l != NULL && count < QUERY_BATCH_SIZE; l = l->next) {
+               ElemNode *node = l->data;
 
-       for (i = 0; i < QUERY_BATCH_SIZE && items; i++) {
-               ElemNode *node;
-
-               last = items;
-               node = items->data;
-               items = items->next;
+               if (node->info)
+                       continue;
 
                if (id_string->len > 0)
                        g_string_append_c (id_string, ',');
 
                g_string_append_printf (id_string, "%d", node->id);
+               count++;
        }
 
+       g_assert (count > 0);
+
        query = g_strdup_printf ("SELECT ?urn"
                                 "       tracker:id(?urn) "
                                 "       nie:url(?urn) "
@@ -1191,15 +1084,56 @@ query_next_items (TrackerDecorator *decorator,
                                 "          ! EXISTS { ?urn nie:dataSource <%s> })"
                                 "}", id_string->str, priv->data_source);
 
-       data = task_data_new (decorator, priv->elem_queue->head, last);
-       g_task_set_task_data (task, data, (GDestroyNotify) task_data_free);
+       sparql_conn = tracker_miner_get_connection (TRACKER_MINER (decorator));
        tracker_sparql_connection_query_async (sparql_conn, query,
-                                              g_task_get_cancellable (task),
-                                              query_next_items_cb, task);
+                                              NULL,
+                                              query_next_items_cb, decorator);
        g_string_free (id_string, TRUE);
        g_free (query);
 }
 
+static void
+complete_tasks_or_query (TrackerDecorator *decorator)
+{
+       TrackerDecoratorPrivate *priv;
+       GList *l;
+       GTask *task;
+
+       priv = decorator->priv;
+
+       for (l = priv->elem_queue->head; l != NULL; l = l->next) {
+               ElemNode *node = l->data;
+
+               /* The next item isn't queried yet, do it now */
+               if (!node->info) {
+                       query_next_items (decorator, l);
+                       return;
+               }
+
+               /* If the item is not already being processed, we can complete a
+                * task with it. */
+               if (!node->info->task) {
+                       task = g_queue_pop_head (&priv->next_elem_queue);
+                       element_ensure_task (node, decorator);
+                       g_task_return_pointer (task, node->info,
+                                              (GDestroyNotify) tracker_decorator_info_unref);
+                       g_object_unref (task);
+
+                       if (g_queue_is_empty (&priv->next_elem_queue))
+                               return;
+               }
+       }
+
+       /* There is no element left, or they are all being processed already */
+       while ((task = g_queue_pop_head (&priv->next_elem_queue))) {
+               g_task_return_new_error (task,
+                                        tracker_decorator_error_quark (),
+                                        TRACKER_DECORATOR_ERROR_EMPTY,
+                                        "There are no items left");
+               g_object_unref (task);
+       }
+}
+
 /**
  * tracker_decorator_next:
  * @decorator: a #TrackerDecorator.
@@ -1222,12 +1156,13 @@ tracker_decorator_next (TrackerDecorator    *decorator,
                         GAsyncReadyCallback  callback,
                         gpointer             user_data)
 {
-       ElemNode *node = NULL;
+       TrackerDecoratorPrivate *priv;
        GTask *task;
-       GList *elem;
 
        g_return_if_fail (TRACKER_IS_DECORATOR (decorator));
 
+       priv = decorator->priv;
+
        task = g_task_new (decorator, cancellable, callback, user_data);
 
        if (tracker_miner_is_paused (TRACKER_MINER (decorator))) {
@@ -1241,15 +1176,12 @@ tracker_decorator_next (TrackerDecorator    *decorator,
                return;
        }
 
-       elem = find_first_free_node (decorator);
-
-       if (elem)
-               node = elem->data;
-
-       if (node && node->info)
-               complete_task (task, node);
-       else
-               query_next_items (decorator, task);
+       /* Push the task in a queue, for the case this function is called
+        * multiple before it finishes. */
+       g_queue_push_tail (&priv->next_elem_queue, task);
+       if (g_queue_get_length (&priv->next_elem_queue) == 1) {
+               complete_tasks_or_query (decorator);
+       }
 }
 
 /**


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