[tracker/tracker-0.6] Use single DB insert statements instead of insert and many updates



commit 169fcacef91396ebe77e50a82241d5742ce53d39
Author: Carlos Garnacho <carlos lanedo com>
Date:   Fri May 15 09:58:31 2009 +0100

    Use single DB insert statements instead of insert and many updates
    
    This seriously improves speed. My desktop, 7k items, 35s down to 28s.
    This patch from Carlos was based on an intitial patch by Philip Van Hoof.
---
 src/libtracker-data/tracker-data-update.c |  255 +++++++++++++++++++++++------
 src/libtracker-data/tracker-data-update.h |   32 ++++-
 src/libtracker-db/tracker-db-interface.h  |    2 +-
 src/tracker-indexer/tracker-indexer.c     |   64 ++++++-
 4 files changed, 293 insertions(+), 60 deletions(-)

diff --git a/src/libtracker-data/tracker-data-update.c b/src/libtracker-data/tracker-data-update.c
index e3f1fef..41c4b86 100644
--- a/src/libtracker-data/tracker-data-update.c
+++ b/src/libtracker-data/tracker-data-update.c
@@ -36,12 +36,17 @@
 #include "tracker-data-query.h"
 
 typedef struct {
+	TrackerDataUpdateMetadataContext *context;
 	TrackerService *service;
 	guint32 iid_value;
 	TrackerLanguage *language;
 	TrackerConfig *config;
 } ForeachInMetadataInfo;
 
+typedef struct {
+	GPtrArray *columns;
+	GPtrArray *values;
+} InsertData;
 
 guint32
 tracker_data_update_get_new_service_id (TrackerDBInterface *iface)
@@ -90,12 +95,13 @@ tracker_data_update_get_new_service_id (TrackerDBInterface *iface)
 }
 
 gboolean
