[PATCH 2/2] tracker: use centralized request queue



From: Lionel Landwerlin <lionel g landwerlin linux intel com>

This is more or less a workaround about the way the tracker API
manages requests, especially with the bus backend, which can run into
file description starvation.

Signed-off-by: Lionel Landwerlin <lionel g landwerlin linux intel com>
---
 src/media/tracker/Makefile.am                 |    2 +
 src/media/tracker/grl-tracker-media-api.c     |  472 ++++++++++++-------------
 src/media/tracker/grl-tracker-media-notif.c   |    1 +
 src/media/tracker/grl-tracker-media-priv.h    |    1 -
 src/media/tracker/grl-tracker-media.c         |   13 +
 src/media/tracker/grl-tracker-media.h         |    3 +
 src/media/tracker/grl-tracker-metadata.c      |   19 +-
 src/media/tracker/grl-tracker-request-queue.c |  229 ++++++++++++
 src/media/tracker/grl-tracker-request-queue.h |   83 +++++
 src/media/tracker/grl-tracker.c               |    4 +
 src/media/tracker/grl-tracker.h               |    5 +
 11 files changed, 575 insertions(+), 257 deletions(-)
 create mode 100644 src/media/tracker/grl-tracker-request-queue.c
 create mode 100644 src/media/tracker/grl-tracker-request-queue.h

diff --git a/src/media/tracker/Makefile.am b/src/media/tracker/Makefile.am
index c4f87af..a0d5c29 100644
--- a/src/media/tracker/Makefile.am
+++ b/src/media/tracker/Makefile.am
@@ -36,6 +36,8 @@ libgrltracker_la_SOURCES = 		\
 	grl-tracker-metadata.c		\
 	grl-tracker-metadata.h		\
 	\
+	grl-tracker-request-queue.c	\
+	grl-tracker-request-queue.h	\
 	grl-tracker-utils.c		\
 	grl-tracker-utils.h
 
diff --git a/src/media/tracker/grl-tracker-media-api.c b/src/media/tracker/grl-tracker-media-api.c
index e64ee6c..b8fffe5 100644
--- a/src/media/tracker/grl-tracker-media-api.c
+++ b/src/media/tracker/grl-tracker-media-api.c
@@ -29,9 +29,11 @@
 #include <gio/gio.h>
 #include <tracker-sparql.h>
 
+#include "grl-tracker.h"
 #include "grl-tracker-media-api.h"
 #include "grl-tracker-media-cache.h"
 #include "grl-tracker-media-priv.h"
+#include "grl-tracker-request-queue.h"
 #include "grl-tracker-utils.h"
 
 /* --------- Logging  -------- */
@@ -143,56 +145,17 @@ GRL_LOG_DOMAIN_STATIC(tracker_media_result_log_domain);
 
 /**/
 
-struct OperationSpec {
-  GrlMediaSource         *source;
-  GrlTrackerMediaPriv    *priv;
-  guint                   operation_id;
-  GCancellable           *cancel_op;
-  const GList            *keys;
-  guint                   skip;
-  guint                   count;
-  guint                   current;
-  GrlMediaSourceResultCb  callback;
-  gpointer                user_data;
-  TrackerSparqlCursor    *cursor;
-};
-
 /**/
 
-static GrlKeyID grl_metadata_key_tracker_category;
+static GrlKeyID    grl_metadata_key_tracker_category;
+static GHashTable *grl_tracker_operations;
 
 /**/
 
-static struct OperationSpec *
-tracker_operation_initiate (GrlMediaSource *source,
-                            GrlTrackerMediaPriv *priv,
-                            guint operation_id)
-{
-  struct OperationSpec *os = g_slice_new0 (struct OperationSpec);
-
-  os->source       = source;
-  os->priv         = priv;
-  os->operation_id = operation_id;
-  os->cancel_op    = g_cancellable_new ();
 
-  g_hash_table_insert (priv->operations, GSIZE_TO_POINTER (operation_id), os);
-
-  return os;
-}
-
-static void
-tracker_operation_terminate (struct OperationSpec *os)
-{
-  if (os == NULL)
-    return;
-
-  g_hash_table_remove (os->priv->operations,
-                       GSIZE_TO_POINTER (os->operation_id));
+/**/
 
-  g_object_unref (G_OBJECT (os->cursor));
-  g_object_unref (G_OBJECT (os->cancel_op));
-  g_slice_free (struct OperationSpec, os);
-}
+/**/
 
 static void
 fill_grilo_media_from_sparql (GrlTrackerMedia    *source,
@@ -263,143 +226,159 @@ fill_grilo_media_from_sparql (GrlTrackerMedia    *source,
   }
 }
 
