[tracker] tracker-miner-fs: Keep cache of IndexFile requesters on directories



commit 614589d2afc3b2e4ffc0f4a5c49ec53c8b6c10f9
Author: Carlos Garnacho <carlosg gnome org>
Date:   Sat Aug 15 00:08:11 2015 +0200

    tracker-miner-fs: Keep cache of IndexFile requesters on directories
    
    The senders for all DBus requests to the IndexFile method on directories
    will be now watched, the dbus presence of the senders will control the
    lifetime of the directory on the indexed directories tree.
    
    There may be multiple requests on a same directory, in such case the
    directory will be indexed/monitored for as long as there is alive requesters
    on it. Requests on already indexed directories (or children of recursively
    indexed ones) will be silently ignored. Unmounts will also silently drop
    the IndexFile listeners, applications should issue new requests on volume
    mounts if desired.
    
    The patch is loosely based on initial work from Felipe Borges.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=680834

 src/miners/fs/Makefile.am                         |    2 +
 src/miners/fs/tracker-miner-files-index.c         |   80 ++++-
 src/miners/fs/tracker-miner-files-index.xml       |    4 +
 src/miners/fs/tracker-miner-files-peer-listener.c |  455 +++++++++++++++++++++
 src/miners/fs/tracker-miner-files-peer-listener.h |   65 +++
 5 files changed, 603 insertions(+), 3 deletions(-)
---
diff --git a/src/miners/fs/Makefile.am b/src/miners/fs/Makefile.am
index c766a60..27bd016 100644
--- a/src/miners/fs/Makefile.am
+++ b/src/miners/fs/Makefile.am
@@ -34,6 +34,8 @@ tracker_miner_fs_SOURCES =                             \
        tracker-miner-files.h                          \
        tracker-miner-files-index.c                    \
        tracker-miner-files-index.h                    \
+       tracker-miner-files-peer-listener.c            \
+       tracker-miner-files-peer-listener.h            \
        tracker-storage.c                              \
        tracker-storage.h                              \
        tracker-writeback-listener.c                   \
diff --git a/src/miners/fs/tracker-miner-files-index.c b/src/miners/fs/tracker-miner-files-index.c
index b507e32..eb309ae 100644
--- a/src/miners/fs/tracker-miner-files-index.c
+++ b/src/miners/fs/tracker-miner-files-index.c
@@ -24,6 +24,7 @@
 #include <libtracker-miner/tracker-miner.h>
 
 #include "tracker-miner-files-index.h"
+#include "tracker-miner-files-peer-listener.h"
 
 
 static const gchar introspection_xml[] =
@@ -35,6 +36,9 @@ static const gchar introspection_xml[] =
   "    <method name='IndexFile'>"
   "      <arg type='s' name='file_uri' direction='in' />"
   "    </method>"
+  "    <method name='IndexFileForProcess'>"
+  "      <arg type='s' name='file_uri' direction='in' />"
+  "    </method>"
   "  </interface>"
   "</node>";
 
