[tracker] libtracker-miner, tracker-miner-fs: Only update FileLastModified and FileLastAccessed on file attrib



commit e90189ec93ec1f1a586e6c82686dae5268622ed9
Author: Aleksander Morgado <aleksander lanedo com>
Date:   Tue Sep 21 11:54:10 2010 +0200

    libtracker-miner, tracker-miner-fs: Only update FileLastModified and FileLastAccessed on file attributes updated

 src/libtracker-miner/tracker-miner-fs.c    |   95 +++++++++++++++++++----
 src/libtracker-miner/tracker-miner-fs.h    |    4 +
 src/miners/fs/tracker-miner-applications.c |   47 ++++++++---
 src/miners/fs/tracker-miner-files.c        |  118 ++++++++++++++++++++++++++++
 4 files changed, 235 insertions(+), 29 deletions(-)
---
diff --git a/src/libtracker-miner/tracker-miner-fs.c b/src/libtracker-miner/tracker-miner-fs.c
index 2bab374..1d65618 100644
--- a/src/libtracker-miner/tracker-miner-fs.c
+++ b/src/libtracker-miner/tracker-miner-fs.c
@@ -184,6 +184,7 @@ enum {
 	CHECK_DIRECTORY_CONTENTS,
 	MONITOR_DIRECTORY,
 	PROCESS_FILE,
+	PROCESS_FILE_ATTRIBUTES,
 	IGNORE_NEXT_UPDATE_FILE,
 	FINISHED,
 	LAST_SIGNAL
@@ -455,6 +456,40 @@ tracker_miner_fs_class_init (TrackerMinerFSClass *klass)
 		              3, G_TYPE_FILE, TRACKER_SPARQL_TYPE_BUILDER, G_TYPE_CANCELLABLE);
 
 	/**
+	 * TrackerMinerFS::process-file-attributes:
+	 * @miner_fs: the #TrackerMinerFS
+	 * @file: a #GFile
+	 * @builder: a #TrackerSparqlBuilder
+	 * @cancellable: a #GCancellable
+	 *
+	 * The ::process-file-attributes signal is emitted whenever a file should
+	 * be processed, but only the attribute-related metadata extracted.
+	 *
+	 * @builder is the #TrackerSparqlBuilder where all sparql updates
+	 * to be performed for @file will be appended. For the properties being
+	 * updated, the DELETE statements should be included as well.
+	 *
+	 * This signal allows both synchronous and asynchronous extraction,
+	 * in the synchronous case @cancellable can be safely ignored. In
+	 * either case, on successful metadata extraction, implementations
+	 * must call tracker_miner_fs_file_notify() to indicate that
+	 * processing has finished on @file, so the miner can execute
+	 * the SPARQL updates and continue processing other files.
+	 *
+	 * Returns: %TRUE if the file is accepted for processing,
+	 *          %FALSE if the file should be ignored.
+	 **/
+	signals[PROCESS_FILE_ATTRIBUTES] =
+		g_signal_new ("process-file-attributes",
+		              G_OBJECT_CLASS_TYPE (object_class),
+		              G_SIGNAL_RUN_LAST,
+		              G_STRUCT_OFFSET (TrackerMinerFSClass, process_file_attributes),
+		              NULL, NULL,
+		              tracker_marshal_BOOLEAN__OBJECT_OBJECT_OBJECT,
+		              G_TYPE_BOOLEAN,
+		              3, G_TYPE_FILE, TRACKER_SPARQL_TYPE_BUILDER, G_TYPE_CANCELLABLE);
+
+	/**
 	 * TrackerMinerFS::ignore-next-update-file:
 	 * @miner_fs: the #TrackerMinerFS
 	 * @file: a #GFile
@@ -1428,18 +1463,28 @@ do_process_file (TrackerMinerFS *fs,
 {
 	TrackerMinerFSPrivate *priv;
 	gboolean processing;
+	gboolean attribute_update_only;
+	gchar *uri;
 
+	uri = g_file_get_uri (data->file);
 	priv = fs->private;
 
-	g_signal_emit (fs, signals[PROCESS_FILE], 0,
-	               data->file, data->builder, data->cancellable,
-	               &processing);
-
-	if (!processing) {
-		gchar *uri;
+	attribute_update_only = GPOINTER_TO_INT (g_object_get_qdata (G_OBJECT (data->file),
+	                                                             priv->quark_attribute_updated));
 
-		uri = g_file_get_uri (data->file);
+	if (!attribute_update_only) {
+		g_debug ("Processing file '%s'...", uri);
+		g_signal_emit (fs, signals[PROCESS_FILE], 0,
+		               data->file, data->builder, data->cancellable,
+		               &processing);
+	} else {
+		g_debug ("Processing attributes in file '%s'...", uri);
+		g_signal_emit (fs, signals[PROCESS_FILE_ATTRIBUTES], 0,
+		               data->file, data->builder, data->cancellable,
+		               &processing);
+	}
 
+	if (!processing) {
 		/* Re-fetch data, since it might have been
 		 * removed in broken implementations
 		 */
