[tracker/property-changes] libtracker-data: Ontology change coping for property changes



commit 820a92eafeb5e9b77e814be6e052968c33000af1
Author: Philip Van Hoof <philip codeminded be>
Date:   Fri Apr 2 14:13:43 2010 +0200

    libtracker-data: Ontology change coping for property changes
    
    This post-check checks for property properties being removed from a class.
    Just checking for tracker:indexed is, for example, not sufficient: It's
    possible that the line got removed from the TTL file. So a post check is
    needed to compare the old situation with the new situation, on top of the
    already added checks comparing values.

 src/libtracker-data/tracker-class.c        |   26 ++++
 src/libtracker-data/tracker-class.h        |    5 +-
 src/libtracker-data/tracker-data-manager.c |  215 +++++++++++++++++++++++++---
 src/libtracker-data/tracker-data-manager.h |    7 +-
 src/libtracker-data/tracker-data-update.c  |   39 +++++-
 src/libtracker-data/tracker-property.c     |   26 ++++
 src/libtracker-data/tracker-property.h     |    3 +
 7 files changed, 290 insertions(+), 31 deletions(-)
---
diff --git a/src/libtracker-data/tracker-class.c b/src/libtracker-data/tracker-class.c
index 7b39c96..501dd9b 100644
--- a/src/libtracker-data/tracker-class.c
+++ b/src/libtracker-data/tracker-class.c
@@ -40,6 +40,7 @@ struct _TrackerClassPriv {
 	gint id;
 	gboolean is_new;
 	gboolean need_recreate;
+	gboolean notify;
 
 	GArray *super_classes;
 };
@@ -167,6 +168,18 @@ tracker_class_get_is_new (TrackerClass *service)
 }
 
 gboolean
