[tracker/tracker-0.6] Fixes: NB#109891, If deleting last music track or last video...



commit cf3fdf2471002b72e8f4f0ba50e0acea554689b6
Author: Martyn Russell <martyn imendio com>
Date:   Thu Apr 16 19:46:56 2009 +0100

    Fixes: NB#109891, If deleting last music track or last video...
    
    The cache expires now after 3 minutes instead of 1 minute which was
    too short. We now use GetServices every time to fix the case where 0
    items for a service type doesn't show up in the
    SERVICE_STATISTICS_UPDATED signal.
---
 src/trackerd/tracker-daemon.c |  345 +++++++++++++++++++----------------------
 1 files changed, 158 insertions(+), 187 deletions(-)

diff --git a/src/trackerd/tracker-daemon.c b/src/trackerd/tracker-daemon.c
index 2670a87..12fce8a 100644
--- a/src/trackerd/tracker-daemon.c
+++ b/src/trackerd/tracker-daemon.c
@@ -45,8 +45,8 @@
 
 #define TRACKER_TYPE_G_STRV_ARRAY  (dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRV))
 
-/* Seconds */
-#define STATS_CACHE_LIFETIME 60
+/* In seconds (3 minutes for now) */
+#define STATS_CACHE_LIFETIME 180
 
 typedef struct {
 	TrackerConfig	 *config;
@@ -66,9 +66,10 @@ enum {
 	LAST_SIGNAL
 };
 
-static void     tracker_daemon_finalize (GObject       *object);
-static gboolean stats_cache_timeout     (gpointer       user_data);
-static void     stats_cache_update      (TrackerDaemon *object);
+static void        tracker_daemon_finalize (GObject       *object);
+static gboolean    stats_cache_timeout     (gpointer       user_data);
+static GHashTable *stats_cache_get_latest  (void);
+static void        stats_cache_update      (TrackerDaemon *object);
 
 static guint signals[LAST_SIGNAL] = {0};
 
@@ -204,11 +205,7 @@ tracker_daemon_init (TrackerDaemon *object)
 {
 	TrackerDaemonPrivate *priv;
 	TrackerDBInterface   *iface;
-	TrackerDBResultSet   *result_set;
 	DBusGProxy           *proxy;
-	GHashTable           *values;
-	GHashTableIter        iter;
-	gpointer              key, value;
 
 	priv = TRACKER_DAEMON_GET_PRIVATE (object);
 
@@ -230,33 +227,9 @@ tracker_daemon_init (TrackerDaemon *object)
 
 	iface = tracker_db_manager_get_db_interface (TRACKER_DB_COMMON);
 
-	/* Prepare cache */
-	priv->stats_cache = g_hash_table_new_full (g_str_hash,
-						   g_str_equal,
-						   g_free, 
-						   NULL);
-
-	result_set = tracker_data_manager_exec_proc (iface, "GetServices", 0);
-	values = tracker_dbus_query_result_to_hash_table (result_set);
-
-	if (result_set) {
-		g_object_unref (result_set);
-	}
-
-	g_hash_table_iter_init (&iter, values);
-
-	while (g_hash_table_iter_next (&iter, &key, &value)) {
-		g_hash_table_replace (priv->stats_cache, 
-				      g_strdup (key), 
-				      GINT_TO_POINTER (0));
-	}
-
-	g_hash_table_destroy (values);
-
-	/* First time update */
-	stats_cache_update (object);
+	/* Do first time stats lookup */
+	priv->stats_cache = stats_cache_get_latest ();
 
-	/* Future updates */
 	priv->stats_cache_timeout_id = 
 		g_timeout_add_seconds (STATS_CACHE_LIFETIME,
 				       stats_cache_timeout,
@@ -406,31 +379,93 @@ tracker_daemon_get_services (TrackerDaemon	    *object,
 	tracker_dbus_request_success (request_id);
 }
 
-
 static void
-stats_cache_update (TrackerDaemon *object)
+stats_cache_filter_dups_func (gpointer data,
+			      gpointer user_data)
 {
-	TrackerDaemonPrivate *priv;
-	TrackerDBResultSet   *result_set;
-	GPtrArray            *stats, *parent_stats;
-	GPtrArray            *values;
-	guint                 i;
-	const gchar          *services_to_fetch[3] = { 
+	GHashTable *values;
+	GStrv       strv;
+	gpointer    p;
+	gint        count;
+
+	/* FIXME: There is a really shit bug here that needs
+	 * fixing. If a file has "Files" as its main category
+	 * and not its *parent* category, then we end up with
+	 * 2 "Files" listings. This sounds like a bug with
+	 * the indexer's insert mechanisms. So far this seems
+	 * to only happen for removable media files
+	 *
+	 * For now, we will concatenate values to sort out the
+	 * duplicates: 
+	 */
+	strv = data;
+	values = user_data;
+
+	count = atoi (strv[1]);
+
+	p = g_hash_table_lookup (values, strv[0]);
+
+	if (G_UNLIKELY (p)) {
+		count += GPOINTER_TO_INT (p);
+	}
+
+	g_hash_table_replace (values, 
+			      g_strdup (strv[0]), 
+			      GINT_TO_POINTER (count));
+}
+
+static GHashTable *
+stats_cache_get_latest (void)
+{
+	TrackerDBResultSet *result_set;
+	TrackerDBInterface *iface;
+	GHashTable         *services;
+	GHashTable         *values;
+	GHashTableIter      iter;
+	gpointer            key, value;
+	guint               i;
+	const gchar        *services_to_fetch[3] = { 
 		TRACKER_DB_FOR_FILE_SERVICE, 
 		TRACKER_DB_FOR_EMAIL_SERVICE, 
 		NULL 
 	};
 
-	priv = TRACKER_DAEMON_GET_PRIVATE (object);
+	/* Set up empty list of services because SQL queries won't give us 0 items. */
+	g_message ("Requesting statistics from database for an accurate signal");
 
-	values = g_ptr_array_new ();
+	iface = tracker_db_manager_get_db_interface (TRACKER_DB_COMMON);
+	result_set = tracker_data_manager_exec_proc (iface, "GetServices", 0);
+	services = tracker_dbus_query_result_to_hash_table (result_set);
+
+	if (result_set) {
+		g_object_unref (result_set);
+	}
 
-	for (i = 0; services_to_fetch[i]; i++) {
+	values = g_hash_table_new_full (g_str_hash,
+					g_str_equal,
+					g_free,
+					NULL);
+
+	/* Put services with 0 counts into new hash table */
+	g_hash_table_iter_init (&iter, services);
+
+	while (g_hash_table_iter_next (&iter, &key, &value)) {
+		g_hash_table_replace (values, g_strdup (key), GINT_TO_POINTER (0));
+	}
+
+	g_hash_table_unref (services);
+
+	/* Populate with real stats */
+	for (i = 0; services_to_fetch[i]; i++) {		
 		TrackerDBInterface *iface;
-		gint                j;
+		GPtrArray          *stats, *parent_stats;
 
 		iface = tracker_db_manager_get_db_interface_by_service (services_to_fetch[i]);
 
+		/* GetStats has asc in its query. Therefore we don't have to
+		 * lookup the in a to compare in b, just compare index based.
+		 * Maybe we want to change this nonetheless later?
+		 */
 		result_set = tracker_data_manager_exec_proc (iface, "GetStats", 0);
 		stats = tracker_dbus_query_result_to_ptr_array (result_set);
 
@@ -444,37 +479,45 @@ stats_cache_update (TrackerDaemon *object)
 		if (result_set) {
 			g_object_unref (result_set);
 		}
-
-		/* Concatenate stats */
-		for (j = 0; j < stats->len; j++) {
-			g_ptr_array_add (values, g_ptr_array_index (stats, j));
-		}
 		
-		for (j = 0; j < parent_stats->len; j++) {
-			g_ptr_array_add (values, g_ptr_array_index (parent_stats, j));
-		}
+		g_ptr_array_foreach (stats, stats_cache_filter_dups_func, values);
+		g_ptr_array_foreach (parent_stats, stats_cache_filter_dups_func, values);
 
 		g_ptr_array_free (parent_stats, TRUE);
 		g_ptr_array_free (stats, TRUE);
 	}
 
-	/* Update local cache */
-	for (i = 0; i < values->len; i++) {
-		gchar       **p;
-		const gchar  *service_type = NULL;
-		gint          new_count;
+	return values;
+}
 
-		p = g_ptr_array_index (values, i);
-		service_type = p[0];
-		new_count = atoi (p[1]);
+static void
+stats_cache_update (TrackerDaemon *object)
+{
+	TrackerDaemonPrivate *priv;
+	GHashTable           *values;
+	GHashTableIter        iter;
+	gpointer              key, value;
+
+	priv = TRACKER_DAEMON_GET_PRIVATE (object);
+
+	/* Get latest */
+	values = stats_cache_get_latest ();
+
+	/* Update local cache */
+	g_hash_table_iter_init (&iter, values);
+	while (g_hash_table_iter_next (&iter, &key, &value)) {
+		const gchar *service_type;
+		gint         new_count;
+		
+		service_type = key;
+		new_count = GPOINTER_TO_INT (value);
 
 		g_hash_table_replace (priv->stats_cache, 
 				      g_strdup (service_type), 
 				      GINT_TO_POINTER (new_count));
 	}
 
-	g_ptr_array_foreach (values, (GFunc) g_strfreev, NULL);
-	g_ptr_array_free (values, TRUE);
+	g_hash_table_unref (values);
 }
 
 static gboolean 
@@ -525,9 +568,9 @@ tracker_daemon_get_stats (TrackerDaemon		 *object,
 
 	g_hash_table_iter_init (&iter, priv->stats_cache);
 	while (g_hash_table_iter_next (&iter, &key, &value)) {
-		GStrv         strv;
-		const gchar  *service_type;
-		gint          count;
+		GStrv        strv;
+		const gchar *service_type;
+		gint         count;
 
 		service_type = key;
 		count = GPOINTER_TO_INT (value);
@@ -775,153 +818,81 @@ tracker_daemon_signal_statistics (void)
 {
 	GObject		     *daemon;
 	TrackerDaemonPrivate *priv;
-	TrackerDBResultSet   *result_set;
-	GPtrArray	     *stats, *parent_stats;
+	GHashTable           *stats;
+	GHashTableIter        iter;
+	gpointer              key, value;
 	GPtrArray            *values;
-	gint                  i;
-	const gchar          *services_to_fetch[3] = {
-		TRACKER_DB_FOR_FILE_SERVICE, 
-		TRACKER_DB_FOR_EMAIL_SERVICE, 
-		NULL
-	};
 
 	daemon = tracker_dbus_get_object (TRACKER_TYPE_DAEMON);
 	priv = TRACKER_DAEMON_GET_PRIVATE (daemon);
 
-	values = g_ptr_array_new ();
-
-	g_message ("Requesting statistics from database for an accurate signal");
-
-	for (i = 0; services_to_fetch[i]; i++) {		
-		TrackerDBInterface *iface;
-		gint                j;
-
-		iface = tracker_db_manager_get_db_interface_by_service (services_to_fetch[i]);
-
-		/* GetStats has asc in its query. Therefore we don't have to
-		 * lookup the in a to compare in b, just compare index based.
-		 * Maybe we want to change this nonetheless later?
-		 */
-		result_set = tracker_data_manager_exec_proc (iface, "GetStats", 0);
-		stats = tracker_dbus_query_result_to_ptr_array (result_set);
-
-		if (result_set) {
-			g_object_unref (result_set);
-		}
-
-		result_set = tracker_data_manager_exec_proc (iface, "GetStatsForParents", 0);
-		parent_stats = tracker_dbus_query_result_to_ptr_array (result_set);
-
-		if (result_set) {
-			g_object_unref (result_set);
-		}
-		
-		for (j = 0; j < stats->len; j++) {
-			g_ptr_array_add (values, g_ptr_array_index (stats, j));
-		}
-
-		for (j = 0; j < parent_stats->len; j++) {
-			g_ptr_array_add (values, g_ptr_array_index (parent_stats, j));
-		}
-
-		g_ptr_array_free (parent_stats, TRUE);
-		g_ptr_array_free (stats, TRUE);
-	}
+	/* Get latest */
+	stats = stats_cache_get_latest ();
 
 	/* There are 3 situations here:
 	 *  - 1. No new stats
 	 *       Action: Do nothing
-	 *  - 2. No previous stats
-	 *       Action: Emit all new stats
-	 *  - 3. New stats and old stats
+	 *  - 2. New stats and old stats
 	 *       Action: Check what has changed and emit new stats
 	 */
 
 	g_message ("Checking for statistics changes and signalling clients...");
 
 	/* Situation #1 */
-	if (!values || values->len < 1) {
+	if (g_hash_table_size (stats) < 1) {
+		g_hash_table_unref (stats);
 		g_message ("  No new statistics, doing nothing");
 		return;
 	}
 
-	if (g_hash_table_size (priv->stats_cache) < 1) {
-		/* Situation #2 */
-		g_message ("  No previous statistics");
-
-		for (i = 0; i < values->len; i++) {
-			const gchar **p;
-			const gchar  *service_type = NULL;
-			gint          new_count;
-
-			p = g_ptr_array_index (values, i);
+	/* Situation #2 */
+	values = g_ptr_array_new ();
 
-			service_type = p[0];
-			new_count = atoi (p[1]);
+	g_hash_table_iter_init (&iter, stats);
+	while (g_hash_table_iter_next (&iter, &key, &value)) {
+		const gchar  *service_type;
+		gpointer      data;
+		gint          old_count, new_count;
+		
+		service_type = key;
+		new_count = GPOINTER_TO_INT (value);
 			
-			if (!service_type) {
-				continue;
-			}
+		data = g_hash_table_lookup (priv->stats_cache, service_type);
+		old_count = GPOINTER_TO_INT (data);
+		
+		if (old_count != new_count) {
+			GStrv strv;
 
-			g_message ("  Adding '%s' with count:%d", 
+			g_message ("  Updating '%s' with new count:%d, old count:%d, diff:%d", 
 				   service_type,
-				   new_count);
-			g_hash_table_insert (priv->stats_cache, 
-					     g_strdup (service_type), 
-					     GINT_TO_POINTER (new_count));
+				   new_count,
+				   old_count,
+				   new_count - old_count);
+			
+			g_hash_table_replace (priv->stats_cache, 
+					      g_strdup (service_type), 
+					      GINT_TO_POINTER (new_count));
+
+			strv = g_new (gchar*, 3);
+			strv[0] = g_strdup (service_type);
+			strv[1] = g_strdup_printf ("%d", new_count);
+			strv[2] = NULL;
+			
+			g_ptr_array_add (values, strv);
 		}
+	}
+
+	g_hash_table_unref (stats);
 
-		/* Emit signal */
+	if (values->len > 0) {
+		/* Make sure we sort the results first */
+		g_ptr_array_sort (values, stats_cache_sort_func);
+		
 		g_signal_emit (daemon, signals[SERVICE_STATISTICS_UPDATED], 0, values);
 	} else {
-		/* Situation #3 */
-		for (i = 0; i < values->len; i++) {
-			gchar       **p;
-			const gchar  *service_type = NULL;
-			gpointer      data;
-			gint          old_count, new_count;
-
-			p = g_ptr_array_index (values, i);
-			service_type = p[0];
-			new_count = atoi (p[1]);
-
-			if (!service_type) {
-				continue;
-			}
-
-			data = g_hash_table_lookup (priv->stats_cache, service_type);
-			old_count = GPOINTER_TO_INT (data);
-
-			if (old_count != new_count) {
-				g_message ("  Updating '%s' with new count:%d, old count:%d, diff:%d", 
-					   service_type,
-					   new_count,
-					   old_count,
-					   new_count - old_count);
-
-				g_hash_table_replace (priv->stats_cache, 
-						      g_strdup (service_type), 
-						      GINT_TO_POINTER (new_count));
-			} else {
-				/* Remove from values since the value is the same */
-				g_strfreev (p);
-				g_ptr_array_remove (values, p);
-
-				/* Decrement i since we are about to
-				 * increment it and we just removed
-				 * an item. Otherwise we miss items.
-				 */
-				i--;
-			}
-		}
-
-		if (values->len > 0) {
-			g_signal_emit (daemon, signals[SERVICE_STATISTICS_UPDATED], 0, values);
-		} else {
-			g_message ("  No changes in the statistics");
-		}
+		g_message ("  No changes in the statistics");
 	}
-
+	
 	g_ptr_array_foreach (values, (GFunc) g_strfreev, NULL);
 	g_ptr_array_free (values, TRUE);
 }



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