[tracker] libtracker-miner: Prevent double unref of cached GFile objects



commit eb715b4ac89a99672a6ca35973f465ce4a1e30c5
Author: Sam Thursfield <sam thursfield codethink co uk>
Date:   Wed Jun 13 17:45:09 2012 +0100

    libtracker-miner: Prevent double unref of cached GFile objects
    
    The reference owned by the TrackerFileSystem cache may be removed
    more than once. Add a flag to ensure that the cache will only ever
    unref it once, even if it is being kept alive in the cache by
    references held elsewhere in the code.
    
    tracker_file_system_delete_files() is renamed to
    tracker_file_system_forget_files() to avoid confusion.
    
    Fixes GB#676849

 src/libtracker-miner/tracker-file-notifier.c |   14 +++++----
 src/libtracker-miner/tracker-file-system.c   |   38 +++++++++++++++++++++-----
 src/libtracker-miner/tracker-file-system.h   |    2 +-
 3 files changed, 40 insertions(+), 14 deletions(-)
---
diff --git a/src/libtracker-miner/tracker-file-notifier.c b/src/libtracker-miner/tracker-file-notifier.c
index 510f64b..75ab022 100644
--- a/src/libtracker-miner/tracker-file-notifier.c
+++ b/src/libtracker-miner/tracker-file-notifier.c
@@ -279,8 +279,10 @@ file_notifier_traverse_tree (TrackerFileNotifier *notifier)
 		                              notifier);
 	}
 
-	/* We dispose regular files, only directories are cached */
-	tracker_file_system_delete_files (priv->file_system,
+	/* We dispose regular files here, only directories are cached once crawling
+	 * has completed.
+	 */
+	tracker_file_system_forget_files (priv->file_system,
 	                                  current_root,
 	                                  G_FILE_TYPE_REGULAR);
 
@@ -839,8 +841,8 @@ monitor_item_deleted_cb (TrackerMonitor *monitor,
 	g_signal_emit (notifier, signals[FILE_DELETED], 0, canonical);
 
 	if (is_directory) {
-		/* Delete all files underneath this dir from the filesystem */
-		tracker_file_system_delete_files (priv->file_system,
+		/* Remove all files underneath this dir from the cache */
+		tracker_file_system_forget_files (priv->file_system,
 						  file,
 						  G_FILE_TYPE_UNKNOWN);
 	}
@@ -1087,8 +1089,8 @@ indexing_tree_directory_removed (TrackerIndexingTree *indexing_tree,
 	/* Remove monitors if any */
 	tracker_monitor_remove_recursively (priv->monitor, directory);
 
-	/* Remove all files from filesystem */
-	tracker_file_system_delete_files (priv->file_system, directory,
+	/* Remove all files from cache */
+	tracker_file_system_forget_files (priv->file_system, directory,
 	                                  G_FILE_TYPE_UNKNOWN);
 }
 
diff --git a/src/libtracker-miner/tracker-file-system.c b/src/libtracker-miner/tracker-file-system.c
index 269df32..193a8d4 100644
--- a/src/libtracker-miner/tracker-file-system.c
+++ b/src/libtracker-miner/tracker-file-system.c
@@ -45,6 +45,7 @@ struct _FileNodeData {
 	gchar *uri_suffix;
 	GArray *properties;
 	guint shallow   : 1;
+	guint unowned : 1;
 	guint file_type : 4;
 };
 
@@ -66,6 +67,14 @@ G_DEFINE_TYPE (TrackerFileSystem, tracker_file_system, G_TYPE_OBJECT)
  *     comparisons on them.
  *   - Stores data for the GFile lifetime, so it may be used as cache store
  *     as long as some file is needed.
+ *
+ * The TrackerFileSystem holds a reference on each GFile. There are two cases
+ * when we want to force a cached GFile to be freed: when it no longer exists
+ * on disk, and once crawling a directory has completed and we only need to
+ * remember the directories. Objects may persist in the cache even after
+ * tracker_file_system_forget_files() is called to delete them if there are
+ * references held on them elsewhere, and they will stay until all references
+ * are dropped.
  */
 
 
@@ -82,7 +91,9 @@ file_node_data_free (FileNodeData *data,
 			                     node);
 		}
 
-		g_object_unref (data->file);
+		if (!data->unowned) {
+			g_object_unref (data->file);
+		}
 	}
 
 	data->file = NULL;
@@ -820,13 +831,13 @@ typedef struct {
 	TrackerFileSystem *file_system;
 	GList *list;
 	GFileType file_type;
-} DeleteFilesData;
+} ForgetFilesData;
 
 static gboolean
 append_deleted_files (GNode    *node,
 		      gpointer  user_data)
 {
-	DeleteFilesData *data;
+	ForgetFilesData *data;
 	FileNodeData *node_data;
 
 	data = user_data;
@@ -834,18 +845,31 @@ append_deleted_files (GNode    *node,
 
 	if (data->file_type == G_FILE_TYPE_UNKNOWN ||
 	    node_data->file_type == data->file_type) {
-		data->list = g_list_prepend (data->list, node_data->file);
+		data->list = g_list_prepend (data->list, node_data);
 	}
 
 	return FALSE;
 }
 
+static void
+forget_file (FileNodeData *node_data)
+{
+	if (!node_data->unowned) {
+		node_data->unowned = TRUE;
+
+		/* Weak reference handler will remove the file from the tree and
+		 * clean up node_data if this is the final reference.
+		 */
+		g_object_unref (node_data->file);
+	}
+}
+
 void
-tracker_file_system_delete_files (TrackerFileSystem *file_system,
+tracker_file_system_forget_files (TrackerFileSystem *file_system,
 				  GFile             *root,
 				  GFileType          file_type)
 {
-	DeleteFilesData data = { file_system, NULL, file_type };
+	ForgetFilesData data = { file_system, NULL, file_type };
 	GNode *node;
 
 	g_return_if_fail (TRACKER_IS_FILE_SYSTEM (file_system));
@@ -864,6 +888,6 @@ tracker_file_system_delete_files (TrackerFileSystem *file_system,
 	                 -1, append_deleted_files,
 	                 &data);
 
-	g_list_foreach (data.list, (GFunc) g_object_unref, NULL);
+	g_list_foreach (data.list, (GFunc) forget_file, NULL);
 	g_list_free (data.list);
 }
diff --git a/src/libtracker-miner/tracker-file-system.h b/src/libtracker-miner/tracker-file-system.h
index 575ccb5..d06949c 100644
--- a/src/libtracker-miner/tracker-file-system.h
+++ b/src/libtracker-miner/tracker-file-system.h
@@ -71,7 +71,7 @@ void          tracker_file_system_traverse       (TrackerFileSystem
                                                   TrackerFileSystemTraverseFunc  func,
                                                   gpointer                       user_data);
 
-void          tracker_file_system_delete_files   (TrackerFileSystem *file_system,
+void          tracker_file_system_forget_files   (TrackerFileSystem *file_system,
 						  GFile             *root,
 						  GFileType          file_type);
 



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