+tracker_class_get_notify (TrackerClass *service)
+{
+	TrackerClassPriv *priv;
+
+	g_return_val_if_fail (TRACKER_IS_CLASS (service), FALSE);
+
+	priv = GET_PRIV (service);
+
+	return priv->notify;
+}
+
+gboolean
 tracker_class_get_need_recreate (TrackerClass *service)
 {
 	TrackerClassPriv *priv;
@@ -275,6 +288,19 @@ tracker_class_set_is_new (TrackerClass *service,
 }
 
 void
+tracker_class_set_notify (TrackerClass *service,
+                          gboolean         value)
+{
+	TrackerClassPriv *priv;
+
+	g_return_if_fail (TRACKER_IS_CLASS (service));
+
+	priv = GET_PRIV (service);
+
+	priv->notify = value;
+}
+
+void
 tracker_class_set_need_recreate (TrackerClass *service,
                                  gboolean         value)
 {
diff --git a/src/libtracker-data/tracker-class.h b/src/libtracker-data/tracker-class.h
index 8282606..0b1725b 100644
--- a/src/libtracker-data/tracker-class.h
+++ b/src/libtracker-data/tracker-class.h
@@ -55,8 +55,9 @@ gint            tracker_class_get_count         (TrackerClass  *service);
 gint            tracker_class_get_id            (TrackerClass  *service);
 gboolean        tracker_class_get_is_new        (TrackerClass  *service);
 gboolean        tracker_class_get_need_recreate (TrackerClass  *service);
-
+gboolean        tracker_class_get_notify        (TrackerClass  *service);
 TrackerClass  **tracker_class_get_super_classes (TrackerClass  *service);
+
 void            tracker_class_set_uri           (TrackerClass  *service,
                                                  const gchar   *value);
 void            tracker_class_set_count         (TrackerClass  *service,
@@ -69,6 +70,8 @@ void            tracker_class_set_is_new        (TrackerClass  *service,
                                                  gboolean       value);
 void            tracker_class_set_need_recreate (TrackerClass  *service,
                                                  gboolean       value);
+void            tracker_class_set_notify        (TrackerClass  *service,
+                                                 gboolean       value);
 
 G_END_DECLS
 
diff --git a/src/libtracker-data/tracker-data-manager.c b/src/libtracker-data/tracker-data-manager.c
index b75785a..7b4030a 100644
--- a/src/libtracker-data/tracker-data-manager.c
+++ b/src/libtracker-data/tracker-data-manager.c
@@ -188,6 +188,28 @@ update_property_value (const gchar *kind,
 	return needed;
 }
 
+
+static void
+fix_indexed (TrackerProperty *property, gboolean enabled)
+{
+	TrackerDBInterface *iface;
+	TrackerClass *class;
+	const gchar *service_name;
+	const gchar *field_name;
+
+	iface = tracker_db_manager_get_db_interface ();
+
+	class = tracker_property_get_domain (property);
+	field_name = tracker_property_get_name (property);
+	service_name = tracker_class_get_name (class);
+
+	if (tracker_property_get_multiple_values (property)) {
+		set_index_for_multi_value_property (iface, service_name, field_name, enabled);
+	} else {
+		set_index_for_single_value_property (iface, service_name, field_name, enabled);
+	}
+}
+
 void
 tracker_data_ontology_load_statement (const gchar *ontology_path,
                                       gint         subject_id,
@@ -197,13 +219,18 @@ tracker_data_ontology_load_statement (const gchar *ontology_path,
                                       gint        *max_id,
                                       gboolean    in_update,
                                       GHashTable *classes,
-                                      GHashTable *properties)
+                                      GHashTable *properties,
+                                      GPtrArray  *seen_classes,
+                                      GPtrArray  *seen_properties)
 {
 	if (g_strcmp0 (predicate, RDF_TYPE) == 0) {
 		if (g_strcmp0 (object, RDFS_CLASS) == 0) {
 			TrackerClass *class;
+			class = tracker_ontologies_get_class_by_uri (subject);
 
-			if (tracker_ontologies_get_class_by_uri (subject) != NULL) {
+			if (class != NULL) {
+				if (seen_classes)
+					g_ptr_array_add (seen_classes, g_object_ref (class));
 				if (!in_update)
 					g_critical ("%s: Duplicate definition of class %s", ontology_path, subject);
 				return;
@@ -220,6 +247,9 @@ tracker_data_ontology_load_statement (const gchar *ontology_path,
 			tracker_ontologies_add_class (class);
 			tracker_ontologies_add_id_uri_pair (subject_id, subject);
 
+			if (seen_classes)
+				g_ptr_array_add (seen_classes, g_object_ref (class));
+
 			if (classes) {
 				g_hash_table_insert (classes, GINT_TO_POINTER (subject_id), class);
 			} else {
@@ -229,7 +259,10 @@ tracker_data_ontology_load_statement (const gchar *ontology_path,
 		} else if (g_strcmp0 (object, RDF_PROPERTY) == 0) {
 			TrackerProperty *property;
 
-			if (tracker_ontologies_get_property_by_uri (subject) != NULL) {
+			property = tracker_ontologies_get_property_by_uri (subject);
+			if (property != NULL) {
+				if (seen_properties)
+					g_ptr_array_add (seen_properties, g_object_ref (property));
 				if (!in_update)
 					g_critical ("%s: Duplicate definition of property %s", ontology_path, subject);
 				return;
@@ -246,6 +279,9 @@ tracker_data_ontology_load_statement (const gchar *ontology_path,
 			tracker_ontologies_add_property (property);
 			tracker_ontologies_add_id_uri_pair (subject_id, subject);
 
+			if (seen_properties)
+				g_ptr_array_add (seen_properties, g_object_ref (property));
+
 			if (properties) {
 				g_hash_table_insert (properties, GINT_TO_POINTER (subject_id), property);
 			} else {
@@ -326,6 +362,8 @@ tracker_data_ontology_load_statement (const gchar *ontology_path,
 			update_property_value ("tracker:notify", subject, predicate, object);
 		}
 
+		tracker_class_set_notify (class, (strcmp (object, "true") == 0));
+
 	} else if (g_strcmp0 (predicate, TRACKER_PREFIX "writeback") == 0) {
 		TrackerProperty *property;
 
@@ -436,24 +474,8 @@ tracker_data_ontology_load_statement (const gchar *ontology_path,
 		enabled = (strcmp (object, "true") == 0);
 
 		if (tracker_property_get_is_new (property) != in_update) {
-
 			if (update_property_value ("tracker:indexed", subject, predicate, object)) {
-				TrackerDBInterface *iface;
-				TrackerClass *class;
-				const gchar *service_name;
-				const gchar *field_name;
-
-				iface = tracker_db_manager_get_db_interface ();
-
-				class = tracker_property_get_domain (property);
-				field_name = tracker_property_get_name (property);
-				service_name = tracker_class_get_name (class);
-
-				if (tracker_property_get_multiple_values (property)) {
-					set_index_for_multi_value_property (iface, service_name, field_name, enabled);
-				} else {
-					set_index_for_single_value_property (iface, service_name, field_name, enabled);
-				}
+				fix_indexed (property, enabled);
 			}
 		}
 
@@ -555,6 +577,139 @@ tracker_data_ontology_load_statement (const gchar *ontology_path,
 	}
 }
 
+void
+tracker_data_ontology_post_check (GPtrArray *seen_classes,
+                                  GPtrArray *seen_properties)
+{
+	gint i;
+
+	for (i = 0; i < seen_classes->len; i++) {
+		TrackerClass *class = g_ptr_array_index (seen_classes, i);
+		GError *error = NULL;
+		TrackerDBResultSet *result_set;
+		const gchar *subject;
+		gchar *query;
+
+		subject = tracker_class_get_uri (class);
+		query = g_strdup_printf ("SELECT ?predicate ?object WHERE { <%s> ?predicate ?object }",
+		                         subject);
+
+		result_set = tracker_data_query_sparql (query, &error);
+		g_free (query);
+
+		if (!error && result_set) {
+			gboolean saw_notify = FALSE, is_notify;
+
+			do {
+				gchar *predicate, *old_object;
+				TrackerProperty *property;
+
+				tracker_db_result_set_get (result_set, 0, &predicate, -1);
+				tracker_db_result_set_get (result_set, 1, &old_object, -1);
+
+				property = tracker_ontologies_get_property_by_uri (predicate);
+
+				if (property != NULL) {
+					if (g_strcmp0 (predicate, TRACKER_PREFIX "notify") == 0) {
+						saw_notify = TRUE;
+						is_notify = (strcmp (old_object, "true") == 0);
+					}
+				}
+
+				g_free (old_object);
+				g_free (predicate);
+
+			} while (tracker_db_result_set_iter_next (result_set) && !saw_notify);
+
+			if (!saw_notify && tracker_class_get_notify (class)) {
+				update_property_value ("tracker:notify", 
+				                       subject,
+				                       TRACKER_PREFIX "notify", 
+				                       is_notify ? "true" : "false");
+			}
+
+		} else {
+			if (error) {
+				g_critical ("Ontology change: %s", error->message);
+				g_clear_error (&error);
+			}
+		}
+
+		if (result_set)
+			g_object_unref (result_set);
+	}
+
+	for (i = 0; i < seen_properties->len; i++) {
+		TrackerProperty *property = g_ptr_array_index (seen_properties, i);
+		GError *error = NULL;
+		TrackerDBResultSet *result_set;
+		const gchar *subject;
+		gboolean saw_writeback = FALSE, saw_indexed = FALSE;
+		gboolean is_writeback, is_indexed;
+		gchar *query;
+
+		subject = tracker_property_get_uri (property);
+		query = g_strdup_printf ("SELECT ?predicate ?object WHERE { <%s> ?predicate ?object }",
+		                         subject);
+		result_set = tracker_data_query_sparql (query, &error);
+		g_free (query);
+
+		if (!error && result_set) {
+			do {
+				gchar *predicate, *old_object;
+
+				tracker_db_result_set_get (result_set, 0, &predicate, -1);
+				tracker_db_result_set_get (result_set, 1, &old_object, -1);
+
+				if (!saw_writeback && g_strcmp0 (predicate, TRACKER_PREFIX "writeback") == 0) {
+					saw_writeback = TRUE;
+					is_writeback = (strcmp (old_object, "true") == 0);
+				}
+
+				if (!saw_indexed && g_strcmp0 (predicate, TRACKER_PREFIX "indexed") == 0) {
+					saw_indexed = TRUE;
+					is_indexed = (strcmp (old_object, "true") == 0);
+				}
+
+				g_free (predicate);
+				g_free (old_object);
+			} while (tracker_db_result_set_iter_next (result_set));
+
+			if (!saw_writeback && tracker_property_get_writeback (property)) {
+				update_property_value ("tracker:writeback", 
+				                       subject,
+				                       TRACKER_PREFIX "writeback", 
+				                       is_writeback ? "true" : "false");
+			}
+
+			if (!saw_indexed && tracker_property_get_indexed (property)) {
+				if (update_property_value ("tracker:indexed", 
+				                           subject, 
+				                           TRACKER_PREFIX "indexed", 
+				                           is_indexed ? "true" : "false")) {
+					fix_indexed (property, is_indexed);
+				}
+			}
+
+		} else {
+			if (error) {
+				g_critical ("Ontology change: %s", error->message);
+				g_clear_error (&error);
+			}
+		}
+
+		if (result_set)
+			g_object_unref (result_set);
+	}
+}
+
+void
+tracker_data_ontology_free_seen (GPtrArray *seen)
+{
+	g_ptr_array_foreach (seen, (GFunc) g_object_unref, NULL);
+	g_ptr_array_free (seen, TRUE);
+}
+
 static void
 load_ontology_file_from_path (const gchar        *ontology_path,
                               gint               *max_id,
@@ -562,6 +717,8 @@ load_ontology_file_from_path (const gchar        *ontology_path,
 {
 	TrackerTurtleReader *reader;
 	GError              *error = NULL;
+	GPtrArray           *seen_classes = NULL;
+	GPtrArray           *seen_properties = NULL;
 
 	reader = tracker_turtle_reader_new (ontology_path, &error);
 	if (error) {
@@ -570,6 +727,11 @@ load_ontology_file_from_path (const gchar        *ontology_path,
 		return;
 	}
 
+	if (in_update) {
+		seen_classes = g_ptr_array_new ();
+		seen_properties = g_ptr_array_new ();
+	}
+
 	while (error == NULL && tracker_turtle_reader_next (reader, &error)) {
 		const gchar *subject, *predicate, *object;
 
@@ -578,11 +740,18 @@ load_ontology_file_from_path (const gchar        *ontology_path,
 		object = tracker_turtle_reader_get_object (reader);
 
 		tracker_data_ontology_load_statement (ontology_path, 0, subject, predicate, object,
-		                                      max_id, in_update, NULL, NULL);
+		                                      max_id, in_update, NULL, NULL,
+		                                      seen_classes, seen_properties);
 	}
 
 	g_object_unref (reader);
 
+	if (in_update) {
+		tracker_data_ontology_post_check (seen_classes, seen_properties);
+		tracker_data_ontology_free_seen (seen_classes);
+		tracker_data_ontology_free_seen (seen_properties);
+	}
+
 	if (error) {
 		g_critical ("Turtle parse error: %s", error->message);
 		g_error_free (error);
@@ -676,7 +845,6 @@ load_ontology_from_journal (GHashTable **classes_out,
 
 	id_uri_map = g_hash_table_new (g_direct_hash, g_direct_equal);
 
-
 	while (tracker_db_journal_reader_next (NULL)) {
 		TrackerDBJournalEntryType type;
 
@@ -707,7 +875,8 @@ load_ontology_from_journal (GHashTable **classes_out,
 			predicate = g_hash_table_lookup (id_uri_map, GINT_TO_POINTER (predicate_id));
 
 			tracker_data_ontology_load_statement ("journal", subject_id, subject, predicate, 
-			                                      object, NULL, FALSE, classes, properties);
+			                                      object, NULL, FALSE, classes, properties,
+			                                      NULL, NULL);
 		}
 	}
 
diff --git a/src/libtracker-data/tracker-data-manager.h b/src/libtracker-data/tracker-data-manager.h
index cb41391..38a5f2c 100644
--- a/src/libtracker-data/tracker-data-manager.h
+++ b/src/libtracker-data/tracker-data-manager.h
@@ -58,7 +58,9 @@ void     tracker_data_ontology_load_statement     (const gchar           *ontolo
                                                    gint                  *max_id,
                                                    gboolean               in_update,
                                                    GHashTable            *classes,
-                                                   GHashTable            *properties);
+                                                   GHashTable            *properties,
+                                                   GPtrArray             *seen_classes,
+                                                   GPtrArray             *seen_properties);
 void     tracker_data_ontology_import_into_db     (gboolean               is_new);
 void     tracker_data_ontology_process_statement  (const gchar           *graph,
                                                    const gchar           *subject,
@@ -68,6 +70,9 @@ void     tracker_data_ontology_process_statement  (const gchar           *graph,
                                                    gboolean               in_update,
                                                    gboolean               ignore_nao_last_modified);
 void    tracker_data_ontology_import_finished     (void);
+void    tracker_data_ontology_post_check          (GPtrArray             *seen_classes,
+                                                   GPtrArray             *seen_properties);
+void    tracker_data_ontology_free_seen           (GPtrArray             *seen);
 
 G_END_DECLS
 
diff --git a/src/libtracker-data/tracker-data-update.c b/src/libtracker-data/tracker-data-update.c
index 37bb4b4..1190e05 100644
--- a/src/libtracker-data/tracker-data-update.c
+++ b/src/libtracker-data/tracker-data-update.c
@@ -2376,11 +2376,13 @@ queue_statement (GList *queue,
 }
 
 static void
-ontology_transaction_end (GList *ontology_queue)
+ontology_transaction_end (GList *ontology_queue, GPtrArray *seen_classes, GPtrArray *seen_properties)
 {
 	GList *l;
 	const gchar *ontology_uri = NULL;
 
+	tracker_data_ontology_post_check (seen_classes, seen_properties);
+
 	/* Perform ALTER-TABLE and CREATE-TABLE calls for all that are is_new */
 	tracker_data_ontology_import_into_db (TRUE);
 
@@ -2444,7 +2446,9 @@ ontology_statement_insert (GList       *ontology_queue,
                            GHashTable  *classes,
                            GHashTable  *properties,
                            GHashTable  *id_uri_map,
-                           gboolean     is_uri)
+                           gboolean     is_uri,
+                           GPtrArray   *seen_classes,
+                           GPtrArray   *seen_properties)
 {
 	const gchar *graph, *subject, *predicate;
 
@@ -2459,7 +2463,8 @@ ontology_statement_insert (GList       *ontology_queue,
 
 	/* load ontology from journal into memory, set all new's is_new to TRUE */
 	tracker_data_ontology_load_statement ("journal", subject_id, subject, predicate, 
-	                                      object, NULL, TRUE, classes, properties);
+	                                      object, NULL, TRUE, classes, properties,
+	                                      seen_classes, seen_properties);
 
 	/* Queue the statement for processing after ALTER in ontology_transaction_end */
 	ontology_queue = queue_statement (ontology_queue, graph, subject, predicate, object, is_uri);
@@ -2480,6 +2485,8 @@ tracker_data_replay_journal (GHashTable          *classes,
 	gint last_operation_type = 0;
 	gboolean in_ontology = FALSE;
 	GList *ontology_queue = NULL;
+	GPtrArray *seen_classes = NULL;
+	GPtrArray *seen_properties = NULL;
 
 	tracker_data_begin_db_transaction_for_replay (0);
 
@@ -2538,11 +2545,15 @@ tracker_data_replay_journal (GHashTable          *classes,
 			resource_time = tracker_db_journal_reader_get_time ();
 		} else if (type == TRACKER_DB_JOURNAL_END_TRANSACTION) {
 			if (in_ontology) {
-				ontology_transaction_end (ontology_queue);
+				ontology_transaction_end (ontology_queue, seen_classes, seen_properties);
 				g_list_foreach (ontology_queue, (GFunc) free_queued_statement, NULL);
 				g_list_free (ontology_queue);
 				ontology_queue = NULL;
 				in_ontology = FALSE;
+				tracker_data_ontology_free_seen (seen_classes);
+				seen_classes = NULL;
+				tracker_data_ontology_free_seen (seen_properties);
+				seen_properties = NULL;
 			} else {
 				GError *new_error = NULL;
 				tracker_data_update_buffer_might_flush (&new_error);
@@ -2558,6 +2569,12 @@ tracker_data_replay_journal (GHashTable          *classes,
 			tracker_db_journal_reader_get_statement (&graph_id, &subject_id, &predicate_id, &object);
 
 			if (in_ontology) {
+
+				if (!seen_classes)
+					seen_classes = g_ptr_array_new ();
+				if (!seen_properties)
+					seen_properties = g_ptr_array_new ();
+
 				ontology_queue = ontology_statement_insert (ontology_queue,
 				                                            graph_id,
 				                                            subject_id,
@@ -2566,7 +2583,9 @@ tracker_data_replay_journal (GHashTable          *classes,
 				                                            classes,
 				                                            properties,
 				                                            id_uri_map,
-				                                            FALSE);
+				                                            FALSE,
+				                                            seen_classes,
+				                                            seen_properties);
 				continue;
 			}
 
@@ -2605,6 +2624,12 @@ tracker_data_replay_journal (GHashTable          *classes,
 			if (in_ontology) {
 				const gchar *object_n;
 				object_n = g_hash_table_lookup (id_uri_map, GINT_TO_POINTER (object_id));
+
+				if (!seen_classes)
+					seen_classes = g_ptr_array_new ();
+				if (!seen_properties)
+					seen_properties = g_ptr_array_new ();
+
 				ontology_queue = ontology_statement_insert (ontology_queue,
 				                                            graph_id,
 				                                            subject_id,
@@ -2613,7 +2638,9 @@ tracker_data_replay_journal (GHashTable          *classes,
 				                                            classes,
 				                                            properties,
 				                                            id_uri_map,
-				                                            TRUE);
+				                                            TRUE,
+				                                            seen_classes,
+				                                            seen_properties);
 				continue;
 			}
 
diff --git a/src/libtracker-data/tracker-property.c b/src/libtracker-data/tracker-property.c
index 692ab74..cbe178e 100644
--- a/src/libtracker-data/tracker-property.c
+++ b/src/libtracker-data/tracker-property.c
@@ -60,6 +60,7 @@ struct _TrackerPropertyPriv {
 	gboolean       is_inverse_functional_property;
 	gboolean       is_new;
 	gboolean       need_recreate;
+	gboolean       writeback;
 
 	GArray        *super_properties;
 };
@@ -342,6 +343,18 @@ tracker_property_get_is_new (TrackerProperty *field)
 }
 
 gboolean
+tracker_property_get_writeback (TrackerProperty *field)
+{
+	TrackerPropertyPriv *priv;
+
+	g_return_val_if_fail (TRACKER_IS_PROPERTY (field), FALSE);
+
+	priv = GET_PRIV (field);
+
+	return priv->writeback;
+}
+
+gboolean
 tracker_property_get_need_recreate (TrackerProperty *field)
 {
 	TrackerPropertyPriv *priv;
@@ -564,6 +577,19 @@ tracker_property_set_is_new (TrackerProperty *field,
 }
 
 void
+tracker_property_set_writeback (TrackerProperty *field,
+                             gboolean         value)
+{
+	TrackerPropertyPriv *priv;
+
+	g_return_if_fail (TRACKER_IS_PROPERTY (field));
+
+	priv = GET_PRIV (field);
+
+	priv->writeback = value;
+}
+
+void
 tracker_property_set_need_recreate (TrackerProperty *field,
                                     gboolean         value)
 {
diff --git a/src/libtracker-data/tracker-property.h b/src/libtracker-data/tracker-property.h
index 5851566..7eb4baa 100644
--- a/src/libtracker-data/tracker-property.h
+++ b/src/libtracker-data/tracker-property.h
@@ -87,6 +87,7 @@ gboolean            tracker_property_get_embedded         (TrackerProperty
 gboolean            tracker_property_get_multiple_values  (TrackerProperty      *property);
 gboolean            tracker_property_get_transient        (TrackerProperty      *property);
 gboolean            tracker_property_get_is_new           (TrackerProperty      *property);
+gboolean            tracker_property_get_writeback        (TrackerProperty      *property);
 gboolean            tracker_property_get_need_recreate    (TrackerProperty      *property);
 gboolean            tracker_property_get_is_inverse_functional_property
 (TrackerProperty      *property);
@@ -115,6 +116,8 @@ void                tracker_property_set_transient        (TrackerProperty
                                                            gboolean              value);
 void                tracker_property_set_is_new           (TrackerProperty      *property,
                                                            gboolean              value);
+void                tracker_property_set_writeback        (TrackerProperty      *property,
+                                                           gboolean              value);
 void                tracker_property_set_need_recreate    (TrackerProperty      *property,
                                                            gboolean              value);
 void                tracker_property_set_is_inverse_functional_property



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