[tracker-miners/wip/carlosg/speed-track: 8/22] libtracker-miner: Make TrackerCrawler API async




commit 4e933ec10951d6421feb54664feb72a74ab17e26
Author: Carlos Garnacho <carlosg gnome org>
Date:   Sat Oct 17 00:13:02 2020 +0200

    libtracker-miner: Make TrackerCrawler API async
    
    Instead of start/stop calls, and relying on signals. Make it an
    async API, with a cancellable and finish() call.

 src/libtracker-miner/tracker-crawler.c        | 367 ++++++++------------------
 src/libtracker-miner/tracker-crawler.h        |  30 ++-
 src/libtracker-miner/tracker-file-notifier.c  | 110 ++++----
 tests/libtracker-miner/tracker-crawler-test.c | 103 ++++----
 4 files changed, 224 insertions(+), 386 deletions(-)
---
diff --git a/src/libtracker-miner/tracker-crawler.c b/src/libtracker-miner/tracker-crawler.c
index 6b09e2c75..bb4f211a6 100644
--- a/src/libtracker-miner/tracker-crawler.c
+++ b/src/libtracker-miner/tracker-crawler.c
@@ -66,6 +66,8 @@ struct DirectoryProcessingData {
 };
 
 struct DirectoryRootInfo {
+       TrackerCrawler *crawler;
+       GTask *task;
        GFile *directory;
        GNode *tree;
 
@@ -75,6 +77,8 @@ struct DirectoryRootInfo {
 
        DataProviderData *dpd;
 
+       guint idle_id;
+
        /* Directory stats */
        guint directories_found;
        guint directories_ignored;
@@ -85,11 +89,6 @@ struct DirectoryRootInfo {
 struct TrackerCrawlerPrivate {
        TrackerDataProvider *data_provider;
 
-       /* Directories to crawl */
-       GQueue         *directories;
-
-       GCancellable   *cancellable;
-
        /* Idle handler for processing found data */
        guint           idle_id;
 
@@ -99,17 +98,6 @@ struct TrackerCrawlerPrivate {
        TrackerCrawlerCheckFunc check_func;
        gpointer check_func_data;
        GDestroyNotify check_func_destroy;
-
-       /* Status */
-       gboolean        is_running;
-       gboolean        is_finished;
-       gboolean        was_started;
-};
-
-enum {
-       DIRECTORY_CRAWLED,
-       FINISHED,
-       LAST_SIGNAL
 };
 
 enum {
@@ -135,8 +123,6 @@ static void     data_provider_end        (TrackerCrawler          *crawler,
                                           DirectoryRootInfo       *info);
 static void     directory_root_info_free (DirectoryRootInfo *info);
 
-
-static guint signals[LAST_SIGNAL] = { 0, };
 static GQuark file_info_quark = 0;
 
 G_DEFINE_TYPE_WITH_PRIVATE (TrackerCrawler, tracker_crawler, G_TYPE_OBJECT)
@@ -150,31 +136,6 @@ tracker_crawler_class_init (TrackerCrawlerClass *klass)
        object_class->get_property = crawler_get_property;
        object_class->finalize = crawler_finalize;
 
-       signals[DIRECTORY_CRAWLED] =
-               g_signal_new ("directory-crawled",
-                             G_TYPE_FROM_CLASS (klass),
-                             G_SIGNAL_RUN_LAST,
-                             G_STRUCT_OFFSET (TrackerCrawlerClass, directory_crawled),
-                             NULL, NULL,
-                             NULL,
-                             G_TYPE_NONE,
-                             6,
-                             G_TYPE_FILE,
-                             G_TYPE_POINTER,
-                             G_TYPE_UINT,
-                             G_TYPE_UINT,
-                             G_TYPE_UINT,
-                             G_TYPE_UINT);
-       signals[FINISHED] =
-               g_signal_new ("finished",
-                             G_TYPE_FROM_CLASS (klass),
-                             G_SIGNAL_RUN_LAST,
-                             G_STRUCT_OFFSET (TrackerCrawlerClass, finished),
-                             NULL, NULL,
-                             NULL,
-                             G_TYPE_NONE,
-                             1, G_TYPE_BOOLEAN);
-
        g_object_class_install_property (object_class,
                                         PROP_DATA_PROVIDER,
                                         g_param_spec_object ("data-provider",
@@ -191,10 +152,6 @@ tracker_crawler_class_init (TrackerCrawlerClass *klass)
 static void
 tracker_crawler_init (TrackerCrawler *object)
 {
-       TrackerCrawlerPrivate *priv;
-
-       priv = tracker_crawler_get_instance_private (TRACKER_CRAWLER (object));
-       priv->directories = g_queue_new ();
 }
 
 static void
@@ -248,18 +205,6 @@ crawler_finalize (GObject *object)
                priv->check_func_destroy (priv->check_func_data);
        }
 
-       if (priv->idle_id) {
-               g_source_remove (priv->idle_id);
-       }
-
-       if (priv->cancellable) {
-               g_cancellable_cancel (priv->cancellable);
-               g_object_unref (priv->cancellable);
-       }
-
-       g_queue_foreach (priv->directories, (GFunc) directory_root_info_free, NULL);
-       g_queue_free (priv->directories);
-
        g_free (priv->file_attributes);
 
        if (priv->data_provider) {
@@ -336,18 +281,9 @@ check_file (TrackerCrawler    *crawler,
             GFile             *file)
 {
        gboolean use = FALSE;
-       TrackerCrawlerPrivate *priv;
-
-       priv = tracker_crawler_get_instance_private (crawler);
 
        use = invoke_check (crawler, TRACKER_CRAWLER_CHECK_FILE, file, NULL);
 
-       /* Crawler may have been stopped while waiting for the 'use' value,
-        * and the DirectoryRootInfo already disposed... */
-       if (!priv->is_running) {
-               return FALSE;
-       }
-
        info->files_found++;
 
        if (!use) {
@@ -363,18 +299,9 @@ check_directory (TrackerCrawler    *crawler,
                 GFile             *file)
 {
        gboolean use = FALSE;
-       TrackerCrawlerPrivate *priv;
-
-       priv = tracker_crawler_get_instance_private (crawler);
 
        use = invoke_check (crawler, TRACKER_CRAWLER_CHECK_DIRECTORY, file, NULL);
 
-       /* Crawler may have been stopped while waiting for the 'use' value,
-        * and the DirectoryRootInfo already disposed... */
-       if (!priv->is_running) {
-               return FALSE;
-       }
-
        info->directories_found++;
 
        if (!use) {
@@ -527,6 +454,10 @@ directory_tree_free_foreach (GNode    *node,
 static void
 directory_root_info_free (DirectoryRootInfo *info)
 {
+       if (info->idle_id) {
+               g_source_remove (info->idle_id);
+       }
+
        if (info->dpd)  {
                data_provider_end (info->dpd->crawler, info);
        }
@@ -550,39 +481,22 @@ directory_root_info_free (DirectoryRootInfo *info)
 }
 
 static gboolean
-process_next (TrackerCrawler *crawler)
+process_next (DirectoryRootInfo *info)
 {
-       TrackerCrawlerPrivate   *priv;
-       DirectoryRootInfo       *info;
-       DirectoryProcessingData *dir_data = NULL;
-       gboolean                 stop_idle = FALSE;
-
-       priv = tracker_crawler_get_instance_private (crawler);
-
-       info = g_queue_peek_head (priv->directories);
+       DirectoryProcessingData *dir_data;
+       GTask *task = info->task;
 
-       if (info) {
-               dir_data = g_queue_peek_head (info->directory_processing_queue);
+       if (g_task_return_error_if_cancelled (task)) {
+               g_object_unref (task);
+               return G_SOURCE_REMOVE;
        }
 
+       dir_data = g_queue_peek_head (info->directory_processing_queue);
+
        if (dir_data) {
                /* One directory inside the tree hierarchy is being inspected */
-               if (!dir_data->was_inspected) {
-                       dir_data->was_inspected = TRUE;
-
-                       /* Crawler may have been already stopped while we were waiting for the
-                        *  check_directory return value, and thus we should check if it's
-                        *  running before going on with the iteration */
-                       if (priv->is_running && G_NODE_IS_ROOT (dir_data->node)) {
-                               /* Directory contents haven't been inspected yet,
-                                * stop this idle function while it's being iterated
-                                */
-                               data_provider_begin (crawler, info, dir_data);
-                               stop_idle = TRUE;
-                       }
-               } else if (dir_data->was_inspected &&
-                          !dir_data->ignored_by_content &&
-                          dir_data->children != NULL) {
+               if (!dir_data->ignored_by_content &&
+                   dir_data->children != NULL) {
                        DirectoryChildData *child_data;
                        GNode *child_node = NULL;
 
@@ -594,18 +508,14 @@ process_next (TrackerCrawler *crawler)
                        dir_data->children = g_slist_remove (dir_data->children, child_data);
 
                        if (((child_data->is_dir &&
-                             check_directory (crawler, info, child_data->child)) ||
+                             check_directory (info->crawler, info, child_data->child)) ||
                             (!child_data->is_dir &&
-                             check_file (crawler, info, child_data->child))) &&
-                           /* Crawler may have been already stopped while we were waiting for the
-                            *  check_directory or check_file return value, and thus we should
-                            *   check if it's running before going on */
-                           priv->is_running) {
+                             check_file (info->crawler, info, child_data->child)))) {
                                child_node = g_node_prepend_data (dir_data->node,
                                                                  g_object_ref (child_data->child));
                        }
 
-                       if (G_NODE_IS_ROOT (dir_data->node) && priv->is_running &&
+                       if (G_NODE_IS_ROOT (dir_data->node) &&
                            child_node && child_data->is_dir) {
                                DirectoryProcessingData *child_dir_data;
 
@@ -614,52 +524,39 @@ process_next (TrackerCrawler *crawler)
                        }
 
                        directory_child_data_free (child_data);
+
+                       return G_SOURCE_CONTINUE;
                } else {
                        /* No (more) children, or directory ignored. stop processing. */
                        g_queue_pop_head (info->directory_processing_queue);
                        directory_processing_data_free (dir_data);
+
+                       g_task_return_boolean (task, !dir_data->ignored_by_content);
+                       g_object_unref (task);
                }
        } else if (!dir_data && info) {
                /* Current directory being crawled doesn't have anything else
-                * to process, emit ::directory-crawled and free data.
+                * to process.
                 */
-               g_signal_emit (crawler, signals[DIRECTORY_CRAWLED], 0,
-                              info->directory,
-                              info->tree,
-                              info->directories_found,
-                              info->directories_ignored,
-                              info->files_found,
-                              info->files_ignored);
-
-               data_provider_end (crawler, info);
-               g_queue_pop_head (priv->directories);
-               directory_root_info_free (info);
-       }
+               g_task_return_boolean (task, TRUE);
+               g_object_unref (task);
 
-       if (!g_queue_peek_head (priv->directories)) {
-               /* There's nothing else to process */
-               priv->is_finished = TRUE;
-               tracker_crawler_stop (crawler);
-               stop_idle = TRUE;
+               data_provider_end (info->crawler, info);
        }
 
-       if (stop_idle) {
-               priv->idle_id = 0;
-               return FALSE;
-       }
-
-       return TRUE;
+       /* There's nothing else to process */
+       return G_SOURCE_REMOVE;
 }
 
 static gboolean
 process_func (gpointer data)
 {
-       TrackerCrawler *crawler = data;
+       DirectoryRootInfo *info = data;
        gboolean retval = FALSE;
        gint i;
 
        for (i = 0; i < MAX_SIMULTANEOUS_ITEMS; i++) {
-               retval = process_next (crawler);
+               retval = process_next (info);
                if (retval == FALSE)
                        break;
        }
@@ -668,36 +565,15 @@ process_func (gpointer data)
 }
 
 static gboolean
-process_func_start (TrackerCrawler *crawler)
+process_func_start (DirectoryRootInfo *info)
 {
-       TrackerCrawlerPrivate *priv;
-
-       priv = tracker_crawler_get_instance_private (crawler);
-
-       if (priv->is_finished) {
-               return FALSE;
-       }
-
-       if (priv->idle_id == 0) {
-               priv->idle_id = g_idle_add (process_func, crawler);
+       if (info->idle_id == 0) {
+               info->idle_id = g_idle_add (process_func, info);
        }
 
        return TRUE;
 }
 
-static void
-process_func_stop (TrackerCrawler *crawler)
-{
-       TrackerCrawlerPrivate *priv;
-
-       priv = tracker_crawler_get_instance_private (crawler);
-
-       if (priv->idle_id != 0) {
-               g_source_remove (priv->idle_id);
-               priv->idle_id = 0;
-       }
-}
-
 static DataProviderData *
 data_provider_data_new (TrackerCrawler          *crawler,
                         DirectoryRootInfo       *root_info,
@@ -865,10 +741,12 @@ enumerate_next_cb (GObject      *object,
 {
        DataProviderData *dpd;
        GList *info;
-       g_autoptr(GError) error = NULL;
+       GError *error = NULL;
+       DirectoryRootInfo *root_info;
 
        info = g_file_enumerator_next_files_finish (G_FILE_ENUMERATOR (object), result, &error);
        dpd = user_data;
+       root_info = dpd->root_info;
 
        if (!info) {
                /* Could be due to:
@@ -879,32 +757,27 @@ enumerate_next_cb (GObject      *object,
                        /* We don't consider cancellation an error, so we only
                         * log errors which are not cancellations.
                         */
-                       if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
-                               gchar *uri = g_file_get_uri (dpd->dir_file);
-                               g_warning ("Could not enumerate next item in container / directory '%s', %s",
-                                          uri, error ? error->message : "no error given");
-                               g_free (uri);
-                       } else {
-                               return;
-                       }
+                       g_task_return_error (root_info->task, error);
+                       g_object_unref (root_info->task);
+                       return;
                } else {
                        /* Done enumerating, start processing what we got ... */
                        data_provider_data_add (dpd);
                        data_provider_data_process (dpd);
                }
 
-               process_func_start (dpd->crawler);
+               process_func_start (dpd->root_info);
        } else {
-               TrackerCrawlerPrivate *priv;
+               DirectoryRootInfo *root_info;
 
-               priv = tracker_crawler_get_instance_private (dpd->crawler);
+               root_info = dpd->root_info;
 
                /* More work to do, we keep reference given to us */
                dpd->files = g_list_concat (dpd->files, info);
                g_file_enumerator_next_files_async (G_FILE_ENUMERATOR (object),
                                                    MAX_SIMULTANEOUS_ITEMS,
                                                    G_PRIORITY_LOW,
-                                                   priv->cancellable,
+                                                   g_task_get_cancellable (root_info->task),
                                                    enumerate_next_cb,
                                                    dpd);
        }
@@ -915,7 +788,6 @@ data_provider_begin_cb (GObject      *object,
                         GAsyncResult *result,
                         gpointer      user_data)
 {
-       TrackerCrawlerPrivate *priv;
        GFileEnumerator *enumerator;
        DirectoryRootInfo *info;
        DataProviderData *dpd;
@@ -926,27 +798,17 @@ data_provider_begin_cb (GObject      *object,
        info = user_data;
 
        if (error) {
-               if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
-                       gchar *uri;
-
-                       dpd = info->dpd;
-                       uri = g_file_get_uri (dpd->dir_file);
-                       g_warning ("Could not enumerate container / directory '%s', %s",
-                                  uri, error ? error->message : "no error given");
-                       g_free (uri);
-                       process_func_start (dpd->crawler);
-               }
-               g_clear_error (&error);
+               g_task_return_error (info->task, error);
+               g_object_unref (info->task);
                return;
        }
 
        dpd = info->dpd;
        dpd->enumerator = enumerator;
-       priv = tracker_crawler_get_instance_private (dpd->crawler);
        g_file_enumerator_next_files_async (enumerator,
                                            MAX_SIMULTANEOUS_ITEMS,
                                            G_PRIORITY_LOW,
-                                           priv->cancellable,
+                                           g_task_get_cancellable (info->task),
                                            enumerate_next_cb,
                                            dpd);
 }
@@ -962,12 +824,6 @@ data_provider_begin (TrackerCrawler          *crawler,
 
        priv = tracker_crawler_get_instance_private (crawler);
 
-       /* DataProviderData is freed in data_provider_end() call. This
-        * call must _ALWAYS_ be reached even on cancellation or
-        * failure, this is normally the case when we return to the
-        * process_func() and finish a directory.
-        */
-       dir_data->was_inspected = TRUE;
        dpd = data_provider_data_new (crawler, info, dir_data);
        info->dpd = dpd;
 
@@ -984,100 +840,95 @@ data_provider_begin (TrackerCrawler          *crawler,
                                           attrs,
                                           info->flags,
                                           G_PRIORITY_LOW,
-                                          priv->cancellable,
+                                          g_task_get_cancellable (info->task),
                                           data_provider_begin_cb,
                                           info);
        g_free (attrs);
 }
 
 gboolean
-tracker_crawler_start (TrackerCrawler        *crawler,
-                       GFile                 *file,
-                       TrackerDirectoryFlags  flags)
+tracker_crawler_get_finish (TrackerCrawler  *crawler,
+                            GAsyncResult    *result,
+                            GFile          **directory,
+                            GNode          **tree,
+                            guint           *directories_found,
+                            guint           *directories_ignored,
+                            guint           *files_found,
+                            guint           *files_ignored,
+                            GError         **error)
+{
+       DirectoryRootInfo *info;
+       gboolean retval;
+
+       info = g_task_get_task_data (G_TASK (result));
+
+       retval = g_task_propagate_boolean (G_TASK (result), error);
+       if (retval) {
+               if (tree)
+                       *tree = info->tree;
+       }
+
+       if (directory)
+               *directory = info->directory;
+       if (directories_found)
+               *directories_found = info->directories_found;
+       if (directories_ignored)
+               *directories_ignored = info->directories_ignored;
+       if (files_found)
+               *files_found = info->files_found;
+       if (files_ignored)
+               *files_ignored = info->files_ignored;
+
+       return retval;
+}
+
+void
+tracker_crawler_get (TrackerCrawler        *crawler,
+                     GFile                 *file,
+                     TrackerDirectoryFlags  flags,
+                     GCancellable          *cancellable,
+                     GAsyncReadyCallback    callback,
+                     gpointer               user_data)
 {
        TrackerCrawlerPrivate *priv;
        DirectoryProcessingData *dir_data;
        DirectoryRootInfo *info;
        gboolean enable_stat;
+       GTask *task;
 
-       g_return_val_if_fail (TRACKER_IS_CRAWLER (crawler), FALSE);
-       g_return_val_if_fail (G_IS_FILE (file), FALSE);
+       g_return_if_fail (TRACKER_IS_CRAWLER (crawler));
+       g_return_if_fail (G_IS_FILE (file));
 
        priv = tracker_crawler_get_instance_private (crawler);
 
        enable_stat = (flags & TRACKER_DIRECTORY_FLAG_NO_STAT) == 0;
 
+       info = directory_root_info_new (file, priv->file_attributes, flags);
+       task = g_task_new (crawler, cancellable, callback, user_data);
+       g_task_set_task_data (task, info,
+                             (GDestroyNotify) directory_root_info_free);
+       info->task = task;
+       info->crawler = crawler;
+
        if (enable_stat && !g_file_query_exists (file, NULL)) {
                /* This shouldn't happen, unless the removal/unmount notification
                 * didn't yet reach the TrackerFileNotifier.
                 */
-               return FALSE;
-       }
-
-       priv->was_started = TRUE;
-
-       /* Set a brand new cancellable */
-       if (priv->cancellable) {
-               g_cancellable_cancel (priv->cancellable);
-               g_object_unref (priv->cancellable);
+               g_task_return_boolean (task, FALSE);
+               g_object_unref (task);
+               return;
        }
 
-       priv->cancellable = g_cancellable_new ();
-
-       /* Set as running now */
-       priv->is_running = TRUE;
-       priv->is_finished = FALSE;
-
-       info = directory_root_info_new (file, priv->file_attributes, flags);
-
        if (!check_directory (crawler, info, file)) {
-               directory_root_info_free (info);
-
-               priv->is_running = FALSE;
-               priv->is_finished = TRUE;
-
-               return FALSE;
+               g_task_return_boolean (task, FALSE);
+               g_object_unref (task);
+               return;
        }
 
-       g_queue_push_tail (priv->directories, info);
-
        dir_data = g_queue_peek_head (info->directory_processing_queue);
 
        if (dir_data)
                data_provider_begin (crawler, info, dir_data);
-
-       return TRUE;
-}
-
-void
-tracker_crawler_stop (TrackerCrawler *crawler)
-{
-       TrackerCrawlerPrivate *priv;
-
-       g_return_if_fail (TRACKER_IS_CRAWLER (crawler));
-
-       priv = tracker_crawler_get_instance_private (crawler);
-
-       /* If already not running, just ignore */
-       if (!priv->is_running) {
-               return;
-       }
-
-       priv->is_running = FALSE;
-       g_cancellable_cancel (priv->cancellable);
-
-       process_func_stop (crawler);
-
-       /* Clean up queue */
-       g_queue_foreach (priv->directories, (GFunc) directory_root_info_free, NULL);
-       g_queue_clear (priv->directories);
-
-       g_signal_emit (crawler, signals[FINISHED], 0,
-                      !priv->is_finished);
-
-       /* We don't free the queue in case the crawler is reused, it
-        * is only freed in finalize.
-        */
 }
 
 /**
diff --git a/src/libtracker-miner/tracker-crawler.h b/src/libtracker-miner/tracker-crawler.h
index 985ecddca..d0a6fe09e 100644
--- a/src/libtracker-miner/tracker-crawler.h
+++ b/src/libtracker-miner/tracker-crawler.h
@@ -63,24 +63,26 @@ struct TrackerCrawler {
 
 struct TrackerCrawlerClass {
        GObjectClass parent;
-
-       void     (* directory_crawled)        (TrackerCrawler *crawler,
-                                              GFile          *directory,
-                                              GNode          *tree,
-                                              guint           directories_found,
-                                              guint           directories_ignored,
-                                              guint           files_found,
-                                              guint           files_ignored);
-       void     (* finished)                 (TrackerCrawler *crawler,
-                                              gboolean        interrupted);
 };
 
 GType           tracker_crawler_get_type     (void);
 TrackerCrawler *tracker_crawler_new          (TrackerDataProvider *data_provider);
-gboolean        tracker_crawler_start        (TrackerCrawler *crawler,
-                                              GFile          *file,
-                                              TrackerDirectoryFlags flags);
-void            tracker_crawler_stop         (TrackerCrawler *crawler);
+
+gboolean tracker_crawler_get_finish (TrackerCrawler  *crawler,
+                                     GAsyncResult    *result,
+                                     GFile          **directory,
+                                     GNode          **tree,
+                                     guint           *directories_found,
+                                     guint           *directories_ignored,
+                                     guint           *files_found,
+                                     guint           *files_ignored,
+                                     GError         **error);
+void tracker_crawler_get (TrackerCrawler        *crawler,
+                          GFile                 *file,
+                          TrackerDirectoryFlags  flags,
+                          GCancellable          *cancellable,
+                          GAsyncReadyCallback    callback,
+                          gpointer               user_data);
 
 void            tracker_crawler_set_file_attributes (TrackerCrawler *crawler,
                                                     const gchar    *file_attributes);
diff --git a/src/libtracker-miner/tracker-file-notifier.c b/src/libtracker-miner/tracker-file-notifier.c
index 45e0eb335..1fd3710a9 100644
--- a/src/libtracker-miner/tracker-file-notifier.c
+++ b/src/libtracker-miner/tracker-file-notifier.c
@@ -109,6 +109,9 @@ typedef struct {
 } TrackerFileNotifierPrivate;
 
 static gboolean notifier_query_root_contents (TrackerFileNotifier *notifier);
+static gboolean crawl_directory_in_current_root (TrackerFileNotifier *notifier);
+static void finish_current_directory (TrackerFileNotifier *notifier,
+                                      gboolean             interrupted);
 
 G_DEFINE_TYPE_WITH_PRIVATE (TrackerFileNotifier, tracker_file_notifier, G_TYPE_OBJECT)
 
@@ -437,20 +440,42 @@ file_notifier_add_node_foreach (GNode    *node,
 }
 
 static void
-crawler_directory_crawled_cb (TrackerCrawler *crawler,
-                              GFile          *directory,
-                              GNode          *tree,
-                              guint           directories_found,
-                              guint           directories_ignored,
-                              guint           files_found,
-                              guint           files_ignored,
-                              gpointer        user_data)
+crawler_get_cb (TrackerCrawler *crawler,
+                GAsyncResult   *result,
+                gpointer        user_data)
 {
-       TrackerFileNotifier *notifier;
-       TrackerFileNotifierPrivate *priv;
+       TrackerFileNotifier *notifier = user_data;
+       TrackerFileNotifierPrivate *priv =
+               tracker_file_notifier_get_instance_private (notifier);
+       guint directories_found, directories_ignored;
+       guint files_found, files_ignored;
+       GFile *directory;
+       GNode *tree;
+       GError *error = NULL;
 
-       notifier = user_data;
-       priv = tracker_file_notifier_get_instance_private (notifier);
+       if (!tracker_crawler_get_finish (crawler,
+                                        result,
+                                        &directory,
+                                        &tree,
+                                        &directories_found,
+                                        &directories_ignored,
+                                        &files_found,
+                                        &files_ignored,
+                                        &error)) {
+               if (error &&
+                   !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+                       gchar *uri;
+
+                       uri = g_file_get_uri (directory);
+                       g_warning ("Got error crawling '%s': %s\n",
+                                  uri, error->message);
+                       g_free (uri);
+               }
+               tracker_monitor_remove (priv->monitor, directory);
+               finish_current_directory (notifier, TRUE);
+               g_clear_error (&error);
+               return;
+       }
 
        g_node_traverse (tree,
                         G_PRE_ORDER,
@@ -463,6 +488,9 @@ crawler_directory_crawled_cb (TrackerCrawler *crawler,
        priv->current_index_root->directories_ignored += directories_ignored;
        priv->current_index_root->files_found += files_found;
        priv->current_index_root->files_ignored += files_ignored;
+
+       if (!crawl_directory_in_current_root (notifier))
+               finish_current_directory (notifier, FALSE);
 }
 
 static void
@@ -507,25 +535,15 @@ crawl_directory_in_current_root (TrackerFileNotifier *notifier)
                if ((flags & TRACKER_DIRECTORY_FLAG_MONITOR) != 0)
                        tracker_monitor_add (priv->monitor, directory);
 
-               /* Begin crawling the directory non-recursively.
-                *
-                *  - We receive ::check-file, ::check-directory and ::check-directory-contents signals
-                *    during the crawl, which control which directories are crawled and which files are
-                *    returned.
-                *  - We receive ::directory-crawled each time a directory crawl completes. This provides
-                *    the list of contents for a directory.
-                *  - We receive ::finished when the crawler completes.
-                *
-                */
-               if (tracker_crawler_start (priv->crawler,
-                                          directory,
-                                          priv->current_index_root->flags)) {
-                       g_object_unref (directory);
-                       return TRUE;
-               }
-
-               tracker_monitor_remove (priv->monitor, directory);
+               /* Begin crawling the directory non-recursively. */
+               tracker_crawler_get (priv->crawler,
+                                    directory,
+                                    priv->current_index_root->flags,
+                                    priv->cancellable,
+                                    (GAsyncReadyCallback) crawler_get_cb,
+                                    notifier);
                g_object_unref (directory);
+               return TRUE;
        }
 
        return FALSE;
@@ -612,7 +630,6 @@ file_notifier_current_root_check_remove_directory (TrackerFileNotifier *notifier
        if (priv->current_index_root &&
            root_data_remove_directory (priv->current_index_root, file)) {
                g_cancellable_cancel (priv->cancellable);
-               tracker_crawler_stop (priv->crawler);
 
                if (!crawl_directory_in_current_root (notifier)) {
                        g_clear_pointer (&priv->current_index_root, root_data_free);
@@ -782,27 +799,6 @@ notifier_query_root_contents (TrackerFileNotifier *notifier)
        return TRUE;
 }
 
-static void
-crawler_finished_cb (TrackerCrawler *crawler,
-                     gboolean        was_interrupted,
-                     gpointer        user_data)
-{
-       TrackerFileNotifier *notifier = user_data;
-       TrackerFileNotifierPrivate *priv;
-
-       priv = tracker_file_notifier_get_instance_private (notifier);
-
-       g_assert (priv->current_index_root != NULL);
-
-       if (was_interrupted) {
-               finish_current_directory (notifier, TRUE);
-               return;
-       }
-
-       if (!crawl_directory_in_current_root (notifier))
-               finish_current_directory (notifier, FALSE);
-}
-
 static gint
 find_directory_root (RootData *data,
                      GFile    *file)
@@ -1254,7 +1250,6 @@ indexing_tree_directory_removed (TrackerIndexingTree *indexing_tree,
        if (priv->current_index_root &&
            g_file_equal (directory, priv->current_index_root->root)) {
                /* Directory being currently processed */
-               tracker_crawler_stop (priv->crawler);
                g_cancellable_cancel (priv->cancellable);
 
                /* If the crawler was already stopped (eg. we're at the querying
@@ -1433,13 +1428,6 @@ tracker_file_notifier_constructed (GObject *object)
                                             G_FILE_ATTRIBUTE_TIME_MODIFIED ","
                                             G_FILE_ATTRIBUTE_STANDARD_TYPE);
 
-       g_signal_connect (priv->crawler, "directory-crawled",
-                         G_CALLBACK (crawler_directory_crawled_cb),
-                         object);
-       g_signal_connect (priv->crawler, "finished",
-                         G_CALLBACK (crawler_finished_cb),
-                         object);
-
        check_disable_monitor (TRACKER_FILE_NOTIFIER (object));
 }
 
@@ -1649,8 +1637,6 @@ tracker_file_notifier_stop (TrackerFileNotifier *notifier)
        priv = tracker_file_notifier_get_instance_private (notifier);
 
        if (!priv->stopped) {
-               tracker_crawler_stop (priv->crawler);
-
                g_clear_pointer (&priv->current_index_root, root_data_free);
                g_cancellable_cancel (priv->cancellable);
                priv->stopped = TRUE;
diff --git a/tests/libtracker-miner/tracker-crawler-test.c b/tests/libtracker-miner/tracker-crawler-test.c
index ddf8ec650..28eac432f 100644
--- a/tests/libtracker-miner/tracker-crawler-test.c
+++ b/tests/libtracker-miner/tracker-crawler-test.c
@@ -32,6 +32,7 @@ struct CrawlerTest {
        guint files_found;
        guint files_ignored;
        gboolean interrupted;
+       gboolean stopped;
 
        /* signals statistics */
        guint n_check_directory;
@@ -40,37 +41,37 @@ struct CrawlerTest {
 };
 
 static void
-crawler_finished_cb (TrackerCrawler *crawler,
-                     gboolean        interrupted,
-                     gpointer        user_data)
+crawler_get_cb (GObject      *source,
+                GAsyncResult *result,
+                gpointer      user_data)
 {
        CrawlerTest *test = user_data;
-
-       test->interrupted = interrupted;
-
-       if (test->main_loop) {
-               g_main_loop_quit (test->main_loop);
+       GError *error = NULL;
+       guint directories_found, directories_ignored;
+       guint files_found, files_ignored;
+       GNode *tree;
+
+       if (!tracker_crawler_get_finish (TRACKER_CRAWLER (source),
+                                        result,
+                                        NULL, &tree,
+                                        &directories_found, &directories_ignored,
+                                        &files_found, &files_ignored,
+                                        &error)) {
+               if (error && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+                       test->interrupted = TRUE;
+
+               test->stopped = TRUE;
+       } else {
+               test->directories_found = directories_found;
+               test->directories_ignored = directories_ignored;
+               test->files_found = files_found;
+               test->files_ignored = files_ignored;
+
+               g_assert_cmpint (g_node_n_nodes (tree, G_TRAVERSE_ALL), ==, directories_found + files_found);
        }
-}
-
-static void
-crawler_directory_crawled_cb (TrackerCrawler *crawler,
-                              GFile          *directory,
-                              GNode          *tree,
-                              guint           directories_found,
-                              guint           directories_ignored,
-                              guint           files_found,
-                              guint           files_ignored,
-                              gpointer        user_data)
-{
-       CrawlerTest *test = user_data;
 
-       test->directories_found = directories_found;
-       test->directories_ignored = directories_ignored;
-       test->files_found = files_found;
-       test->files_ignored = files_ignored;
-
-       g_assert_cmpint (g_node_n_nodes (tree, G_TRAVERSE_ALL), ==, directories_found + files_found);
+       if (test->main_loop)
+               g_main_loop_quit (test->main_loop);
 }
 
 static gboolean
@@ -97,20 +98,16 @@ test_crawler_crawl (void)
 {
        TrackerCrawler *crawler;
        CrawlerTest test = { 0 };
-       gboolean started;
        GFile *file;
 
        test.main_loop = g_main_loop_new (NULL, FALSE);
 
        crawler = tracker_crawler_new (NULL);
-       g_signal_connect (crawler, "finished",
-                         G_CALLBACK (crawler_finished_cb), &test);
 
        file = g_file_new_for_path (TEST_DATA_DIR);
 
-       started = tracker_crawler_start (crawler, file, TRACKER_DIRECTORY_FLAG_NONE);
-
-       g_assert_cmpint (started, ==, 1);
+       tracker_crawler_get (crawler, file, TRACKER_DIRECTORY_FLAG_NONE,
+                            NULL, crawler_get_cb, &test);
 
        g_main_loop_run (test.main_loop);
 
@@ -126,23 +123,26 @@ test_crawler_crawl_interrupted (void)
 {
        TrackerCrawler *crawler;
        CrawlerTest test = { 0 };
-       gboolean started;
+       GCancellable *cancellable;
        GFile *file;
 
+       test.main_loop = g_main_loop_new (NULL, FALSE);
+
        crawler = tracker_crawler_new (NULL);
-       g_signal_connect (crawler, "finished",
-                         G_CALLBACK (crawler_finished_cb), &test);
 
        file = g_file_new_for_path (TEST_DATA_DIR);
+       cancellable = g_cancellable_new ();
 
-       started = tracker_crawler_start (crawler, file, TRACKER_DIRECTORY_FLAG_NONE);
+       tracker_crawler_get (crawler, file, TRACKER_DIRECTORY_FLAG_NONE,
+                            cancellable, crawler_get_cb, &test);
 
-       g_assert_cmpint (started, ==, 1);
+       g_cancellable_cancel (cancellable);
 
-       tracker_crawler_stop (crawler);
+       g_main_loop_run (test.main_loop);
 
        g_assert_cmpint (test.interrupted, ==, 1);
 
+       g_object_unref (cancellable);
        g_object_unref (crawler);
        g_object_unref (file);
 }
@@ -151,15 +151,20 @@ static void
 test_crawler_crawl_nonexisting (void)
 {
        TrackerCrawler *crawler;
+       CrawlerTest test = { 0 };
        GFile *file;
-       gboolean started;
+
+       test.main_loop = g_main_loop_new (NULL, FALSE);
 
        crawler = tracker_crawler_new (NULL);
        file = g_file_new_for_path (TEST_DATA_DIR "-idontexist");
 
-       started = tracker_crawler_start (crawler, file, TRACKER_DIRECTORY_FLAG_NONE);
+       tracker_crawler_get (crawler, file, TRACKER_DIRECTORY_FLAG_NONE,
+                            NULL, crawler_get_cb, &test);
+
+       g_main_loop_run (test.main_loop);
 
-       g_assert_cmpint (started, ==, 0);
+       g_assert_cmpint (test.stopped, ==, 1);
 
        g_object_unref (crawler);
        g_object_unref (file);
@@ -175,14 +180,11 @@ test_crawler_crawl_non_recursive (void)
        test.main_loop = g_main_loop_new (NULL, FALSE);
 
        crawler = tracker_crawler_new (NULL);
-       g_signal_connect (crawler, "finished",
-                         G_CALLBACK (crawler_finished_cb), &test);
-       g_signal_connect (crawler, "directory-crawled",
-                         G_CALLBACK (crawler_directory_crawled_cb), &test);
 
        file = g_file_new_for_path (TEST_DATA_DIR);
 
-       tracker_crawler_start (crawler, file, TRACKER_DIRECTORY_FLAG_NONE);
+       tracker_crawler_get (crawler, file, TRACKER_DIRECTORY_FLAG_NONE,
+                            NULL, crawler_get_cb, &test);
 
        g_main_loop_run (test.main_loop);
 
@@ -210,14 +212,11 @@ test_crawler_crawl_n_signals_non_recursive (void)
 
        crawler = tracker_crawler_new (NULL);
        tracker_crawler_set_check_func (crawler, check_func, &test, NULL);
-       g_signal_connect (crawler, "finished",
-                         G_CALLBACK (crawler_finished_cb), &test);
-       g_signal_connect (crawler, "directory-crawled",
-                         G_CALLBACK (crawler_directory_crawled_cb), &test);
 
        file = g_file_new_for_path (TEST_DATA_DIR);
 
-       tracker_crawler_start (crawler, file, TRACKER_DIRECTORY_FLAG_NONE);
+       tracker_crawler_get (crawler, file, TRACKER_DIRECTORY_FLAG_NONE,
+                            NULL, crawler_get_cb, &test);
 
        g_main_loop_run (test.main_loop);
 


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