-tracker_data_update_create_service (TrackerService *service,
-				    guint32	    service_id,
-				    const gchar    *udi,
-				    const gchar	   *dirname,
-				    const gchar	   *basename,
-				    GHashTable     *metadata)
+tracker_data_update_create_service (TrackerDataUpdateMetadataContext *context,
+				    TrackerService                   *service,
+				    guint32	                      service_id,
+				    const gchar                      *udi,
+				    const gchar	                     *dirname,
+				    const gchar	                     *basename,
+				    GHashTable                       *metadata)
 {
 	TrackerDBInterface *iface;
 	TrackerDBResultSet *result_set;
@@ -134,19 +140,22 @@ tracker_data_update_create_service (TrackerService *service,
 	is_dir = g_file_test (path, G_FILE_TEST_IS_DIR);
 	is_symlink = g_file_test (path, G_FILE_TEST_IS_SYMLINK);
 
-	tracker_db_interface_execute_procedure (iface, NULL, "CreateService",
-						id_str,
-						dirname,
-						basename,
-						service_type_id_str,
-						is_dir ? "Folder" : g_hash_table_lookup (metadata, "File:Mime"),
-						g_hash_table_lookup (metadata, "File:Size"),
-						is_dir ? "1" : "0",
-						is_symlink ? "1" : "0",
-						"0", /* Offset */
-						g_hash_table_lookup (metadata, "File:Modified"),
-						volume_id_str, /* Aux ID */
-						NULL);
+	/* Add data to the context */
+	tracker_data_update_metadata_context_add (context, "ID", id_str);
+	tracker_data_update_metadata_context_add (context, "Path", dirname);
+	tracker_data_update_metadata_context_add (context, "Name", basename);
+	tracker_data_update_metadata_context_add (context, "ServiceTypeID", service_type_id_str);
+	tracker_data_update_metadata_context_add (context, "Mime",
+						  is_dir ? "Folder" : g_hash_table_lookup (metadata, "File:Mime"));
+	tracker_data_update_metadata_context_add (context, "Size",
+						  g_hash_table_lookup (metadata, "File:Size"));
+	tracker_data_update_metadata_context_add (context, "IsDirectory",
+						  is_dir ? "1" : "0");
+	tracker_data_update_metadata_context_add (context, "IsLink",
+						  is_symlink ? "1" : "0");
+	tracker_data_update_metadata_context_add (context, "IndexTime",
+						  g_hash_table_lookup (metadata, "File:Modified"));
+	tracker_data_update_metadata_context_add (context, "AuxilaryID", volume_id_str);
 
 	g_free (id_str);
 	g_free (service_type_id_str);
@@ -323,19 +332,21 @@ tracker_data_update_delete_all_metadata (TrackerService *service,
 }
 
 void
-tracker_data_update_set_metadata (TrackerService *service,
-				  guint32	  service_id,
-				  TrackerField	 *field,
-				  const gchar	 *value,
-				  const gchar	 *parsed_value)
+tracker_data_update_set_metadata (TrackerDataUpdateMetadataContext *context,
+				  TrackerService                   *service,
+				  guint32	                    service_id,
+				  TrackerField	                   *field,
+				  const gchar	                   *value,
+				  const gchar	                   *parsed_value)
 {
 	TrackerDBInterface *iface;
 	gint metadata_key;
 	gint collate_key;
 	gchar *id_str;
 
-	if(!strlen(value))
+	if (tracker_is_empty_string (value)) {
 		return;
+	}
 
 	id_str = tracker_guint32_to_string (service_id);
 
@@ -390,39 +401,31 @@ tracker_data_update_set_metadata (TrackerService *service,
 	metadata_key = tracker_ontology_service_get_key_metadata (tracker_service_get_name (service),
 								  tracker_field_get_name (field));
 	if (metadata_key > 0) {
-		gchar *val;
+		gchar *column;
 
-		val = tracker_escape_string (value);
-
-		tracker_db_interface_execute_query (iface, NULL,
-						    "update Services set KeyMetadata%d = '%s' where id = %d",
-						    metadata_key,
-						    val,
-						    service_id);
-		g_free (val);
+		column = g_strdup_printf ("KeyMetadata%d", metadata_key);
+		tracker_data_update_metadata_context_add (context, column, value);
+		g_free (column);
 	} else if (tracker_field_get_data_type (field) == TRACKER_FIELD_TYPE_DATE &&
 		   (strcmp (tracker_field_get_name (field), "File:Modified") == 0)) {
 		/* Handle mtime */
-		tracker_db_interface_execute_query (iface, NULL,
-						    "update Services set IndexTime = '%s' where ID = %d",
-						    value,
-						    service_id);
+		tracker_data_update_metadata_context_add (context, "IndexTime", value);
 	}
 
 	collate_key = tracker_ontology_service_get_key_collate (tracker_service_get_name (service),
 								tracker_field_get_name (field));
 	if (collate_key > 0) {
-		gchar *val;
-		
+		gchar *val, *collate_val, *column;
+
 		val = tracker_escape_string (value);
-		
-		tracker_db_interface_execute_query (iface, NULL,
-			       "update Services set KeyMetadataCollation%d = CollateKey('%s') where id = %d",
-			       collate_key,
-			       val,
-			       service_id);
+		collate_val = g_strdup_printf ("CollateKey('%s')", val);
+		column = g_strdup_printf ("KeyMetadataCollation%d", collate_key);
+
+		tracker_data_update_metadata_context_add (context, column, collate_val);
 
 		g_free (val);
+		g_free (collate_val);
+		g_free (column);
 	}
 
 	g_free (id_str);
@@ -654,7 +657,12 @@ set_metadata (TrackerField *field,
 					   score);
 	}
 
-	tracker_data_update_set_metadata (info->service, info->iid_value, field, value, parsed_value);
+	tracker_data_update_set_metadata (info->context, 
+					  info->service, 
+					  info->iid_value, 
+					  field, 
+					  value, 
+					  parsed_value);
 
 	g_free (parsed_value);
 	g_strfreev (arr);
@@ -697,6 +705,7 @@ tracker_data_update_replace_service (const gchar *udi,
 				     const gchar *rdf_type,
 				     GHashTable  *metadata)
 {
+	TrackerDataUpdateMetadataContext *context;
 	TrackerDBInterface  *iface;
 	TrackerDBResultSet  *result_set;
 	const gchar         *modified;
@@ -753,11 +762,17 @@ tracker_data_update_replace_service (const gchar *udi,
 			set_metadata = TRUE;
 		}
 
+		context = tracker_data_update_metadata_context_new (TRACKER_CONTEXT_TYPE_UPDATE,
+								    service, id);
+
 		g_object_unref (result_set);
 	} else {
 		id = tracker_data_update_get_new_service_id (iface);
 
-		if (tracker_data_update_create_service (service, id,
+		context = tracker_data_update_metadata_context_new (TRACKER_CONTEXT_TYPE_INSERT,
+								    service, id);
+
+		if (tracker_data_update_create_service (context, service, id,
 							udi,
 							dirname, basename,
 							metadata)) {
@@ -770,6 +785,7 @@ tracker_data_update_replace_service (const gchar *udi,
 
 		info = g_slice_new (ForeachInMetadataInfo);
 
+		info->context = context;
 		info->service = service;
 		info->iid_value = id;
 
@@ -783,6 +799,9 @@ tracker_data_update_replace_service (const gchar *udi,
 		g_slice_free (ForeachInMetadataInfo, info);
 	}
 
+	tracker_data_update_metadata_context_close (context);
+	tracker_data_update_metadata_context_free (context);
+
 	g_free (dirname);
 	g_free (basename);
 	g_free (escaped_path);
@@ -872,3 +891,143 @@ tracker_data_update_disable_all_volumes (void)
 						NULL);
 }
 
+/* Metadata context */
+TrackerDataUpdateMetadataContext *
+tracker_data_update_metadata_context_new (TrackerDataUpdateMetadataContextType  type,
+					  TrackerService                       *service,
+					  guint                                 id)
+{
+	TrackerDataUpdateMetadataContext *context;
+
+	context = g_slice_new (TrackerDataUpdateMetadataContext);
+	context->type = type;
+	context->service = g_object_ref (service);
+	context->id = id;
+
+	context->data = g_hash_table_new_full (g_str_hash,
+					       g_str_equal,
+					       (GDestroyNotify) g_free,
+					       (GDestroyNotify) g_free);
+	return context;
+}
+
+void
+tracker_data_update_metadata_context_add (TrackerDataUpdateMetadataContext *context,
+					  const gchar                      *column,
+					  const gchar                      *value)
+{
+	g_hash_table_replace (context->data,
+			      g_strdup (column),
+			      tracker_escape_string (value));
+}
+
+static void
+get_insert_data_foreach (gpointer key,
+			 gpointer value,
+			 gpointer user_data)
+{
+	InsertData *insert_data = (InsertData *) user_data;
+
+	g_ptr_array_add (insert_data->columns, key);
+	g_ptr_array_add (insert_data->values, value);
+}
+
+void
+tracker_data_update_metadata_context_close (TrackerDataUpdateMetadataContext *context)
+{
+	TrackerDBInterface *iface;
+	GError *error = NULL;
+	guint size;
+	gchar *sql;
+
+	size = g_hash_table_size (context->data);
+
+	if (size == 0) {
+		/* No changes */
+		return;
+	}
+
+	if (context->type == TRACKER_CONTEXT_TYPE_INSERT) {
+		gchar *id_str, *joined_columns, *joined_values;
+		InsertData insert_data;
+
+		/* Ensure we have an ID */
+		id_str = tracker_guint32_to_string (context->id);
+		tracker_data_update_metadata_context_add (context, "ID", id_str);
+		g_free (id_str);
+
+		/* Compose insert SQL query */
+		size = g_hash_table_size (context->data);
+		insert_data.columns = g_ptr_array_sized_new (size + 1);
+		insert_data.values = g_ptr_array_sized_new (size + 1);
+
+		g_hash_table_foreach (context->data,
+				      get_insert_data_foreach,
+				      &insert_data);
+
+		g_ptr_array_add (insert_data.columns, NULL);
+		g_ptr_array_add (insert_data.values, NULL);
+
+		joined_columns = g_strjoinv (",", (gchar **) insert_data.columns->pdata);
+		joined_values = g_strjoinv (",", (gchar **) insert_data.values->pdata);
+
+		sql = g_strdup_printf ("INSERT INTO Services (%s) VALUES (%s);", 
+				       joined_columns, 
+				       joined_values);
+
+		g_free (joined_columns);
+		g_free (joined_values);
+
+		g_ptr_array_free (insert_data.columns, TRUE);
+		g_ptr_array_free (insert_data.values, TRUE);
+	} else if (context->type == TRACKER_CONTEXT_TYPE_UPDATE) {
+		GString        *update_query;
+		GHashTableIter  iter;
+		gpointer        key, value;
+		gboolean        first = TRUE;
+
+		/* Compose update SQL query */
+		update_query = g_string_new ("UPDATE Services SET ");
+
+		g_hash_table_iter_init (&iter, context->data);
+
+		while (g_hash_table_iter_next (&iter, &key, &value)) {
+			const gchar *column = key;
+			const gchar *val    = value;
+
+			if (!first) {
+				g_string_append (update_query, ", ");
+			}
+
+			g_string_append_printf (update_query,
+						"%s = '%s'",
+						column,
+						val);
+			first = FALSE;
+		}
+
+		g_string_append_printf (update_query, " WHERE ID = %d", context->id);
+
+		sql = g_string_free (update_query, FALSE);
+	} else {
+		g_assert_not_reached ();
+	}
+
+	iface = tracker_db_manager_get_db_interface_by_type (tracker_service_get_name (context->service),
+							     TRACKER_DB_CONTENT_TYPE_METADATA);
+
+	tracker_db_interface_execute_query (iface, &error, sql, NULL);
+
+	if (error) {
+		g_warning ("%s", error->message);
+		g_error_free (error);
+	}
+}
+
+void
+tracker_data_update_metadata_context_free (TrackerDataUpdateMetadataContext *context)
+{
+	g_object_unref (context->service);
+	g_hash_table_unref (context->data);
+	g_slice_free (TrackerDataUpdateMetadataContext, context);
+}
diff --git a/src/libtracker-data/tracker-data-update.h b/src/libtracker-data/tracker-data-update.h
index 90cc12a..09783e3 100644
--- a/src/libtracker-data/tracker-data-update.h
+++ b/src/libtracker-data/tracker-data-update.h
@@ -32,10 +32,26 @@
 
 G_BEGIN_DECLS
 
+typedef struct TrackerDataUpdateMetadataContext TrackerDataUpdateMetadataContext;
+typedef enum TrackerDataUpdateMetadataContextType TrackerDataUpdateMetadataContextType;
+
+enum TrackerDataUpdateMetadataContextType {
+	TRACKER_CONTEXT_TYPE_INSERT,
+	TRACKER_CONTEXT_TYPE_UPDATE
+};
+
+struct TrackerDataUpdateMetadataContext {
+	TrackerDataUpdateMetadataContextType type;
+	TrackerService *service;
+	guint id;
+	GHashTable *data;
+};
+
 guint32  tracker_data_update_get_new_service_id         (TrackerDBInterface  *iface);
 
 /* Services  */
-gboolean tracker_data_update_create_service             (TrackerService      *service,
+gboolean tracker_data_update_create_service             (TrackerDataUpdateMetadataContext *context,
+							 TrackerService      *service,
 							 guint32              service_id,
 							 const gchar         *udi,
 							 const gchar         *dirname,
@@ -62,7 +78,8 @@ void     tracker_data_update_delete_service_all         (const gchar *rdf_type);
 
 
 /* Metadata */
-void     tracker_data_update_set_metadata               (TrackerService      *service,
+void     tracker_data_update_set_metadata               (TrackerDataUpdateMetadataContext *context,
+							 TrackerService      *service,
 							 guint32              service_id,
 							 TrackerField        *field,
 							 const gchar         *value,
@@ -89,6 +106,17 @@ void tracker_data_update_disable_volume                 (const gchar         *ud
 void tracker_data_update_disable_all_volumes            (void);
 void tracker_data_update_reset_volume                   (guint32              volume_id);
 
+/* Metadata context */
+TrackerDataUpdateMetadataContext *
+     tracker_data_update_metadata_context_new           (TrackerDataUpdateMetadataContextType  type,
+							 TrackerService                       *service,
+							 guint                                 id);
+void tracker_data_update_metadata_context_add           (TrackerDataUpdateMetadataContext *context,
+							 const gchar                      *column,
+							 const gchar                      *value);
+void tracker_data_update_metadata_context_close         (TrackerDataUpdateMetadataContext *context);
+void tracker_data_update_metadata_context_free          (TrackerDataUpdateMetadataContext *context);
+
 G_END_DECLS
 
 #endif /* __TRACKER_DATA_UPDATE_H__ */
diff --git a/src/libtracker-db/tracker-db-interface.h b/src/libtracker-db/tracker-db-interface.h
index 71952fc..ca16469 100644
--- a/src/libtracker-db/tracker-db-interface.h
+++ b/src/libtracker-db/tracker-db-interface.h
@@ -70,7 +70,7 @@ struct TrackerDBInterfaceIface {
 
 };
 
-#undef DISABLE_DEBUG
+#define DISABLE_DEBUG
 
 #ifdef G_HAVE_ISO_VARARGS
 #  ifdef DISABLE_DEBUG
diff --git a/src/tracker-indexer/tracker-indexer.c b/src/tracker-indexer/tracker-indexer.c
index 0aec6bc..9d4d7ea 100644
--- a/src/tracker-indexer/tracker-indexer.c
+++ b/src/tracker-indexer/tracker-indexer.c
@@ -167,6 +167,7 @@ struct PathInfo {
 };
 
 struct MetadataForeachData {
+	TrackerDataUpdateMetadataContext *context;
 	TrackerLanguage *language;
 	TrackerConfig *config;
 	guint32 service_id;
@@ -1199,9 +1200,17 @@ index_metadata_item (TrackerField	 *field,
 	}
 
 	if (data->add) {
-		tracker_data_update_set_metadata (data->service, data->id, field, (gchar *) value, parsed_value);
+		tracker_data_update_set_metadata (data->context, 
+						  data->service, 
+						  data->id, 
+						  field, 
+						  value, 
+						  parsed_value);
 	} else {
-		tracker_data_update_delete_metadata (data->service, data->id, field, (gchar *) value);
+		tracker_data_update_delete_metadata (data->service, 
+						     data->id, 
+						     field, 
+						     value);
 	}
 
 	g_free (parsed_value);
@@ -1243,6 +1252,7 @@ index_metadata_foreach (TrackerField *field,
 
 static void
 index_metadata (TrackerIndexer	      *indexer,
+		TrackerDataUpdateMetadataContext *context,
 		guint32		       id,
 		TrackerService	      *service,
 		TrackerModuleMetadata *metadata)
@@ -1252,6 +1262,7 @@ index_metadata (TrackerIndexer	      *indexer,
 
 	service_id = tracker_service_get_id (service);
 
+	data.context = context;
 	data.language = indexer->private->language;
 	data.config = indexer->private->config;
 	data.service_id = service_id;
@@ -1276,6 +1287,7 @@ unindex_metadata (TrackerIndexer      *indexer,
 
 	service_id = tracker_service_get_id (service);
 
+	data.context = NULL;
 	data.language = indexer->private->language;
 	data.config = indexer->private->config;
 	data.service_id = service_id;
@@ -1667,6 +1679,7 @@ item_add_or_update (TrackerIndexer        *indexer,
 	}
 
 	if (exists) {
+		TrackerDataUpdateMetadataContext *context;
 		TrackerDataMetadata *old_metadata_emb, *old_metadata_non_emb;
 		gchar *old_text;
 
@@ -1701,7 +1714,13 @@ item_add_or_update (TrackerIndexer        *indexer,
 							remove_existing_non_emb_metadata,
 							old_metadata_non_emb);
 
-		index_metadata (indexer, id, service, metadata);
+		context = tracker_data_update_metadata_context_new (TRACKER_CONTEXT_TYPE_UPDATE,
+								    service, id);
+
+		index_metadata (indexer, context, id, service, metadata);
+
+		tracker_data_update_metadata_context_close (context);
+		tracker_data_update_metadata_context_free (context);
 
 		/* Take the old text -> the new one, calculate
 		 * difference and add the words.
@@ -1727,6 +1746,7 @@ item_add_or_update (TrackerIndexer        *indexer,
 		tracker_data_metadata_free (old_metadata_emb);
 		tracker_data_metadata_free (old_metadata_non_emb);
 	} else {
+		TrackerDataUpdateMetadataContext *context;
 		GHashTable *data;
 		const gchar *udi;
 
@@ -1739,14 +1759,21 @@ item_add_or_update (TrackerIndexer        *indexer,
 		data = tracker_module_metadata_get_hash_table (metadata);
 		udi = tracker_hal_udi_get_for_path (indexer->private->hal, dirname);
 
-		tracker_data_update_create_service (service,
+		context = tracker_data_update_metadata_context_new (TRACKER_CONTEXT_TYPE_INSERT,
+								    service, id);
+
+		tracker_data_update_create_service (context,
+						    service,
 						    id,
 						    udi,
 						    dirname,
 						    basename,
 						    data);
 
-		index_metadata (indexer, id, service, metadata);
+		index_metadata (indexer, context, id, service, metadata);
+
+		tracker_data_update_metadata_context_close (context);
+		tracker_data_update_metadata_context_free (context);
 
 		if (text) {
 			/* Save in the index */
@@ -1893,6 +1920,7 @@ update_moved_item_index (TrackerIndexer      *indexer,
 			 GFile               *file,
 			 GFile               *source_file)
 {
+	TrackerDataUpdateMetadataContext *context;
 	TrackerModuleMetadata *new_metadata;
 	gchar *path, *new_path, *new_name;
 	const gchar *ext;
@@ -1922,7 +1950,13 @@ update_moved_item_index (TrackerIndexer      *indexer,
 		tracker_module_metadata_add_string (new_metadata, METADATA_FILE_EXT, ext);
 	}
 
-	index_metadata (indexer, service_id, service, new_metadata);
+	context = tracker_data_update_metadata_context_new (TRACKER_CONTEXT_TYPE_UPDATE,
+							    service, service_id);
+
+	index_metadata (indexer, context, service_id, service, new_metadata);
+
+	tracker_data_update_metadata_context_close (context);
+	tracker_data_update_metadata_context_free (context);
 
 	g_object_unref (new_metadata);
 	g_free (new_path);
@@ -2283,6 +2317,7 @@ handle_metadata_add (TrackerIndexer *indexer,
 		     GStrv	     values,
 		     GError	   **error)
 {
+	TrackerDataUpdateMetadataContext *context;
 	TrackerService *service;
 	TrackerField   *field;
 	guint           service_id, i, j;
@@ -2377,6 +2412,9 @@ handle_metadata_add (TrackerIndexer *indexer,
 
 	set_values = g_new0 (gchar *, g_strv_length (values) + 1);
 
+	context = tracker_data_update_metadata_context_new (TRACKER_CONTEXT_TYPE_UPDATE,
+							    service, service_id);
+
 	for (i = 0, j = 0; values[i] != NULL; i++) {
 		g_debug ("Setting metadata: service_type '%s' id '%d' field '%s' value '%s'",
 			 tracker_service_get_name (service),
@@ -2384,15 +2422,23 @@ handle_metadata_add (TrackerIndexer *indexer,
 			 tracker_field_get_name (field),
 			 values[i]);
 
-		if (tracker_field_get_multiple_values (field) 
-		    && (tracker_string_in_string_list (values[i], old_contents) > -1) ) {
+		if (tracker_field_get_multiple_values (field) &&
+		    tracker_string_in_string_list (values[i], old_contents) > -1) {
 			continue;
 		}
 
-		tracker_data_update_set_metadata (service, service_id, field, values[i], NULL);
+		tracker_data_update_set_metadata (context, 
+						  service, 
+						  service_id, 
+						  field, 
+						  values[i], 
+						  NULL);
 		set_values [++j] = values[i];
 	}
 
+	tracker_data_update_metadata_context_close (context);
+	tracker_data_update_metadata_context_free (context);
+
 	joined = g_strjoinv (" ", set_values);
 	if (tracker_field_get_filtered (field)) {
 		index_text_no_parsing (indexer,



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