[Xfce4-commits] <tumbler:master> Rework the TumblerGroupScheduler code. Use a GList for error/ready URIs.

Jannis Pohlmann noreply at xfce.org
Tue Oct 6 20:54:11 CEST 2009


Updating branch refs/heads/master
         to bb8928cb7423a1634f444411d7dbc6e4ea0601ef (commit)
       from 437b6b40d0fce61358e1a0ed6ae83b1929a550fe (commit)

commit bb8928cb7423a1634f444411d7dbc6e4ea0601ef
Author: Jannis Pohlmann <jannis at xfce.org>
Date:   Tue Oct 6 20:51:29 2009 +0200

    Rework the TumblerGroupScheduler code. Use a GList for error/ready URIs.

 tumblerd/tumbler-group-scheduler.c |  274 +++++++++++++++++++++++-------------
 tumblerd/tumbler-group-scheduler.h |    5 +-
 2 files changed, 180 insertions(+), 99 deletions(-)

diff --git a/tumblerd/tumbler-group-scheduler.c b/tumblerd/tumbler-group-scheduler.c
index bbe4654..c128a11 100644
--- a/tumblerd/tumbler-group-scheduler.c
+++ b/tumblerd/tumbler-group-scheduler.c
@@ -1,6 +1,8 @@
 /* vi:set et ai sw=2 sts=2 ts=2: */
 /*-
- * Copyright (C) 2009, Nokia
+ * Copyright (c) 2009 Jannis Pohlmann <jannis at xfce.org>
+ * Copyright (c) 2009 Nokia,
+ *   written by Philip Van Hoof <philip at codeminded.be>
  *
  * This program is free software; you can redistribute it and/or 
  * modify it under the terms of the GNU General Public License as
@@ -16,8 +18,6 @@
  * License along with this program; if not, write to the Free 
  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  * Boston, MA 02110-1301, USA.
- *
- * Author: Philip Van Hoof <philip at codeminded.be>
  */
 
 #ifdef HAVE_CONFIG_H
@@ -35,6 +35,8 @@
 #include <tumblerd/tumbler-group-scheduler.h>
 #include <tumblerd/tumbler-scheduler.h>
 
+
+
 /* Property identifiers */
 enum
 {
@@ -42,6 +44,12 @@ enum
   PROP_NAME,
 };
 
+
+
+typedef struct _UriError UriError;
+
+
+
 static void tumbler_group_scheduler_iface_init        (TumblerSchedulerIface     *iface);
 static void tumbler_group_scheduler_finalize          (GObject                   *object);
 static void tumbler_group_scheduler_get_property      (GObject                   *object,
@@ -56,7 +64,7 @@ static void tumbler_group_scheduler_push              (TumblerScheduler
                                                        TumblerSchedulerRequest   *request);
 static void tumbler_group_scheduler_unqueue           (TumblerScheduler          *scheduler,
                                                        guint                      handle);
-static void tumbler_group_scheduler_finish_request    (TumblerGroupScheduler *scheduler,
+static void tumbler_group_scheduler_finish_request    (TumblerGroupScheduler     *scheduler,
                                                        TumblerSchedulerRequest   *request);
 static void tumbler_group_scheduler_unqueue_request   (TumblerSchedulerRequest   *request,
                                                        gpointer                   user_data);
@@ -66,10 +74,10 @@ static void tumbler_group_scheduler_thumbnailer_error (TumblerThumbnailer
                                                        const gchar               *failed_uri,
                                                        gint                       error_code,
                                                        const gchar               *message,
-                                                       GPtrArray   *errors);
+                                                       GList                    **uri_errors);
 static void tumbler_group_scheduler_thumbnailer_ready (TumblerThumbnailer        *thumbnailer,
                                                        const gchar               *uri,
-                                                       GPtrArray   *readies);
+                                                       GList                    **ready_uris);
 
 
 
@@ -86,9 +94,18 @@ struct _TumblerGroupScheduler
   GMutex      *mutex;
   GList       *requests;
   guint        group;
+
   gchar       *name;
 };
 
+struct _UriError
+{
+  guint  error_code;
+  gchar *message;
+  gchar *failed_uri;
+};
+
+
 
 
 G_LOCK_DEFINE (group_access_lock);
