[tracker] libtracker-miner: Prevent double unref of cached GFile objects
- From: Sam Thursfield <sthursfield src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker] libtracker-miner: Prevent double unref of cached GFile objects
- Date: Fri, 15 Jun 2012 21:09:11 +0000 (UTC)
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]