@@ -54,6 +58,7 @@ typedef struct {
 
 typedef struct {
        TrackerMinerFiles *files_miner;
+       TrackerMinerFilesPeerListener *peer_listener;
        GDBusConnection *d_connection;
        GDBusNodeInfo *introspection_data;
        guint registration_id;
@@ -161,6 +166,7 @@ index_finalize (GObject *object)
                g_object_unref (priv->d_connection);
        }
 
+       g_clear_object (&priv->peer_listener);
        g_free (priv->full_name);
        g_free (priv->full_path);
 
@@ -308,7 +314,8 @@ tracker_miner_files_index_reindex_mime_types (TrackerMinerFilesIndex *miner,
 static void
 handle_method_call_index_file (TrackerMinerFilesIndex *miner,
                                GDBusMethodInvocation  *invocation,
-                               GVariant               *parameters)
+                               GVariant               *parameters,
+                               gboolean                watch_source)
 {
        TrackerMinerFilesIndexPrivate *priv;
        TrackerDBusRequest *request;
@@ -365,7 +372,39 @@ handle_method_call_index_file (TrackerMinerFilesIndex *miner,
 #endif /* REQUIRE_LOCATION_IN_CONFIG */
 
        if (is_dir) {
-               tracker_miner_fs_check_directory (TRACKER_MINER_FS (priv->files_miner), file, do_checks);
+               TrackerIndexingTree *indexing_tree;
+               TrackerDirectoryFlags flags;
+               gboolean is_watched, needs_watch = FALSE;
+               GFile *root;
+
+               indexing_tree = tracker_miner_fs_get_indexing_tree (TRACKER_MINER_FS (priv->files_miner));
+               root = tracker_indexing_tree_get_root (indexing_tree, file, &flags);
+
+               /* If the directory had already subscribers, we want to add all
+                * further watches, so the directory survives as long as there's
+                * watchers.
+                */
+               is_watched = tracker_miner_files_peer_listener_is_file_watched (priv->peer_listener, file);
+
+               /* Check whether the requested dir is not over a (recursively)
+                * watched directory already, in that case we don't add the
+                * directory (nor add a watch if we're positive it comes from
+                * config).
+                */
+               if (!root || !(flags & TRACKER_DIRECTORY_FLAG_RECURSE)) {
+                       tracker_indexing_tree_add (indexing_tree, file,
+                                                  TRACKER_DIRECTORY_FLAG_RECURSE |
+                                                  TRACKER_DIRECTORY_FLAG_PRIORITY |
+                                                  TRACKER_DIRECTORY_FLAG_CHECK_MTIME |
+                                                  TRACKER_DIRECTORY_FLAG_MONITOR);
+                       needs_watch = TRUE;
+               }
+
+               if (watch_source && (is_watched || needs_watch)) {
+                       tracker_miner_files_peer_listener_add_watch (priv->peer_listener,
+                                                                    g_dbus_method_invocation_get_sender 
(invocation),
+                                                                    file);
+               }
        } else {
                tracker_miner_fs_check_file (TRACKER_MINER_FS (priv->files_miner), file, do_checks);
        }
@@ -394,12 +433,38 @@ handle_method_call (GDBusConnection       *connection,
        if (g_strcmp0 (method_name, "ReindexMimeTypes") == 0) {
                tracker_miner_files_index_reindex_mime_types (miner, invocation, parameters);
        } else if (g_strcmp0 (method_name, "IndexFile") == 0) {
-               handle_method_call_index_file (miner, invocation, parameters);
+               handle_method_call_index_file (miner, invocation, parameters, FALSE);
+       } else if (g_strcmp0 (method_name, "IndexFileForProcess") == 0) {
+               handle_method_call_index_file (miner, invocation, parameters, TRUE);
        } else {
                g_assert_not_reached ();
        }
 }
 
+static void
+peer_listener_unwatch_file (TrackerMinerFilesPeerListener *listener,
+                            GFile                         *file,
+                            gpointer                       user_data)
+{
+       TrackerMinerFilesIndexPrivate *priv;
+       TrackerIndexingTree *indexing_tree;
+
+       priv = TRACKER_MINER_FILES_INDEX_GET_PRIVATE (user_data);
+       indexing_tree = tracker_miner_fs_get_indexing_tree (TRACKER_MINER_FS (priv->files_miner));
+       tracker_indexing_tree_remove (indexing_tree, file);
+}
+
+static void
+indexing_tree_directory_remove (TrackerIndexingTree *indexing_tree,
+                                GFile               *file,
+                                gpointer             user_data)
+{
+       TrackerMinerFilesIndexPrivate *priv;
+
+       priv = TRACKER_MINER_FILES_INDEX_GET_PRIVATE (user_data);
+       tracker_miner_files_peer_listener_remove_file (priv->peer_listener, file);
+}
+
 static GVariant *
 handle_get_property (GDBusConnection  *connection,
                      const gchar      *sender,
@@ -441,6 +506,7 @@ tracker_miner_files_index_new (TrackerMinerFiles *miner_files)
        GVariant *reply;
        guint32 rval;
        GError *error = NULL;
+       TrackerIndexingTree *indexing_tree;
        GDBusInterfaceVTable interface_vtable = {
                handle_method_call,
                handle_get_property,
@@ -530,5 +596,13 @@ tracker_miner_files_index_new (TrackerMinerFiles *miner_files)
 
        priv->full_path = full_path;
 
+       priv->peer_listener = tracker_miner_files_peer_listener_new (priv->d_connection);
+       g_signal_connect (priv->peer_listener, "unwatch-file",
+                         G_CALLBACK (peer_listener_unwatch_file), miner);
+
+       indexing_tree = tracker_miner_fs_get_indexing_tree (TRACKER_MINER_FS (miner_files));
+       g_signal_connect (indexing_tree, "directory-removed",
+                         G_CALLBACK (indexing_tree_directory_remove), miner);
+
        return (TrackerMinerFilesIndex *) miner;
 }
diff --git a/src/miners/fs/tracker-miner-files-index.xml b/src/miners/fs/tracker-miner-files-index.xml
index afe3364..4e02ba3 100644
--- a/src/miners/fs/tracker-miner-files-index.xml
+++ b/src/miners/fs/tracker-miner-files-index.xml
@@ -10,5 +10,9 @@
       <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
       <arg type="s" name="file_uri" direction="in" />
     </method>
+    <method name="IndexFileForProcess">
+      <annotation name="org.freedesktop.DBus.GLib.Async" value="true"/>
+      <arg type="s" name="file_uri" direction="in" />
+    </method>
   </interface>
 </node>
diff --git a/src/miners/fs/tracker-miner-files-peer-listener.c 
b/src/miners/fs/tracker-miner-files-peer-listener.c
new file mode 100644
index 0000000..9131082
--- /dev/null
+++ b/src/miners/fs/tracker-miner-files-peer-listener.c
@@ -0,0 +1,455 @@
+/*
+ * Copyright (C) 2015, Carlos Garnacho
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Author: Carlos Garnacho <carlosg gnome org>
+ */
+
+/* TrackerMinerFilesPeerListener is a helper object to keep track
+ * of the DBus callers that request directories to be indexed. The
+ * ::unwatch-file will be emitted as soon as there's no further
+ * requestors on a directory, be it due to disconnections, or due
+ * to other reasons (tracker_indexing_tree_remove() being called
+ * externally, eg. when the directory being monitored is unmounted).
+ */
+
+#include "tracker-miner-files-peer-listener.h"
+
+enum {
+       PROP_CONNECTION = 1
+};
+
+enum {
+       WATCH_FILE,
+       UNWATCH_FILE,
+       N_SIGNALS
+};
+
+static guint signals[N_SIGNALS] = { 0 };
+
+typedef struct {
+       gchar *dbus_name;
+       GPtrArray *files; /* Array of GFiles, actually owned by FilePeersData */
+       guint watch_id;
+} PeerFilesData;
+
+typedef struct {
+       GFile *file;
+       GPtrArray *peers; /* Array of dbus names, actually owned by PeerFilesData */
+} FilePeersData;
+
+typedef struct {
+       GDBusConnection *d_connection;
+       GHashTable *peer_files; /* dbus name -> PeerFilesData */
+       GHashTable *file_peers; /* GFile -> FilePeersData */
+} TrackerMinerFilesPeerListenerPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (TrackerMinerFilesPeerListener,
+                            tracker_miner_files_peer_listener,
+                            G_TYPE_OBJECT)
+
+static void
+on_app_disappeared_cb (GDBusConnection *conn,
+                       const gchar     *dbus_name,
+                       gpointer         user_data)
+{
+       TrackerMinerFilesPeerListener *listener = user_data;
+
+       tracker_miner_files_peer_listener_remove_dbus_name (listener, dbus_name);
+}
+
+static PeerFilesData *
+peer_files_data_new (const gchar                   *dbus_name,
+                     TrackerMinerFilesPeerListener *listener)
+{
+       TrackerMinerFilesPeerListenerPrivate *priv;
+       PeerFilesData *data;
+
+       priv = tracker_miner_files_peer_listener_get_instance_private (listener);
+
+       data = g_slice_new0 (PeerFilesData);
+       data->dbus_name = g_strdup (dbus_name);
+       data->files = g_ptr_array_new ();
+       data->watch_id = g_bus_watch_name_on_connection (priv->d_connection,
+                                                        dbus_name, 0, NULL,
+                                                        on_app_disappeared_cb,
+                                                        listener, NULL);
+       return data;
+}
+
+static void
+peer_files_data_free (PeerFilesData *data)
+{
+       g_bus_unwatch_name (data->watch_id);
+       g_ptr_array_unref (data->files);
+       g_free (data->dbus_name);
+       g_slice_free (PeerFilesData, data);
+}
+
+static void
+peer_files_data_add_file (PeerFilesData *data,
+                          GFile         *file)
+{
+       g_ptr_array_add (data->files, file);
+}
+
+static void
+peer_files_data_remove_file (PeerFilesData *data,
+                             GFile         *file)
+{
+       gint i;
+
+       for (i = 0; i < data->files->len; i++) {
+               if (file != g_ptr_array_index (data->files, i))
+                       continue;
+
+               g_ptr_array_remove_index (data->files, i);
+               break;
+       }
+}
+
+static FilePeersData *
+file_peers_data_new (GFile *file)
+{
+       FilePeersData *data;
+
+       g_return_val_if_fail (G_IS_FILE (file), NULL);
+
+       data = g_slice_new0 (FilePeersData);
+       data->file = g_object_ref (file);
+       data->peers = g_ptr_array_new ();
+
+       return data;
+}
+
+static void
+file_peers_data_free (FilePeersData *data)
+{
+       g_object_unref (data->file);
+       g_ptr_array_unref (data->peers);
+       g_slice_free (FilePeersData, data);
+}
+
+static void
+file_peers_data_add_dbus_name (FilePeersData *data,
+                               gchar         *dbus_name)
+{
+       g_ptr_array_add (data->peers, dbus_name);
+}
+
+static void
+file_peers_data_remove_dbus_name (FilePeersData *data,
+                                  gchar         *dbus_name)
+{
+       gint i;
+
+       for (i = 0; i < data->peers->len; i++) {
+               if (dbus_name != g_ptr_array_index (data->peers, i))
+                       continue;
+
+               g_ptr_array_remove_index (data->peers, i);
+               break;
+       }
+}
+
+static void
+tracker_miner_files_peer_listener_finalize (GObject *object)
+{
+       TrackerMinerFilesPeerListener *listener;
+       TrackerMinerFilesPeerListenerPrivate *priv;
+
+       listener = TRACKER_MINER_FILES_PEER_LISTENER (object);
+       priv = tracker_miner_files_peer_listener_get_instance_private (listener);
+       g_hash_table_destroy (priv->peer_files);
+       g_hash_table_destroy (priv->file_peers);
+       g_object_unref (priv->d_connection);
+
+       G_OBJECT_CLASS (tracker_miner_files_peer_listener_parent_class)->finalize (object);
+}
+
+static void
+tracker_miner_files_peer_listener_set_property (GObject      *object,
+                                                guint         prop_id,
+                                                const GValue *value,
+                                                GParamSpec   *pspec)
+{
+       TrackerMinerFilesPeerListenerPrivate *priv;
+       TrackerMinerFilesPeerListener *listener;
+
+       listener = TRACKER_MINER_FILES_PEER_LISTENER (object);
+       priv = tracker_miner_files_peer_listener_get_instance_private (listener);
+
+       switch (prop_id) {
+       case PROP_CONNECTION:
+               priv->d_connection = g_value_dup_object (value);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+tracker_miner_files_peer_listener_get_property (GObject    *object,
+                                                guint       prop_id,
+                                                GValue     *value,
+                                                GParamSpec *pspec)
+{
+       TrackerMinerFilesPeerListenerPrivate *priv;
+       TrackerMinerFilesPeerListener *listener;
+
+       listener = TRACKER_MINER_FILES_PEER_LISTENER (object);
+       priv = tracker_miner_files_peer_listener_get_instance_private (listener);
+
+       switch (prop_id) {
+       case PROP_CONNECTION:
+               g_value_set_object (value, priv->d_connection);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+tracker_miner_files_peer_listener_class_init (TrackerMinerFilesPeerListenerClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+       object_class->finalize = tracker_miner_files_peer_listener_finalize;
+       object_class->set_property = tracker_miner_files_peer_listener_set_property;
+       object_class->get_property = tracker_miner_files_peer_listener_get_property;
+
+       g_object_class_install_property (object_class,
+                                        PROP_CONNECTION,
+                                        g_param_spec_object ("connection",
+                                                             "Connection",
+                                                             "Connection",
+                                                             G_TYPE_DBUS_CONNECTION,
+                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+       signals[WATCH_FILE] =
+               g_signal_new ("watch-file",
+                             G_OBJECT_CLASS_TYPE (object_class),
+                             G_SIGNAL_RUN_LAST, 0,
+                             NULL, NULL, NULL,
+                             G_TYPE_NONE, 1, G_TYPE_FILE);
+       signals[UNWATCH_FILE] =
+               g_signal_new ("unwatch-file",
+                             G_OBJECT_CLASS_TYPE (object_class),
+                             G_SIGNAL_RUN_LAST, 0,
+                             NULL, NULL, NULL,
+                             G_TYPE_NONE, 1, G_TYPE_FILE);
+}
+
+static void
+tracker_miner_files_peer_listener_init (TrackerMinerFilesPeerListener *listener)
+{
+       TrackerMinerFilesPeerListenerPrivate *priv;
+
+       priv = tracker_miner_files_peer_listener_get_instance_private (listener);
+       priv->peer_files = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
+                                                 (GDestroyNotify) peer_files_data_free);
+       priv->file_peers = g_hash_table_new_full (g_file_hash,
+                                                 (GEqualFunc) g_file_equal, NULL,
+                                                 (GDestroyNotify) file_peers_data_free);
+}
+
+TrackerMinerFilesPeerListener *
+tracker_miner_files_peer_listener_new (GDBusConnection *connection)
+{
+       return g_object_new (TRACKER_TYPE_MINER_FILES_PEER_LISTENER,
+                            "connection", connection,
+                            NULL);
+}
+
+static void
+unwatch_file (TrackerMinerFilesPeerListener *listener,
+              GFile                         *file)
+{
+       TrackerMinerFilesPeerListenerPrivate *priv;
+
+       priv = tracker_miner_files_peer_listener_get_instance_private (listener);
+
+       g_object_ref (file);
+       g_hash_table_remove (priv->file_peers, file);
+       g_signal_emit (listener, signals[UNWATCH_FILE], 0, file);
+       g_object_unref (file);
+}
+
+void
+tracker_miner_files_peer_listener_add_watch (TrackerMinerFilesPeerListener *listener,
+                                             const gchar                   *dbus_name,
+                                             GFile                         *file)
+{
+       TrackerMinerFilesPeerListenerPrivate *priv;
+       PeerFilesData *peer_data;
+       FilePeersData *file_data;
+
+       g_return_if_fail (TRACKER_IS_MINER_FILES_PEER_LISTENER (listener));
+       g_return_if_fail (G_IS_FILE (file));
+       g_return_if_fail (dbus_name != NULL);
+
+       priv = tracker_miner_files_peer_listener_get_instance_private (listener);
+
+       peer_data = g_hash_table_lookup (priv->peer_files, dbus_name);
+       file_data = g_hash_table_lookup (priv->file_peers, file);
+
+       if (!peer_data) {
+               peer_data = peer_files_data_new (dbus_name, listener);
+               g_hash_table_insert (priv->peer_files,
+                                    peer_data->dbus_name, peer_data);
+       }
+
+       if (!file_data) {
+               gchar *uri;
+
+               file_data = file_peers_data_new (file);
+               g_hash_table_insert (priv->file_peers,
+                                    file_data->file, file_data);
+               g_signal_emit (listener, signals[WATCH_FILE], 0, file_data->file);
+
+               uri = g_file_get_uri (file);
+               g_debug ("Client '%s' requests watch on '%s'", dbus_name, uri);
+               g_free (uri);
+       }
+
+       peer_files_data_add_file (peer_data, file_data->file);
+       file_peers_data_add_dbus_name (file_data, peer_data->dbus_name);
+}
+
+void
+tracker_miner_files_peer_listener_remove_watch (TrackerMinerFilesPeerListener *listener,
+                                                const gchar                   *dbus_name,
+                                                GFile                         *file)
+{
+       TrackerMinerFilesPeerListenerPrivate *priv;
+       PeerFilesData *peer_data;
+       FilePeersData *file_data;
+
+       g_return_if_fail (TRACKER_IS_MINER_FILES_PEER_LISTENER (listener));
+       g_return_if_fail (G_IS_FILE (file));
+       g_return_if_fail (dbus_name != NULL);
+
+       priv = tracker_miner_files_peer_listener_get_instance_private (listener);
+
+       peer_data = g_hash_table_lookup (priv->peer_files, dbus_name);
+       file_data = g_hash_table_lookup (priv->file_peers, file);
+
+       if (!file_data || !peer_data)
+               return;
+
+       peer_files_data_remove_file (peer_data, file_data->file);
+       file_peers_data_remove_dbus_name (file_data, peer_data->dbus_name);
+
+       if (peer_data->files->len == 0)
+               g_hash_table_remove (priv->peer_files, peer_data->dbus_name);
+
+       if (file_data->peers->len == 0)
+               unwatch_file (listener, file_data->file);
+}
+
+void
+tracker_miner_files_peer_listener_remove_dbus_name (TrackerMinerFilesPeerListener *listener,
+                                                    const gchar                   *dbus_name)
+{
+       TrackerMinerFilesPeerListenerPrivate *priv;
+       PeerFilesData *peer_data;
+       FilePeersData *file_data;
+       GFile *file;
+       gint i;
+
+       g_return_if_fail (TRACKER_IS_MINER_FILES_PEER_LISTENER (listener));
+       g_return_if_fail (dbus_name != NULL);
+
+       priv = tracker_miner_files_peer_listener_get_instance_private (listener);
+       peer_data = g_hash_table_lookup (priv->peer_files, dbus_name);
+
+       if (!peer_data)
+               return;
+
+       g_debug ("Removing all watches from client '%s'", dbus_name);
+
+       for (i = 0; i < peer_data->files->len; i++) {
+               file = g_ptr_array_index (peer_data->files, i);
+               file_data = g_hash_table_lookup (priv->file_peers, file);
+
+               if (!file_data)
+                       continue;
+
+               file_peers_data_remove_dbus_name (file_data, peer_data->dbus_name);
+
+               if (file_data->peers->len == 0)
+                       unwatch_file (listener, file_data->file);
+       }
+
+       g_hash_table_remove (priv->peer_files, dbus_name);
+}
+
+void
+tracker_miner_files_peer_listener_remove_file (TrackerMinerFilesPeerListener *listener,
+                                               GFile                         *file)
+{
+       TrackerMinerFilesPeerListenerPrivate *priv;
+       PeerFilesData *peer_data;
+       FilePeersData *file_data;
+       const gchar *dbus_name;
+       gchar *uri;
+       gint i;
+
+       g_return_if_fail (TRACKER_IS_MINER_FILES_PEER_LISTENER (listener));
+       g_return_if_fail (G_IS_FILE (file));
+
+       priv = tracker_miner_files_peer_listener_get_instance_private (listener);
+       file_data = g_hash_table_lookup (priv->file_peers, file);
+
+       if (!file_data || file_data->peers->len == 0)
+               return;
+
+       uri = g_file_get_uri (file);
+       g_debug ("Removing client listeners for file '%s'", uri);
+       g_free (uri);
+
+       for (i = 0; i < file_data->peers->len; i++) {
+               dbus_name = g_ptr_array_index (file_data->peers, i);
+               peer_data = g_hash_table_lookup (priv->peer_files, dbus_name);
+
+               if (!peer_data)
+                       continue;
+
+               peer_files_data_remove_file (peer_data, file_data->file);
+
+               if (peer_data->files->len == 0)
+                       g_hash_table_remove (priv->peer_files, dbus_name);
+       }
+
+       unwatch_file (listener, file);
+}
+
+gboolean
+tracker_miner_files_peer_listener_is_file_watched (TrackerMinerFilesPeerListener *listener,
+                                                   GFile                         *file)
+{
+       TrackerMinerFilesPeerListenerPrivate *priv;
+
+       g_return_if_fail (TRACKER_IS_MINER_FILES_PEER_LISTENER (listener));
+       g_return_if_fail (G_IS_FILE (file));
+
+       priv = tracker_miner_files_peer_listener_get_instance_private (listener);
+
+       return g_hash_table_lookup (priv->file_peers, file) != NULL;
+}
diff --git a/src/miners/fs/tracker-miner-files-peer-listener.h 
b/src/miners/fs/tracker-miner-files-peer-listener.h
new file mode 100644
index 0000000..7a23d32
--- /dev/null
+++ b/src/miners/fs/tracker-miner-files-peer-listener.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015, Carlos Garnacho
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ *
+ * Author: Carlos Garnacho <carlosg gnome org>
+ */
+
+#ifndef __TRACKER_MINER_FILES_PEER_LISTENER_H__
+#define __TRACKER_MINER_FILES_PEER_LISTENER_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#define TRACKER_TYPE_MINER_FILES_PEER_LISTENER            (tracker_miner_files_peer_listener_get_type ())
+#define TRACKER_MINER_FILES_PEER_LISTENER(object)         (G_TYPE_CHECK_INSTANCE_CAST ((object), 
TRACKER_TYPE_MINER_FILES_PEER_LISTENER, TrackerMinerFilesPeerListener))
+#define TRACKER_MINER_FILES_PEER_LISTENER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), 
TRACKER_TYPE_DBUS_MINER_FILES_PEER_LISTENER, TrackerMinerFilesPeerListenerClass))
+#define TRACKER_IS_MINER_FILES_PEER_LISTENER(object)      (G_TYPE_CHECK_INSTANCE_TYPE ((object), 
TRACKER_TYPE_MINER_FILES_PEER_LISTENER))
+#define TRACKER_IS_MINER_FILES_PEER_LISTENER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), 
TRACKER_TYPE_MINER_FILES_PEER_LISTENER))
+#define TRACKER_MINER_FILES_PEER_LISTENER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), 
TRACKER_TYPE_MINER_FILES_PEER_LISTENER, TrackerMinerFilesPeerListenerClass))
+
+typedef struct _TrackerMinerFilesPeerListener TrackerMinerFilesPeerListener;
+typedef struct _TrackerMinerFilesPeerListenerClass TrackerMinerFilesPeerListenerClass;
+
+struct _TrackerMinerFilesPeerListener {
+       GObject parent_instance;
+};
+
+struct _TrackerMinerFilesPeerListenerClass {
+       GObjectClass parent_class;
+};
+
+GType tracker_miner_files_peer_listener_get_type     (void) G_GNUC_CONST;
+
+TrackerMinerFilesPeerListener *
+         tracker_miner_files_peer_listener_new          (GDBusConnection               *connection);
+
+void     tracker_miner_files_peer_listener_add_watch    (TrackerMinerFilesPeerListener *listener,
+                                                         const gchar                   *dbus_name,
+                                                         GFile                         *file);
+void     tracker_miner_files_peer_listener_remove_watch (TrackerMinerFilesPeerListener *listener,
+                                                         const gchar                   *dbus_name,
+                                                         GFile                         *file);
+
+void     tracker_miner_files_peer_listener_remove_dbus_name (TrackerMinerFilesPeerListener *listener,
+                                                             const gchar                   *dbus_name);
+void     tracker_miner_files_peer_listener_remove_file      (TrackerMinerFilesPeerListener *listener,
+                                                             GFile                         *file);
+gboolean tracker_miner_files_peer_listener_is_file_watched  (TrackerMinerFilesPeerListener *listener,
+                                                             GFile                         *file);
+
+#endif /* __TRACKER_MINER_FILES_PEER_LISTENER_H__ */


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