@@ -1456,10 +1501,10 @@ do_process_file (TrackerMinerFS *fs,
 			priv->processing_pool = g_list_remove (priv->processing_pool, data);
 			process_data_free (data);
 		}
-
-		g_free (uri);
 	}
 
+	g_free (uri);
+
 	return processing;
 }
 
@@ -1510,13 +1555,31 @@ item_add_or_update_cb (TrackerMinerFS *fs,
 		gchar *full_sparql;
 
 		if (data->urn) {
-			g_debug ("Updating item '%s' with urn '%s'", uri, data->urn);
-
-			/* update, delete all statements inserted by miner
-			   except for rdf:type statements as they could cause implicit deletion of user data */
-			full_sparql = g_strdup_printf ("DELETE { GRAPH <%s> { <%s> ?p ?o } } WHERE { GRAPH <%s> { <%s> ?p ?o FILTER (?p != rdf:type) } } %s",
-			                               TRACKER_MINER_FS_GRAPH_URN, data->urn, TRACKER_MINER_FS_GRAPH_URN,
-			                               data->urn, tracker_sparql_builder_get_result (data->builder));
+			gboolean attribute_update_only;
+
+			attribute_update_only = GPOINTER_TO_INT (g_object_steal_qdata (G_OBJECT (data->file),
+			                                                               fs->private->quark_attribute_updated));
+			g_debug ("Updating item '%s' with urn '%s'%s",
+			         uri,
+			         data->urn,
+			         attribute_update_only ? " (attributes only)" : "");
+
+			if (!attribute_update_only) {
+				/* update, delete all statements inserted by miner
+				 * except for rdf:type statements as they could cause implicit deletion of user data */
+				full_sparql = g_strdup_printf ("DELETE { GRAPH <%s> { <%s> ?p ?o } } "
+				                               "WHERE { GRAPH <%s> { <%s> ?p ?o FILTER (?p != rdf:type) } } %s",
+				                               TRACKER_MINER_FS_GRAPH_URN,
+				                               data->urn,
+				                               TRACKER_MINER_FS_GRAPH_URN,
+				                               data->urn,
+				                               tracker_sparql_builder_get_result (data->builder));
+			} else {
+				/* Do not drop graph if only updating attributes, the SPARQL builder
+				 * will already contain the necessary DELETE statements for the properties
+				 * being updated */
+				full_sparql = g_strdup (tracker_sparql_builder_get_result (data->builder));
+			}
 		} else {
 			g_debug ("Creating new item '%s'", uri);
 
diff --git a/src/libtracker-miner/tracker-miner-fs.h b/src/libtracker-miner/tracker-miner-fs.h
index 3e7acac..c8f1757 100644
--- a/src/libtracker-miner/tracker-miner-fs.h
+++ b/src/libtracker-miner/tracker-miner-fs.h
@@ -92,6 +92,10 @@ typedef struct {
 	gboolean (* monitor_directory)        (TrackerMinerFS       *fs,
 	                                       GFile                *file);
 	void     (* finished)                 (TrackerMinerFS       *fs);
+	gboolean (* process_file_attributes)  (TrackerMinerFS       *fs,
+	                                       GFile                *file,
+	                                       TrackerSparqlBuilder *builder,
+	                                       GCancellable         *cancellable);
 } TrackerMinerFSClass;
 
 GType                 tracker_miner_fs_get_type             (void) G_GNUC_CONST;
diff --git a/src/miners/fs/tracker-miner-applications.c b/src/miners/fs/tracker-miner-applications.c
index 6b756f9..3ad4346 100644
--- a/src/miners/fs/tracker-miner-applications.c
+++ b/src/miners/fs/tracker-miner-applications.c
@@ -31,19 +31,23 @@
 #define SOFTWARE_CATEGORY_URN_PREFIX "urn:software-category:"
 #define THEME_ICON_URN_PREFIX        "urn:theme-icon:"
 
-static void     miner_applications_finalize          (GObject              *object);
-static void     miner_applications_constructed       (GObject              *object);
-
-static gboolean miner_applications_check_file        (TrackerMinerFS       *fs,
-                                                      GFile                *file);
-static gboolean miner_applications_check_directory   (TrackerMinerFS       *fs,
-                                                      GFile                *file);
-static gboolean miner_applications_process_file      (TrackerMinerFS       *fs,
-                                                      GFile                *file,
-                                                      TrackerSparqlBuilder *sparql,
-                                                      GCancellable         *cancellable);
-static gboolean miner_applications_monitor_directory (TrackerMinerFS       *fs,
-                                                      GFile                *file);
+static void     miner_applications_finalize                (GObject              *object);
+static void     miner_applications_constructed             (GObject              *object);
+
+static gboolean miner_applications_check_file              (TrackerMinerFS       *fs,
+                                                            GFile                *file);
+static gboolean miner_applications_check_directory         (TrackerMinerFS       *fs,
+                                                            GFile                *file);
+static gboolean miner_applications_process_file            (TrackerMinerFS       *fs,
+                                                            GFile                *file,
+                                                            TrackerSparqlBuilder *sparql,
+                                                            GCancellable         *cancellable);
+static gboolean miner_applications_process_file_attributes (TrackerMinerFS       *fs,
+                                                            GFile                *file,
+                                                            TrackerSparqlBuilder *sparql,
+                                                            GCancellable         *cancellable);
+static gboolean miner_applications_monitor_directory       (TrackerMinerFS       *fs,
+                                                            GFile                *file);
 
 static GQuark miner_applications_error_quark = 0;
 
@@ -73,6 +77,7 @@ tracker_miner_applications_class_init (TrackerMinerApplicationsClass *klass)
 	miner_fs_class->check_directory = miner_applications_check_directory;
 	miner_fs_class->monitor_directory = miner_applications_monitor_directory;
 	miner_fs_class->process_file = miner_applications_process_file;
+	miner_fs_class->process_file_attributes = miner_applications_process_file_attributes;
 
 	miner_applications_error_quark = g_quark_from_static_string ("TrackerMinerApplications");
 }
@@ -615,6 +620,22 @@ miner_applications_process_file (TrackerMinerFS       *fs,
 	return TRUE;
 }
 
+static gboolean
+miner_applications_process_file_attributes (TrackerMinerFS       *fs,
+                                            GFile                *file,
+                                            TrackerSparqlBuilder *sparql,
+                                            GCancellable         *cancellable)
+{
+	gchar *uri;
+
+	/* We don't care about file attribute changes here */
+	uri = g_file_get_uri (file);
+	g_debug ("Ignoring file attribute changes in '%s'", uri);
+	g_free (uri);
+
+	return FALSE;
+}
+
 TrackerMiner *
 tracker_miner_applications_new (void)
 {
diff --git a/src/miners/fs/tracker-miner-files.c b/src/miners/fs/tracker-miner-files.c
index 1ab9577..a5d2170 100644
--- a/src/miners/fs/tracker-miner-files.c
+++ b/src/miners/fs/tracker-miner-files.c
@@ -187,6 +187,10 @@ static gboolean    miner_files_process_file             (TrackerMinerFS       *f
                                                          GFile                *file,
                                                          TrackerSparqlBuilder *sparql,
                                                          GCancellable         *cancellable);
+static gboolean    miner_files_process_file_attributes  (TrackerMinerFS       *fs,
+                                                         GFile                *file,
+                                                         TrackerSparqlBuilder *sparql,
+                                                         GCancellable         *cancellable);
 static gboolean    miner_files_monitor_directory        (TrackerMinerFS       *fs,
                                                          GFile                *file);
 static gboolean    miner_files_ignore_next_update_file  (TrackerMinerFS       *fs,
@@ -233,6 +237,7 @@ tracker_miner_files_class_init (TrackerMinerFilesClass *klass)
 	miner_fs_class->check_directory_contents = miner_files_check_directory_contents;
 	miner_fs_class->monitor_directory = miner_files_monitor_directory;
 	miner_fs_class->process_file = miner_files_process_file;
+	miner_fs_class->process_file_attributes = miner_files_process_file_attributes;
 	miner_fs_class->ignore_next_update_file = miner_files_ignore_next_update_file;
         miner_fs_class->finished = miner_files_finished;
 
@@ -2219,6 +2224,119 @@ miner_files_process_file (TrackerMinerFS       *fs,
 	return TRUE;
 }
 
+static void
+process_file_attributes_cb (GObject      *object,
+                            GAsyncResult *result,
+                            gpointer      user_data)
+{
+	TrackerSparqlBuilder *sparql;
+	ProcessFileData *data;
+	const gchar *urn;
+	GFileInfo *file_info;
+	guint64 time_;
+	GFile *file;
+	gchar *uri;
+	GError *error = NULL;
+	gboolean is_iri;
+
+	data = user_data;
+	file = G_FILE (object);
+	sparql = data->sparql;
+	file_info = g_file_query_info_finish (file, result, &error);
+
+	if (error) {
+		/* Something bad happened, notify about the error */
+		tracker_miner_fs_file_notify (TRACKER_MINER_FS (data->miner), file, error);
+		process_file_data_free (data);
+		g_error_free (error);
+		return;
+	}
+
+	uri = g_file_get_uri (file);
+	urn = miner_files_get_file_urn (TRACKER_MINER_FILES (data->miner), file, &is_iri);
+
+	/* We MUST have an IRI in attributes updating */
+	if (!is_iri) {
+		error = g_error_new_literal (miner_files_error_quark,
+		                             0,
+		                             "Received request to update attributes but no IRI available!");
+		/* Notify about the error */
+		tracker_miner_fs_file_notify (TRACKER_MINER_FS (data->miner), file, error);
+		process_file_data_free (data);
+		g_error_free (error);
+		return;
+	}
+
+	/* DELETE old property values */
+	tracker_sparql_builder_delete_open (sparql, TRACKER_MINER_FS_GRAPH_URN);
+	tracker_sparql_builder_subject_iri (sparql, urn);
+	tracker_sparql_builder_predicate (sparql, "nfo:fileLastModified");
+	tracker_sparql_builder_object_variable (sparql, "lastmodified");
+	tracker_sparql_builder_predicate (sparql, "nfo:fileLastAccessed");
+	tracker_sparql_builder_object_variable (sparql, "lastaccessed");
+	tracker_sparql_builder_delete_close (sparql);
+
+	tracker_sparql_builder_where_open (sparql);
+	tracker_sparql_builder_subject_iri (sparql, urn);
+	tracker_sparql_builder_predicate (sparql, "nfo:fileLastModified");
+	tracker_sparql_builder_object_variable (sparql, "lastmodified");
+	tracker_sparql_builder_predicate (sparql, "nfo:fileLastAccessed");
+	tracker_sparql_builder_object_variable (sparql, "lastaccessed");
+	tracker_sparql_builder_where_close (sparql);
+
+	/* INSERT new property values */
+	tracker_sparql_builder_insert_open (sparql, TRACKER_MINER_FS_GRAPH_URN);
+	tracker_sparql_builder_subject_iri (sparql, urn);
+
+	time_ = g_file_info_get_attribute_uint64 (file_info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
+	tracker_sparql_builder_predicate (sparql, "nfo:fileLastModified");
+	tracker_sparql_builder_object_date (sparql, (time_t *) &time_);
+
+	time_ = g_file_info_get_attribute_uint64 (file_info, G_FILE_ATTRIBUTE_TIME_ACCESS);
+	tracker_sparql_builder_predicate (sparql, "nfo:fileLastAccessed");
+	tracker_sparql_builder_object_date (sparql, (time_t *) &time_);
+
+	tracker_sparql_builder_insert_close (sparql);
+
+	g_object_unref (file_info);
+	g_free (uri);
+
+	/* Notify about the success */
+	tracker_miner_fs_file_notify (TRACKER_MINER_FS (data->miner), data->file, NULL);
+
+	process_file_data_free (data);
+}
+
+static gboolean
+miner_files_process_file_attributes (TrackerMinerFS       *fs,
+                                     GFile                *file,
+                                     TrackerSparqlBuilder *sparql,
+                                     GCancellable         *cancellable)
+{
+	ProcessFileData *data;
+	const gchar *attrs;
+
+	data = g_slice_new0 (ProcessFileData);
+	data->miner = g_object_ref (fs);
+	data->cancellable = g_object_ref (cancellable);
+	data->sparql = g_object_ref (sparql);
+	data->file = g_object_ref (file);
+
+	/* Query only attributes that may change in an ATTRIBUTES_UPDATED event */
+	attrs = G_FILE_ATTRIBUTE_TIME_MODIFIED ","
+		G_FILE_ATTRIBUTE_TIME_ACCESS;
+
+	g_file_query_info_async (file,
+	                         attrs,
+	                         G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+	                         G_PRIORITY_DEFAULT,
+	                         cancellable,
+	                         process_file_attributes_cb,
+	                         data);
+
+	return TRUE;
+}
+
 static gboolean
 miner_files_ignore_next_update_file (TrackerMinerFS       *fs,
                                      GFile                *file,



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