-static void
-tracker_query_result_cb (GObject              *source_object,
-                         GAsyncResult         *result,
-                         struct OperationSpec *operation)
-{
-  gint         col;
-  const gchar *sparql_type;
-  GError      *tracker_error = NULL, *error = NULL;
-  GrlMedia    *media;
-
-  GRL_ODEBUG ("%s", __FUNCTION__);
-
-  if (g_cancellable_is_cancelled (operation->cancel_op)) {
-    GRL_ODEBUG ("\tOperation %u cancelled", operation->operation_id);
-    operation->callback (operation->source,
-                         operation->operation_id,
-                         NULL, 0,
-                         operation->user_data, NULL);
-    tracker_operation_terminate (operation);
-
-    return;
-  }
-
-  if (!tracker_sparql_cursor_next_finish (operation->cursor,
-                                          result,
-                                          &tracker_error)) {
-    if (tracker_error != NULL) {
-      GRL_WARNING ("\terror in parsing query id=%u : %s",
-                   operation->operation_id, tracker_error->message);
-
-      error = g_error_new (GRL_CORE_ERROR,
-                           GRL_CORE_ERROR_BROWSE_FAILED,
-                           "Failed to start browse/query action : %s",
-                           tracker_error->message);
-
-      operation->callback (operation->source,
-                           operation->operation_id,
-                           NULL, 0,
-                           operation->user_data, error);
-
-      g_error_free (error);
-      g_error_free (tracker_error);
-    } else {
-      GRL_ODEBUG ("\tend of parsing id=%u :)", operation->operation_id);
-
-      /* Only emit this last one if more result than expected */
-      if (operation->count > 1)
-        operation->callback (operation->source,
-                             operation->operation_id,
-                             NULL, 0,
-                             operation->user_data, NULL);
-    }
-
-    tracker_operation_terminate (operation);
-    return;
-  }
-
-  sparql_type = tracker_sparql_cursor_get_string (operation->cursor, 0, NULL);
-
-  GRL_ODEBUG ("\tParsing line %i of type %s", operation->current, sparql_type);
-
-  media = grl_tracker_build_grilo_media (sparql_type);
-
-  if (media != NULL) {
-    for (col = 1 ;
-         col < tracker_sparql_cursor_get_n_columns (operation->cursor) ;
-         col++) {
-      fill_grilo_media_from_sparql (GRL_TRACKER_MEDIA (operation->source),
-                                    media, operation->cursor, col);
-    }
-
-    operation->callback (operation->source,
-                         operation->operation_id,
-                         media,
-                         --operation->count,
-                         operation->user_data,
-                         NULL);
-  }
-
-  /* Schedule the next line to parse */
-  operation->current++;
-  if (operation->count < 1)
-    tracker_operation_terminate (operation);
-  else
-    tracker_sparql_cursor_next_async (operation->cursor, operation->cancel_op,
-                                      (GAsyncReadyCallback) tracker_query_result_cb,
-                                      (gpointer) operation);
-}
-
-static void
-tracker_query_cb (GObject              *source_object,
-                  GAsyncResult         *result,
-                  struct OperationSpec *operation)
-{
-  GError *tracker_error = NULL, *error = NULL;
-
-  GRL_ODEBUG ("%s", __FUNCTION__);
-
-  operation->cursor =
-    tracker_sparql_connection_query_finish (operation->priv->tracker_connection,
-                                            result, &tracker_error);
-
-  if (tracker_error) {
-    GRL_WARNING ("Could not execute sparql query id=%u: %s",
-                 operation->operation_id, tracker_error->message);
-
-    error = g_error_new (GRL_CORE_ERROR,
-			 GRL_CORE_ERROR_BROWSE_FAILED,
-			 "Failed to start browse/query action : %s",
-                         tracker_error->message);
-
-    operation->callback (operation->source, operation->operation_id, NULL, 0,
-                         operation->user_data, error);
-
-    g_error_free (tracker_error);
-    g_error_free (error);
-    tracker_operation_terminate (operation);
-
-    return;
+/* I can haz templatze ?? */
+#define TRACKER_QUERY_CB(spec_type,name)                             \
+                                                                     \
+  static void                                                           \
+  tracker_##name##_result_cb (GObject      *source_object,              \
+                              GAsyncResult *result,                     \
+                              GrlTrackerOp *os)                         \
+  {                                                                     \
+    gint         col;                                                   \
+    const gchar *sparql_type;                                           \
+    GError      *tracker_error = NULL, *error = NULL;                   \
+    GrlMedia    *media;                                                 \
+    spec_type   *spec =                                                 \
+      (spec_type *) os->data;                                           \
+                                                                        \
+    GRL_ODEBUG ("%s", __FUNCTION__);                                    \
+                                                                        \
+    if (g_cancellable_is_cancelled (os->cancel)) {                      \
+      GRL_ODEBUG ("\tOperation %u cancelled", spec->name##_id);         \
+      spec->callback (spec->source,                                     \
+                      spec->name##_id,                                  \
+                      NULL, 0,                                          \
+                      spec->user_data, NULL);                           \
+      grl_tracker_queue_done (grl_tracker_queue, os);                   \
+                                                                        \
+      return;                                                           \
+    }                                                                   \
+                                                                        \
+    if (!tracker_sparql_cursor_next_finish (os->cursor,                 \
+                                            result,                     \
+                                            &tracker_error)) {          \
+      if (tracker_error != NULL) {                                      \
+        GRL_WARNING ("\terror in parsing query id=%u : %s",             \
+                     spec->name##_id, tracker_error->message);          \
+                                                                        \
+        error = g_error_new (GRL_CORE_ERROR,                            \
+                             GRL_CORE_ERROR_BROWSE_FAILED,              \
+                             "Failed to start query action : %s",       \
+                             tracker_error->message);                   \
+                                                                        \
+        spec->callback (spec->source,                                   \
+                        spec->name##_id,                                \
+                        NULL, 0,                                        \
+                        spec->user_data, error);                        \
+                                                                        \
+        g_error_free (error);                                           \
+        g_error_free (tracker_error);                                   \
+      } else {                                                          \
+        GRL_ODEBUG ("\tend of parsing id=%u :)", spec->name##_id);      \
+                                                                        \
+        /* Only emit this last one if more result than expected */      \
+        if (os->count > 1)                                              \
+          spec->callback (spec->source,                                 \
+                          spec->name##_id,                              \
+                          NULL, 0,                                      \
+                          spec->user_data, NULL);                       \
+      }                                                                 \
+                                                                        \
+      grl_tracker_queue_done (grl_tracker_queue, os);                   \
+      return;                                                           \
+    }                                                                   \
+                                                                        \
+    sparql_type = tracker_sparql_cursor_get_string (os->cursor,         \
+                                                    0,                  \
+                                                    NULL);              \
+                                                                        \
+    GRL_ODEBUG ("\tParsing line %i of type %s",                         \
+                os->current, sparql_type);                              \
+                                                                        \
+    media = grl_tracker_build_grilo_media (sparql_type);                \
+                                                                        \
+    if (media != NULL) {                                                \
+      for (col = 1 ;                                                    \
+           col < tracker_sparql_cursor_get_n_columns (os->cursor) ;     \
+           col++) {                                                     \
+        fill_grilo_media_from_sparql (GRL_TRACKER_MEDIA (spec->source), \
+                                      media, os->cursor, col);          \
+      }                                                                 \
+                                                                        \
+      spec->callback (spec->source,                                     \
+                      spec->name##_id,                                  \
+                      media,                                            \
+                      --os->count,                                      \
+                      spec->user_data,                                  \
+                      NULL);                                            \
+    }                                                                   \
+                                                                        \
+    /* Schedule the next line to parse */                               \
+    os->current++;                                                      \
+    if (os->count < 1)                                                  \
+      grl_tracker_queue_done (grl_tracker_queue, os);                   \
+    else                                                                \
+      tracker_sparql_cursor_next_async (os->cursor, os->cancel,         \
+                                        (GAsyncReadyCallback) tracker_##name##_result_cb, \
+                                        (gpointer) os);                 \
+  }                                                                     \
+                                                                        \
+  static void                                                           \
+  tracker_##name##_cb (GObject      *source_object,                     \
+                       GAsyncResult *result,                            \
+                       GrlTrackerOp *os)                                \
+  {                                                                     \
+    GError *tracker_error = NULL, *error = NULL;                        \
+    spec_type *spec = (spec_type *) os->data;                           \
+    TrackerSparqlConnection *connection =                               \
+      grl_tracker_media_get_tracker_connection (GRL_TRACKER_MEDIA (spec->source)); \
+                                                                        \
+    GRL_ODEBUG ("%s", __FUNCTION__);                                    \
+                                                                        \
+    os->cursor =                                                        \
+      tracker_sparql_connection_query_finish (connection,               \
+                                              result, &tracker_error);  \
+                                                                        \
+    if (tracker_error) {                                                \
+      GRL_WARNING ("Could not execute sparql query id=%u: %s",          \
+                   spec->name##_id, tracker_error->message);            \
+                                                                        \
+      error = g_error_new (GRL_CORE_ERROR,                              \
+                           GRL_CORE_ERROR_BROWSE_FAILED,                \
+                           "Failed to start query action : %s",         \
+                           tracker_error->message);                     \
+                                                                        \
+      spec->callback (spec->source, spec->name##_id, NULL, 0,           \
+                      spec->user_data, error);                          \
+                                                                        \
+      g_error_free (tracker_error);                                     \
+      g_error_free (error);                                             \
+      grl_tracker_queue_done (grl_tracker_queue, os);                   \
+                                                                        \
+      return;                                                           \
+    }                                                                   \
+                                                                        \
+    /* Start parsing results */                                         \
+    os->current = 0;                                                    \
+    tracker_sparql_cursor_next_async (os->cursor, NULL,                 \
+                                      (GAsyncReadyCallback) tracker_##name##_result_cb, \
+                                      (gpointer) os);                   \
   }
 
-  /* Start parsing results */
-  operation->current = 0;
-  tracker_sparql_cursor_next_async (operation->cursor, NULL,
-                                    (GAsyncReadyCallback) tracker_query_result_cb,
-                                    (gpointer) operation);
-}
+TRACKER_QUERY_CB(GrlMediaSourceQuerySpec, query)
+TRACKER_QUERY_CB(GrlMediaSourceBrowseSpec, browse)
+TRACKER_QUERY_CB(GrlMediaSourceSearchSpec, search)
 
 static void
-tracker_metadata_cb (GObject                    *source_object,
-                     GAsyncResult               *result,
-                     GrlMediaSourceMetadataSpec *ms)
+tracker_metadata_cb (GObject      *source_object,
+                     GAsyncResult *result,
+                     GrlTrackerOp *os)
 {
-  GrlTrackerMediaPriv *priv = GRL_TRACKER_MEDIA_GET_PRIVATE (ms->source);
-  gint                  col;
-  GError               *tracker_error = NULL, *error = NULL;
-  TrackerSparqlCursor  *cursor;
+  GrlMediaSourceMetadataSpec *ms            = (GrlMediaSourceMetadataSpec *) os->data;
+  GrlTrackerMediaPriv        *priv          = GRL_TRACKER_MEDIA_GET_PRIVATE (ms->source);
+  gint                        col;
+  GError                     *tracker_error = NULL, *error = NULL;
+  TrackerSparqlCursor        *cursor;
 
   GRL_ODEBUG ("%s", __FUNCTION__);
 
@@ -437,13 +416,17 @@ tracker_metadata_cb (GObject                    *source_object,
  end_operation:
   if (cursor)
     g_object_unref (G_OBJECT (cursor));
+
+  grl_tracker_queue_done (grl_tracker_queue, os);
 }
 
 static void
-tracker_set_metadata_cb (GObject                          *source_object,
-                         GAsyncResult                     *result,
-                         GrlMetadataSourceSetMetadataSpec *sms)
+tracker_set_metadata_cb (GObject      *source_object,
+                         GAsyncResult *result,
+                         GrlTrackerOp *os)
 {
+  GrlMetadataSourceSetMetadataSpec *sms =
+    (GrlMetadataSourceSetMetadataSpec *) os->data;
   GrlTrackerMediaPriv *priv = GRL_TRACKER_MEDIA_GET_PRIVATE (sms->source);
   GError *tracker_error = NULL, *error = NULL;
 
@@ -467,6 +450,8 @@ tracker_set_metadata_cb (GObject                          *source_object,
   } else {
     sms->callback (sms->source, sms->media, NULL, sms->user_data, error);
   }
+
+  grl_tracker_queue_done (grl_tracker_queue, os);
 }
 
 /**/
@@ -565,7 +550,7 @@ grl_tracker_media_query (GrlMediaSource *source,
   gchar                *constraint;
   gchar                *sparql_final;
   gchar                *sparql_select;
-  struct OperationSpec *os;
+  GrlTrackerOp         *os;
 
   GRL_IDEBUG ("%s: id=%u", __FUNCTION__, qs->query_id);
 
@@ -596,18 +581,19 @@ grl_tracker_media_query (GrlMediaSource *source,
 
   GRL_IDEBUG ("\tselect : '%s'", qs->query);
 
-  os = tracker_operation_initiate (source, priv, qs->query_id);
-  os->keys         = qs->keys;
-  os->skip         = qs->skip;
-  os->count        = qs->count;
-  os->callback     = qs->callback;
-  os->user_data    = qs->user_data;
+  os = grl_tracker_op_initiate_query (qs->query_id,
+                                      g_strdup (qs->query),
+                                      (GAsyncReadyCallback) tracker_query_cb,
+                                      qs);
+
+  os->keys  = qs->keys;
+  os->skip  = qs->skip;
+  os->count = qs->count;
+  os->data  = qs;
+  /* os->cb.sr     = qs->callback; */
+  /* os->user_data = qs->user_data; */
 
-  tracker_sparql_connection_query_async (priv->tracker_connection,
-                                         qs->query,
-                                         os->cancel_op,
-                                         (GAsyncReadyCallback) tracker_query_cb,
-                                         os);
+  grl_tracker_queue_push (grl_tracker_queue, os);
 
   return;
 
@@ -620,8 +606,9 @@ void
 grl_tracker_media_metadata (GrlMediaSource *source,
                             GrlMediaSourceMetadataSpec *ms)
 {
-  GrlTrackerMediaPriv *priv = GRL_TRACKER_MEDIA_GET_PRIVATE (source);
-  gchar                *constraint = NULL, *sparql_select, *sparql_final;
+  GrlTrackerMediaPriv *priv       = GRL_TRACKER_MEDIA_GET_PRIVATE (source);
+  gchar               *constraint = NULL, *sparql_select, *sparql_final;
+  GrlTrackerOp        *os;
 
   GRL_IDEBUG ("%s: id=%i", __FUNCTION__, ms->metadata_id);
 
@@ -643,28 +630,28 @@ grl_tracker_media_metadata (GrlMediaSource *source,
 
   GRL_IDEBUG ("\tselect: '%s'", sparql_final);
 
-  tracker_sparql_connection_query_async (priv->tracker_connection,
-                                         sparql_final,
-                                         NULL,
+  os = grl_tracker_op_initiate_metadata (sparql_final,
                                          (GAsyncReadyCallback) tracker_metadata_cb,
                                          ms);
+  os->keys = ms->keys;
+
+  grl_tracker_queue_push (grl_tracker_queue, os);
 
   if (constraint != NULL)
     g_free (constraint);
   if (sparql_select != NULL)
     g_free (sparql_select);
-  if (sparql_final != NULL)
-    g_free (sparql_final);
 }
 
 void
 grl_tracker_media_set_metadata (GrlMetadataSource *source,
                                 GrlMetadataSourceSetMetadataSpec *sms)
 {
-  GrlTrackerMediaPriv *priv = GRL_TRACKER_MEDIA_GET_PRIVATE (source);
+  /* GrlTrackerMediaPriv *priv = GRL_TRACKER_MEDIA_GET_PRIVATE (source); */
   gchar *sparql_delete, *sparql_cdelete, *sparql_insert, *sparql_final;
   const gchar *urn = grl_data_get_string (GRL_DATA (sms->media),
                                           grl_metadata_key_tracker_urn);
+  GrlTrackerOp *os;
 
   GRL_IDEBUG ("%s: urn=%s", G_STRFUNC, urn);
 
@@ -676,19 +663,18 @@ grl_tracker_media_set_metadata (GrlMetadataSource *source,
                                   urn, sparql_cdelete,
                                   urn, sparql_insert);
 
+  os = grl_tracker_op_initiate_set_metadata (sparql_final,
+                                             (GAsyncReadyCallback) tracker_set_metadata_cb,
+                                             sms);
+  os->keys = sms->keys;
+
   GRL_IDEBUG ("\trequest: '%s'", sparql_final);
 
-  tracker_sparql_connection_update_async (priv->tracker_connection,
-                                          sparql_final,
-                                          G_PRIORITY_DEFAULT,
-                                          NULL,
-                                          (GAsyncReadyCallback) tracker_set_metadata_cb,
-                                          sms);
+  grl_tracker_queue_push (grl_tracker_queue, os);
 
   g_free (sparql_delete);
   g_free (sparql_cdelete);
   g_free (sparql_insert);
-  g_free (sparql_final);
 }
 
 void
@@ -698,7 +684,7 @@ grl_tracker_media_search (GrlMediaSource *source, GrlMediaSourceSearchSpec *ss)
   gchar                *constraint;
   gchar                *sparql_select;
   gchar                *sparql_final;
-  struct OperationSpec *os;
+  GrlTrackerOp         *os;
 
   GRL_IDEBUG ("%s: id=%u", __FUNCTION__, ss->search_id);
 
@@ -715,22 +701,18 @@ grl_tracker_media_search (GrlMediaSource *source, GrlMediaSourceSearchSpec *ss)
 
   GRL_IDEBUG ("\tselect: '%s'", sparql_final);
 
-  os = tracker_operation_initiate (source, priv, ss->search_id);
-  os->keys         = ss->keys;
-  os->skip         = ss->skip;
-  os->count        = ss->count;
-  os->callback     = ss->callback;
-  os->user_data    = ss->user_data;
+  os = grl_tracker_op_initiate_query (ss->search_id,
+                                      sparql_final,
+                                      (GAsyncReadyCallback) tracker_search_cb,
+                                      ss);
+  os->keys  = ss->keys;
+  os->skip  = ss->skip;
+  os->count = ss->count;
 
-  tracker_sparql_connection_query_async (priv->tracker_connection,
-                                         sparql_final,
-                                         os->cancel_op,
-                                         (GAsyncReadyCallback) tracker_query_cb,
-                                         os);
+  grl_tracker_queue_push (grl_tracker_queue, os);
 
   g_free (constraint);
   g_free (sparql_select);
-  g_free (sparql_final);
 }
 
 static void
@@ -741,7 +723,7 @@ grl_tracker_media_browse_category (GrlMediaSource *source,
   gchar                *constraint;
   gchar                *sparql_select;
   gchar                *sparql_final;
-  struct OperationSpec *os;
+  GrlTrackerOp         *os;
   GrlMedia             *media;
   const gchar          *category;
 
@@ -794,22 +776,18 @@ grl_tracker_media_browse_category (GrlMediaSource *source,
 
   GRL_IDEBUG ("\tselect: '%s'", sparql_final);
 
-  os = tracker_operation_initiate (source, priv, bs->browse_id);
-  os->keys         = bs->keys;
-  os->skip         = bs->skip;
-  os->count        = bs->count;
-  os->callback     = bs->callback;
-  os->user_data    = bs->user_data;
+  os = grl_tracker_op_initiate_query (bs->browse_id,
+                                      sparql_final,
+                                      (GAsyncReadyCallback) tracker_browse_cb,
+                                      bs);
+  os->keys  = bs->keys;
+  os->skip  = bs->skip;
+  os->count = bs->count;
 
-  tracker_sparql_connection_query_async (priv->tracker_connection,
-                                         sparql_final,
-                                         os->cancel_op,
-                                         (GAsyncReadyCallback) tracker_query_cb,
-                                         os);
+  grl_tracker_queue_push (grl_tracker_queue, os);
 
   g_free (constraint);
   g_free (sparql_select);
-  g_free (sparql_final);
 }
 
 static void
@@ -820,7 +798,7 @@ grl_tracker_media_browse_filesystem (GrlMediaSource *source,
   gchar                *constraint;
   gchar                *sparql_select;
   gchar                *sparql_final;
-  struct OperationSpec *os;
+  GrlTrackerOp         *os;
 
   GRL_IDEBUG ("%s: id=%u", __FUNCTION__, bs->browse_id);
 
@@ -844,22 +822,18 @@ grl_tracker_media_browse_filesystem (GrlMediaSource *source,
 
   GRL_IDEBUG ("\tselect: '%s'", sparql_final);
 
-  os = tracker_operation_initiate (source, priv, bs->browse_id);
-  os->keys         = bs->keys;
-  os->skip         = bs->skip;
-  os->count        = bs->count;
-  os->callback     = bs->callback;
-  os->user_data    = bs->user_data;
+  os = grl_tracker_op_initiate_query (bs->browse_id,
+                                      sparql_final,
+                                      (GAsyncReadyCallback) tracker_browse_cb,
+                                      bs);
+  os->keys  = bs->keys;
+  os->skip  = bs->skip;
+  os->count = bs->count;
 
-  tracker_sparql_connection_query_async (priv->tracker_connection,
-                                         sparql_final,
-                                         os->cancel_op,
-                                         (GAsyncReadyCallback) tracker_query_cb,
-                                         os);
+  grl_tracker_queue_push (grl_tracker_queue, os);
 
   g_free (constraint);
   g_free (sparql_select);
-  g_free (sparql_final);
 }
 
 void
@@ -875,15 +849,15 @@ grl_tracker_media_browse (GrlMediaSource *source,
 void
 grl_tracker_media_cancel (GrlMediaSource *source, guint operation_id)
 {
-  GrlTrackerMediaPriv *priv = GRL_TRACKER_MEDIA_GET_PRIVATE (source);
-  struct OperationSpec *os;
+  GrlTrackerOp *os;
 
   GRL_IDEBUG ("%s: id=%u", __FUNCTION__, operation_id);
 
-  os = g_hash_table_lookup (priv->operations, GSIZE_TO_POINTER (operation_id));
+  os = g_hash_table_lookup (grl_tracker_operations,
+                            GSIZE_TO_POINTER (operation_id));
 
   if (os != NULL)
-    g_cancellable_cancel (os->cancel_op);
+    grl_tracker_queue_cancel (grl_tracker_queue, os);
 }
 
 gboolean
@@ -919,6 +893,8 @@ grl_tracker_media_init_requests (void)
                                                                     G_PARAM_READWRITE),
                                                NULL);
 
+  grl_tracker_operations = g_hash_table_new (g_direct_hash, g_direct_equal);
+
   GRL_LOG_DOMAIN_INIT (tracker_media_request_log_domain,
                        "tracker-media-request");
   GRL_LOG_DOMAIN_INIT (tracker_media_result_log_domain,
diff --git a/src/media/tracker/grl-tracker-media-notif.c b/src/media/tracker/grl-tracker-media-notif.c
index 8ed574b..37d3b06 100644
--- a/src/media/tracker/grl-tracker-media-notif.c
+++ b/src/media/tracker/grl-tracker-media-notif.c
@@ -24,6 +24,7 @@
 
 #include <tracker-sparql.h>
 
+#include "grl-tracker.h"
 #include "grl-tracker-media-notif.h"
 #include "grl-tracker-media-priv.h"
 #include "grl-tracker-utils.h"
diff --git a/src/media/tracker/grl-tracker-media-priv.h b/src/media/tracker/grl-tracker-media-priv.h
index a1210fc..6d6d13b 100644
--- a/src/media/tracker/grl-tracker-media-priv.h
+++ b/src/media/tracker/grl-tracker-media-priv.h
@@ -70,7 +70,6 @@ struct _GrlTrackerMediaPriv {
 
 /**/
 
-extern TrackerSparqlConnection *grl_tracker_connection;
 extern const GrlPluginInfo *grl_tracker_plugin;
 
 /* shared data across  */
diff --git a/src/media/tracker/grl-tracker-media.c b/src/media/tracker/grl-tracker-media.c
index 4118b95..84dd299 100644
--- a/src/media/tracker/grl-tracker-media.c
+++ b/src/media/tracker/grl-tracker-media.c
@@ -31,6 +31,7 @@
 #include <string.h>
 #include <tracker-sparql.h>
 
+#include "grl-tracker.h"
 #include "grl-tracker-media.h"
 #include "grl-tracker-media-priv.h"
 #include "grl-tracker-media-api.h"
@@ -195,6 +196,18 @@ grl_tracker_media_get_tracker_source (GrlTrackerMedia *source)
   return priv->tracker_datasource;
 }
 
+TrackerSparqlConnection *
+grl_tracker_media_get_tracker_connection (GrlTrackerMedia *source)
+{
+  GrlTrackerMediaPriv *priv;
+
+  g_return_val_if_fail (GRL_IS_TRACKER_MEDIA (source), NULL);
+
+  priv = source->priv;
+
+  return priv->tracker_connection;
+}
+
 /* =================== TrackerMedia Plugin  =============== */
 
 void
diff --git a/src/media/tracker/grl-tracker-media.h b/src/media/tracker/grl-tracker-media.h
index 0ca6a9d..78e0fad 100644
--- a/src/media/tracker/grl-tracker-media.h
+++ b/src/media/tracker/grl-tracker-media.h
@@ -26,6 +26,7 @@
 #define _GRL_TRACKER_MEDIA_H_
 
 #include <grilo.h>
+#include <tracker-sparql.h>
 
 #define GRL_TRACKER_MEDIA_TYPE                  \
   (grl_tracker_media_get_type ())
@@ -79,6 +80,8 @@ gboolean grl_tracker_media_can_notify (GrlTrackerMedia *source);
 
 const gchar *grl_tracker_media_get_tracker_source (GrlTrackerMedia *source);
 
+TrackerSparqlConnection *grl_tracker_media_get_tracker_connection (GrlTrackerMedia *source);
+
 /**/
 
 void grl_tracker_media_sources_init (void);
diff --git a/src/media/tracker/grl-tracker-metadata.c b/src/media/tracker/grl-tracker-metadata.c
index 6d255a9..0ba6a33 100644
--- a/src/media/tracker/grl-tracker-metadata.c
+++ b/src/media/tracker/grl-tracker-metadata.c
@@ -24,6 +24,7 @@
 
 #include <tracker-sparql.h>
 
+#include "grl-tracker.h"
 #include "grl-tracker-metadata.h"
 #include "grl-tracker-utils.h"
 #include "grl-tracker-media.h"
@@ -242,10 +243,11 @@ fill_grilo_media_from_sparql (GrlMedia            *media,
 }
 
 static void
-tracker_resolve_cb (GObject                      *source_object,
-                    GAsyncResult                 *result,
-                    GrlMetadataSourceResolveSpec *rs)
+tracker_resolve_cb (GObject      *source_object,
+                    GAsyncResult *result,
+                    GrlTrackerOp *os)
 {
+  GrlMetadataSourceResolveSpec *rs = (GrlMetadataSourceResolveSpec *) os->data;
   GrlTrackerMetadataPriv *priv = GRL_TRACKER_METADATA_GET_PRIVATE (rs->source);
   gint                  col;
   GError               *tracker_error = NULL, *error = NULL;
@@ -288,6 +290,8 @@ tracker_resolve_cb (GObject                      *source_object,
  end_operation:
   if (cursor)
     g_object_unref (G_OBJECT (cursor));
+
+  grl_tracker_queue_done (grl_tracker_queue, os);
 }
 
 
@@ -321,9 +325,9 @@ static void
 grl_tracker_metadata_resolve (GrlMetadataSource            *source,
                               GrlMetadataSourceResolveSpec *rs)
 {
-  GrlTrackerMetadataPriv *priv = GRL_TRACKER_METADATA_GET_PRIVATE (source);
   const gchar *url = grl_media_get_url (rs->media);
   gchar *sparql_select, *sparql_final;
+  GrlTrackerOp *os;
 
   GRL_IDEBUG ("%s", __FUNCTION__);
 
@@ -337,14 +341,13 @@ grl_tracker_metadata_resolve (GrlMetadataSource            *source,
 
   GRL_IDEBUG ("\trequest: '%s'", sparql_final);
 
-  tracker_sparql_connection_query_async (priv->tracker_connection,
-                                         sparql_final,
-                                         NULL,
+  os = grl_tracker_op_initiate_metadata (sparql_final,
                                          (GAsyncReadyCallback) tracker_resolve_cb,
                                          rs);
 
+  grl_tracker_queue_push (grl_tracker_queue, os);
+
   g_free (sparql_select);
-  g_free (sparql_final);
 }
 
 /* =================== TrackerMedia Plugin  =============== */
diff --git a/src/media/tracker/grl-tracker-request-queue.c b/src/media/tracker/grl-tracker-request-queue.c
new file mode 100644
index 0000000..0805f02
--- /dev/null
+++ b/src/media/tracker/grl-tracker-request-queue.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * Contact: Iago Toral Quiroga <itoral igalia com>
+ *
+ * Authors: Lionel Landwerlin <lionel g landwerlin linux intel com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include "grl-tracker.h"
+#include "grl-tracker-request-queue.h"
+
+/**/
+
+struct _GrlTrackerQueue {
+  GList      *head;
+  GList      *tail;
+  GHashTable *operations;
+  GHashTable *operations_ids;
+};
+
+/**/
+
+static void
+grl_tracker_op_terminate (GrlTrackerOp *os)
+{
+  if (os == NULL)
+    return;
+
+  if (os->cursor)
+    g_object_unref (os->cursor);
+
+  g_object_unref (os->cancel);
+  g_free (os->request);
+
+  g_slice_free (GrlTrackerOp, os);
+}
+
+static GrlTrackerOp *
+grl_tracker_op_initiate (gchar               *request,
+                         GAsyncReadyCallback  callback,
+                         gpointer             data)
+{
+  GrlTrackerOp *os = g_slice_new0 (GrlTrackerOp);
+
+  os->request  = request;
+  os->callback = callback;
+  os->data     = data;
+  os->cancel   = g_cancellable_new ();
+
+  return os;
+}
+
+GrlTrackerOp *
+grl_tracker_op_initiate_query (guint                operation_id,
+                               gchar               *request,
+                               GAsyncReadyCallback  callback,
+                               gpointer             data)
+{
+  GrlTrackerOp *os = grl_tracker_op_initiate (request,
+                                              callback,
+                                              data);
+
+  os->type         = GRL_TRACKER_OP_TYPE_QUERY;
+  os->operation_id = operation_id;
+
+  /* g_hash_table_insert (grl_tracker_operations, */
+  /*                      GSIZE_TO_POINTER (operation_id), os); */
+
+  return os;
+}
+
+GrlTrackerOp *
+grl_tracker_op_initiate_metadata (gchar               *request,
+                                  GAsyncReadyCallback  callback,
+                                  gpointer             data)
+{
+  GrlTrackerOp *os = grl_tracker_op_initiate (request,
+                                              callback,
+                                              data);
+
+  os->type = GRL_TRACKER_OP_TYPE_QUERY;
+
+  return os;
+}
+
+GrlTrackerOp *
+grl_tracker_op_initiate_set_metadata (gchar               *request,
+                                      GAsyncReadyCallback  callback,
+                                      gpointer             data)
+{
+  GrlTrackerOp *os = grl_tracker_op_initiate (request,
+                                              callback,
+                                              data);
+
+  os->type = GRL_TRACKER_OP_TYPE_UPDATE;
+
+  return os;
+}
+
+static void
+grl_tracker_op_start (GrlTrackerOp *os)
+{
+  switch (os->type) {
+  case GRL_TRACKER_OP_TYPE_QUERY:
+    tracker_sparql_connection_query_async (grl_tracker_connection,
+                                           os->request,
+                                           NULL,
+                                           os->callback,
+                                           os);
+    break;
+
+  case GRL_TRACKER_OP_TYPE_UPDATE:
+    tracker_sparql_connection_update_async (grl_tracker_connection,
+                                            os->request,
+                                            G_PRIORITY_DEFAULT,
+                                            NULL,
+                                            os->callback,
+                                            os);
+    break;
+
+  default:
+    g_assert_not_reached();
+    break;
+  }
+}
+
+/**/
+
+GrlTrackerQueue *
+grl_tracker_queue_new (void)
+{
+  GrlTrackerQueue *queue = g_new0 (GrlTrackerQueue, 1);
+
+  queue->operations     = g_hash_table_new (g_direct_hash, g_direct_equal);
+  queue->operations_ids = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+  return queue;
+}
+
+void
+grl_tracker_queue_push (GrlTrackerQueue *queue,
+                        GrlTrackerOp    *os)
+{
+  gboolean first = FALSE;
+
+  queue->tail = g_list_append (queue->tail, os);
+  if (queue->tail->next)
+    queue->tail = queue->tail->next;
+  else {
+    queue->head = queue->tail;
+    first = TRUE;
+  }
+
+  g_assert (queue->tail->next == NULL);
+
+  g_hash_table_insert (queue->operations, os, queue->tail);
+  if (os->operation_id != 0)
+    g_hash_table_insert (queue->operations_ids,
+                         GSIZE_TO_POINTER (os->operation_id), os);
+
+  if (first)
+    grl_tracker_op_start (os);
+}
+
+void
+grl_tracker_queue_cancel (GrlTrackerQueue *queue,
+                          GrlTrackerOp    *os)
+{
+  GList *item = g_hash_table_lookup (queue->operations, os);
+
+  if (!item)
+    return;
+
+  g_cancellable_cancel (os->cancel);
+
+  g_hash_table_remove (queue->operations, os);
+  if (os->operation_id != 0)
+    g_hash_table_remove (queue->operations_ids,
+                         GSIZE_TO_POINTER (os->operation_id));
+
+  if (item == queue->head) {
+    queue->head = queue->head->next;
+  }
+  if (item == queue->tail) {
+    queue->tail = queue->tail->prev;
+  }
+
+  if (item->prev)
+    item->prev->next = item->next;
+  if (item->next)
+    item->next->prev = item->prev;
+
+  item->next = NULL;
+  item->prev = NULL;
+  g_list_free (item);
+}
+
+void
+grl_tracker_queue_done (GrlTrackerQueue *queue,
+                        GrlTrackerOp    *os)
+{
+  GrlTrackerOp *next_os;
+
+  grl_tracker_queue_cancel (queue, os);
+  grl_tracker_op_terminate (os);
+
+  if (!queue->head)
+    return;
+
+  next_os = queue->head->data;
+
+  grl_tracker_op_start (next_os);
+}
diff --git a/src/media/tracker/grl-tracker-request-queue.h b/src/media/tracker/grl-tracker-request-queue.h
new file mode 100644
index 0000000..ee61908
--- /dev/null
+++ b/src/media/tracker/grl-tracker-request-queue.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2011 Intel Corporation.
+ *
+ * Contact: Iago Toral Quiroga <itoral igalia com>
+ *
+ * Authors: Lionel Landwerlin <lionel g landwerlin linux intel com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef _GRL_TRACKER_REQUEST_QUEUE_H_
+#define _GRL_TRACKER_REQUEST_QUEUE_H_
+
+#include <grilo.h>
+#include <tracker-sparql.h>
+
+/**/
+
+typedef enum {
+  GRL_TRACKER_OP_TYPE_QUERY,
+  GRL_TRACKER_OP_TYPE_UPDATE,
+} GrlTrackerOpType;
+
+typedef struct {
+  GrlTrackerOpType         type;
+  GAsyncReadyCallback      callback;
+  GCancellable            *cancel;
+  TrackerSparqlConnection *connection;
+  gchar                   *request;
+  const GList             *keys;
+  gpointer                 data;
+
+  TrackerSparqlCursor *cursor;
+
+  guint operation_id;
+
+  guint skip;
+  guint count;
+  guint current;
+} GrlTrackerOp;
+
+typedef struct _GrlTrackerQueue GrlTrackerQueue;
+
+/**/
+
+GrlTrackerOp *grl_tracker_op_initiate_query (guint                operation_id,
+                                             gchar               *request,
+                                             GAsyncReadyCallback  callback,
+                                             gpointer             data);
+
+GrlTrackerOp *grl_tracker_op_initiate_metadata (gchar               *request,
+                                                GAsyncReadyCallback  callback,
+                                                gpointer             data);
+
+GrlTrackerOp *grl_tracker_op_initiate_set_metadata (gchar               *request,
+                                                    GAsyncReadyCallback  callback,
+                                                    gpointer             data);
+
+/**/
+
+GrlTrackerQueue *grl_tracker_queue_new (void);
+
+void grl_tracker_queue_push (GrlTrackerQueue *queue, GrlTrackerOp *os);
+
+void grl_tracker_queue_cancel (GrlTrackerQueue *queue, GrlTrackerOp *os);
+
+void grl_tracker_queue_done (GrlTrackerQueue *queue, GrlTrackerOp *os);
+
+#endif /* _GRL_TRACKER_REQUEST_QUEUE_H_ */
diff --git a/src/media/tracker/grl-tracker.c b/src/media/tracker/grl-tracker.c
index 8f9450f..097858f 100644
--- a/src/media/tracker/grl-tracker.c
+++ b/src/media/tracker/grl-tracker.c
@@ -36,6 +36,7 @@
 #include "grl-tracker-media-api.h"
 #include "grl-tracker-media-notif.h"
 #include "grl-tracker-metadata.h"
+#include "grl-tracker-request-queue.h"
 #include "grl-tracker-utils.h"
 
 /* --------- Logging  -------- */
@@ -76,6 +77,7 @@ gboolean grl_tracker_plugin_init (GrlPluginRegistry *registry,
 TrackerSparqlConnection *grl_tracker_connection = NULL;
 const GrlPluginInfo *grl_tracker_plugin;
 gboolean grl_tracker_upnp_present = FALSE;
+GrlTrackerQueue *grl_tracker_queue = NULL;
 
 /* tracker plugin config */
 gboolean grl_tracker_per_device_source = FALSE;
@@ -88,6 +90,8 @@ init_sources (void)
 {
   grl_tracker_setup_key_mappings ();
 
+  grl_tracker_queue = grl_tracker_queue_new ();
+
   if (grl_tracker_connection != NULL) {
     grl_tracker_media_dbus_start_watch ();
 
diff --git a/src/media/tracker/grl-tracker.h b/src/media/tracker/grl-tracker.h
index cc1dd28..6aacf09 100644
--- a/src/media/tracker/grl-tracker.h
+++ b/src/media/tracker/grl-tracker.h
@@ -25,8 +25,13 @@
 #ifndef _GRL_TRACKER_H_
 #define _GRL_TRACKER_H_
 
+#include "grl-tracker-request-queue.h"
+
 /* ---- Plugin information --- */
 
 #define GRL_TRACKER_PLUGIN_ID   TRACKER_PLUGIN_ID
 
+extern GrlTrackerQueue *grl_tracker_queue;
+extern TrackerSparqlConnection *grl_tracker_connection;
+
 #endif /* _GRL_TRACKER_H_ */
-- 
1.7.4.1



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