@@ -133,8 +150,8 @@ tumbler_group_scheduler_init (TumblerGroupScheduler *scheduler)
   scheduler->mutex = g_mutex_new ();
   scheduler->requests = NULL;
 
-  /* allocate a pool with max. 1 threads for requests */
-  scheduler->pool = g_thread_pool_new (tumbler_group_scheduler_thread,
+  /* allocate a pool with one thread for all requests */
+  scheduler->pool = g_thread_pool_new (tumbler_group_scheduler_thread, 
                                        scheduler, 1, TRUE, NULL);
 
 }
@@ -155,6 +172,7 @@ tumbler_group_scheduler_finalize (GObject *object)
   /* destroy the request list */
   g_list_free (scheduler->requests);
 
+  /* free the scheduler name */
   g_free (scheduler->name);
 
   /* destroy the mutex */
@@ -223,8 +241,7 @@ tumbler_group_scheduler_push (TumblerScheduler        *scheduler,
   tumbler_scheduler_take_request (scheduler, request);
 
   /* prepend the request to the request list */
-  group_scheduler->requests = 
-    g_list_prepend (group_scheduler->requests, request);
+  group_scheduler->requests = g_list_prepend (group_scheduler->requests, request);
 
   /* enqueue the request in the pool */
   g_thread_pool_push (group_scheduler->pool, request, NULL);
@@ -246,6 +263,7 @@ tumbler_group_scheduler_unqueue (TumblerScheduler *scheduler,
 
   g_mutex_lock (group_scheduler->mutex);
 
+  /* unqueue all requests (usually only one) with this handle */
   g_list_foreach (group_scheduler->requests, 
                   (GFunc) tumbler_group_scheduler_unqueue_request, 
                   GUINT_TO_POINTER (handle));
@@ -262,11 +280,13 @@ tumbler_group_scheduler_finish_request (TumblerGroupScheduler *scheduler,
   g_return_if_fail (TUMBLER_IS_GROUP_SCHEDULER (scheduler));
   g_return_if_fail (request != NULL);
 
+  /* emit a finished signal */
   g_signal_emit_by_name (scheduler, "finished", request->handle);
 
-  scheduler->requests = g_list_remove (scheduler->requests,
-                                       request);
+  /* remove the request from the request list */
+  scheduler->requests = g_list_remove (scheduler->requests, request);
 
+  /* destroy the request */
   tumbler_scheduler_request_free (request);
 }
 
@@ -281,43 +301,61 @@ tumbler_group_scheduler_unqueue_request (TumblerSchedulerRequest *request,
   g_return_if_fail (request != NULL);
   g_return_if_fail (handle != 0);
 
+  /* mark the request as unqueued if the handles match */
   if (request->handle == handle)
     request->unqueued = TRUE;
 }
 
-typedef struct {
-  guint error_code;
-  gchar *message, *failed_uri;
-} GroupError;
+
+
+static UriError *
+uri_error_new (void)
+{
+  UriError *error;
+
+  error = g_slice_new0 (UriError);
+  return error;
+}
+
+
 
 static void
-group_error_free (gpointer data, gpointer user_data)
+uri_error_free (UriError *error)
 {
-    GroupError *grp_error = data;
+  g_free (error->message);
+  g_free (error->failed_uri);
 
-    g_free (grp_error->message);
-    g_free (grp_error->failed_uri);
-    g_free (grp_error);
+  g_slice_free (UriError, error);
 }
 
+
+
 static void
 tumbler_group_scheduler_thread (gpointer data,
                                 gpointer user_data)
 {
-  TumblerGroupScheduler     *scheduler = user_data;
-  TumblerSchedulerRequest   *request = data;
-  TumblerFileInfo           *info;
-  const gchar              **uris;
-  gboolean                   outdated;
-  gboolean                   uri_needs_update;
-  guint64                    mtime;
-  GError                    *error = NULL;
-  GList                     *cached_uris = NULL;
-  GList                     *missing_uris = NULL;
-  GList                     *thumbnails;
-  GList                     *lp;
-  gint                       n;
-  GPtrArray                 *errors, *readies;
+  TumblerSchedulerRequest *request = data;
+  TumblerGroupScheduler   *scheduler = user_data;
+  TumblerFileInfo         *info;
+  const gchar            **uris;
+  const gchar            **failed_uris;
+  const gchar            **success_uris;
+  UriError                *uri_error;
+  gboolean                 outdated;
+  gboolean                 uri_needs_update;
+  GString                 *message;
+  guint64                  mtime;
+  GError                  *error = NULL;
+  GList                   *iter;
+  GList                   *uri_errors;
+  GList                   *ready_uris;
+  GList                   *cached_uris = NULL;
+  GList                   *missing_uris = NULL;
+  GList                   *thumbnails;
+  GList                   *lp;
+  guint                    n;
+  guint                    i;
+  gint                     error_code;
 
   g_return_if_fail (TUMBLER_IS_GROUP_SCHEDULER (scheduler));
   g_return_if_fail (request != NULL);
@@ -325,7 +363,6 @@ tumbler_group_scheduler_thread (gpointer data,
   /* notify others that we're starting to process this request */
   g_signal_emit_by_name (request->scheduler, "started", request->handle);
 
-
   /* finish the request if it was unqueued */
   if (request->unqueued)
     {
@@ -347,47 +384,59 @@ tumbler_group_scheduler_thread (gpointer data,
           return;
         }
 
+      /* create a file infor for the current URI */
       info = tumbler_file_info_new (request->uris[n]);
       uri_needs_update = FALSE;
 
       G_LOCK (group_access_lock);
 
+      /* try to load thumbnail information about the URI */
       if (tumbler_file_info_load (info, NULL, &error))
         {
+          /* check if we have a thumbnailer for the URI */
           if (request->thumbnailers[n] != NULL)
             {
+              /* compute the last modification time of the URI */
               mtime = tumbler_file_info_get_mtime (info);
 
+              /* get a list of all thumbnails for this URI */
               thumbnails = tumbler_file_info_get_thumbnails (info);
 
-              for (lp = thumbnails; 
-                   error == NULL && lp != NULL; 
-                   lp = lp->next)
+              /* iterate over them */
+              for (lp = thumbnails; error == NULL && lp != NULL; lp = lp->next)
                 {
+                  /* try to load the thumbnail information */
                   if (tumbler_thumbnail_load (lp->data, NULL, &error))
                     {
+                      /* check if the thumbnail needs an update */
                       outdated = tumbler_thumbnail_needs_update (lp->data, 
                                                                  request->uris[n],
                                                                  mtime);
 
+                      /* if at least one thumbnail is out of date, we need to 
+                       * regenerate thumbnails for the URI */
                       uri_needs_update = uri_needs_update || outdated;
                     }
                 }
             }
           else
             {
+              /* no thumbnailer for this URI, we need to emit an error */
               g_set_error (&error, TUMBLER_ERROR, TUMBLER_ERROR_NO_THUMBNAILER,
                            _("No thumbnailer available for \"%s\""), 
                            request->uris[n]);
             }
         }
 
+      /* release the file info */
       g_object_unref (info);
 
       G_UNLOCK (group_access_lock);
 
+      /* check if the URI is supported */
       if (error == NULL)
         {
+          /* put it in the right list depending on its thumbnail status */
           if (uri_needs_update)
             missing_uris = g_list_prepend (missing_uris, GINT_TO_POINTER (n));
           else
@@ -395,9 +444,9 @@ tumbler_group_scheduler_thread (gpointer data,
         }
       else
         {
+          /* emit an error for the URI */
           tumbler_scheduler_emit_uri_error (TUMBLER_SCHEDULER (scheduler), request,
                                             request->uris[n], error);
-
           g_clear_error (&error);
         }
     }
@@ -405,6 +454,7 @@ tumbler_group_scheduler_thread (gpointer data,
   /* check if we have any cached files */
   if (cached_uris != NULL)
     {
+      /* allocate a URI array and fill it with all cached URIs */
       uris = g_new0 (const gchar *, g_list_length (cached_uris) + 1);
       for (n = 0, lp = g_list_last (cached_uris); lp != NULL; lp = lp->prev, ++n)
         uris[n] = lp->data;
@@ -418,8 +468,10 @@ tumbler_group_scheduler_thread (gpointer data,
       g_free (uris);
     }
 
-  errors = g_ptr_array_new ();
-  readies = g_ptr_array_new ();
+  /* initialize lists for grouping failed URIs and URIs for which 
+   * thumbnails are ready */
+  uri_errors = NULL;
+  ready_uris = NULL;
 
   /* iterate over invalid/missing URI list */
   for (lp = g_list_last (missing_uris); lp != NULL; lp = lp->prev)
@@ -438,12 +490,12 @@ tumbler_group_scheduler_thread (gpointer data,
       /* connect to the error signal of the thumbnailer */
       g_signal_connect (request->thumbnailers[n], "error", 
                         G_CALLBACK (tumbler_group_scheduler_thumbnailer_error),
-                        errors);
+                        &uri_errors);
 
       /* connect to the ready signal of the thumbnailer */
       g_signal_connect (request->thumbnailers[n], "ready",
                         G_CALLBACK (tumbler_group_scheduler_thumbnailer_ready),
-                        readies);
+                        &ready_uris);
 
       /* tell the thumbnailer to generate the thumbnail */
       tumbler_thumbnailer_create (request->thumbnailers[n], request->uris[n], 
@@ -457,53 +509,81 @@ tumbler_group_scheduler_thread (gpointer data,
 
   g_mutex_lock (scheduler->mutex);
 
-  /* We put all the errors and readies together, to avoid DBus traffic */
+  /* We emit all the errors and ready signals together in order to 
+   * reduce the overall D-Bus traffic */
 
-  if (errors->len > 0) {
-    guint i, error_code;
-    GString *message = g_string_new ("");
-    GStrv failed_uris = (GStrv) g_malloc0 (sizeof (gchar *) * errors->len);
+  /* check if we have any failed URIs */
+  if (uri_errors != NULL)
+    {
+      /* allocate the failed URIs array */
+      failed_uris = g_new0 (const gchar *, g_list_length (uri_errors) + 1);
 
-    for (i = 0; i < errors->len; i++) {
-      GroupError *grp_error = g_ptr_array_index (errors, i);
+      /* allocate the grouped error message */
+      message = g_string_new ("");
 
-      if (i != 0) {
-        if (grp_error->message)
-          g_string_append_c (message, ' ');
-      } else
-        error_code = grp_error->error_code;
+      for (iter = uri_errors, n = 0; iter != NULL; iter = iter->next, ++n) 
+        {
+          uri_error = iter->data;
 
-      if (grp_error->message)
-        g_string_append (message, grp_error->message);
+          /* we use the error code of the first failed URI */
+          if (iter == uri_errors) 
+            error_code = uri_error->error_code;
 
-      failed_uris[i] = g_ptr_array_index (errors, i);
-    }
+          if (uri_error->message != NULL)
+            {
+              /* we concatenate error messages with a newline inbetween */
+              if (iter != uri_errors && iter->next != NULL)
+                g_string_append_c (message, '\n');
 
-    /* forward the error signal */
-    g_signal_emit_by_name (request->scheduler, "error", request->handle, 
-                           failed_uris, error_code, message->str);
+              /* append the current error message */
+              g_string_append (message, uri_error->message);
+            }
 
-    g_free (failed_uris);
-    g_string_free (message, TRUE);
-  }
+          /* fill the failed_uris array with URIs */
+          failed_uris[n] = uri_error->failed_uri;
+        }
 
-  g_ptr_array_foreach (errors, group_error_free, NULL);
-  g_ptr_array_free (errors, TRUE); 
+      /* NULL-terminate the failed URI array */
+      failed_uris[n] = NULL;
 
-  if (readies->len > 0) {
-    GStrv ready_uris = (GStrv) g_new0 (gchar*, readies->len);
-    guint i;
+      /* forward the error signal */
+      g_signal_emit_by_name (request->scheduler, "error", request->handle, 
+                             failed_uris, error_code, message->str);
 
-    for (i = 0; i < readies->len; i++)
-      ready_uris[i] = g_ptr_array_index (readies, i);
+      /* free the failed URIs array. Its contents are owned by the URI errors */
+      g_free (failed_uris);
 
-    g_signal_emit_by_name (request->scheduler, "ready", ready_uris);
+      /* free the error message */
+      g_string_free (message, TRUE);
+    }
+
+  /* free all URI errors and the error URI list */
+  g_list_foreach (uri_errors, (GFunc) uri_error_free, NULL);
+  g_list_free (uri_errors);
+
+  /* check if we have any successfully processed URIs */
+  if (ready_uris != NULL)
+    {
+      /* allocate a string array for successful URIs */
+      success_uris = g_new0 (const gchar *, g_list_length (ready_uris) + 1);
+
+      /* fill the array with all ready URIs */
+      for (iter = ready_uris, n = 0; iter != NULL; iter = iter->next, ++n)
+        success_uris[n] = iter->data;
 
-    g_free (ready_uris);
-  }
+      /* NULL-terminate the successful URI array */
+      success_uris[n] = NULL;
 
-  g_ptr_array_foreach (readies, (GFunc) g_free, NULL);
-  g_ptr_array_free (readies, TRUE); 
+      /* emit a grouped ready signal */
+      g_signal_emit_by_name (request->scheduler, "ready", success_uris);
+
+      /* free the success URI array. Its contents are owned by the ready URI list */
+      g_free (success_uris);
+    }
+
+  /* free the ready URIs */
+  g_list_foreach (ready_uris, (GFunc) g_free, NULL);
+  g_list_free (ready_uris); 
 
   /* notify others that we're finished processing the request */
   tumbler_group_scheduler_finish_request (scheduler, request);
@@ -514,39 +594,41 @@ tumbler_group_scheduler_thread (gpointer data,
 
 
 static void
-tumbler_group_scheduler_thumbnailer_error (TumblerThumbnailer      *thumbnailer,
-                                           const gchar              *failed_uri,
-                                           gint                      error_code,
-                                           const gchar              *message,
-                                           GPtrArray                *errors)
+tumbler_group_scheduler_thumbnailer_error (TumblerThumbnailer *thumbnailer,
+                                           const gchar        *failed_uri,
+                                           gint                error_code,
+                                           const gchar        *message,
+                                           GList             **uri_errors)
 {
-  GroupError *grp_error;
+  UriError *error;
 
   g_return_if_fail (TUMBLER_IS_THUMBNAILER (thumbnailer));
   g_return_if_fail (failed_uri != NULL);
+  g_return_if_fail (error_code < 0);
+  g_return_if_fail (uri_errors != NULL);
 
-  grp_error = g_new0 (GroupError, 1);
-
-  grp_error->error_code = error_code;
-  if (message) {
-    grp_error->message = g_strdup (message);
-  }
-  grp_error->failed_uri = g_strdup (failed_uri);
+  /* allocate a new URI error */
+  error = g_slice_new0 (UriError);
+  error->error_code = error_code;
+  error->message = g_strdup (message);
+  error->failed_uri = g_strdup (failed_uri);
 
-  g_ptr_array_add (errors, grp_error);
+  /* add the error to the list */
+  *uri_errors = g_list_prepend (*uri_errors, error);
 }
 
 
 
 static void
-tumbler_group_scheduler_thumbnailer_ready (TumblerThumbnailer      *thumbnailer,
-                                           const gchar              *uri,
-                                           GPtrArray                *readies)
+tumbler_group_scheduler_thumbnailer_ready (TumblerThumbnailer *thumbnailer,
+                                           const gchar        *uri,
+                                           GList             **ready_uris)
 {
   g_return_if_fail (TUMBLER_IS_THUMBNAILER (thumbnailer));
   g_return_if_fail (uri != NULL);
+  g_return_if_fail (ready_uris != NULL);
 
-  g_ptr_array_add (readies, g_strdup (uri));
+  *ready_uris = g_list_prepend (*ready_uris, g_strdup (uri));
 }
 
 
diff --git a/tumblerd/tumbler-group-scheduler.h b/tumblerd/tumbler-group-scheduler.h
index 741adec..dd36bda 100644
--- a/tumblerd/tumbler-group-scheduler.h
+++ b/tumblerd/tumbler-group-scheduler.h
@@ -1,6 +1,7 @@
 /* vi:set et ai sw=2 sts=2 ts=2: */
 /*-
- * Copyright (C) 2009, Nokia
+ * Copyright (C) 2009 Nokia,
+ *   written by Philip Van Hoof <philip at codeminded.be>
  *
  * This program is free software; you can redistribute it and/or 
  * modify it under the terms of the GNU General Public License as
@@ -16,8 +17,6 @@
  * License along with this program; if not, write to the Free 
  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  * Boston, MA 02110-1301, USA.
- *
- * Author: Philip Van Hoof <philip at codeminded.be>
  */
 
 #ifndef __TUMBLER_GROUP_SCHEDULER_H__



More information about the Xfce4-commits mailing list