diff -u -p -u -r1.12 rhythmdb-private.h
--- rhythmdb/rhythmdb-private.h	19 Jun 2006 01:45:18 -0000	1.12
+++ rhythmdb/rhythmdb-private.h	26 Jun 2006 10:40:46 -0000
@@ -57,6 +57,9 @@ typedef struct {
 enum {
 	RHYTHMDB_ENTRY_HIDDEN = 1,
 	RHYTHMDB_ENTRY_INSERTED = 2,
+	RHYTHMDB_ENTRY_LAST_PLAYED_DIRTY = 4,
+	RHYTHMDB_ENTRY_FIRST_SEEN_DIRTY = 8,
+	RHYTHMDB_ENTRY_LAST_SEEN_DIRTY = 16,
 
 	/* the backend can use the top 16 bits for private flags */
 	RHYTHMDB_ENTRY_PRIVATE_FLAG_BASE = 65536,
diff -u -p -u -r1.229 rhythmdb.c
--- rhythmdb/rhythmdb.c	22 Jun 2006 10:27:40 -0000	1.229
+++ rhythmdb/rhythmdb.c	26 Jun 2006 10:40:49 -0000
@@ -113,6 +113,8 @@ static void library_location_changed_cb 
 					  GConfEntry *entry,
 					  RhythmDB *db);
 static void rhythmdb_sync_library_location (RhythmDB *db);
+static void rhythmdb_entry_sync_mirrored (RhythmDBEntry *entry,
+					  guint propid);
 
 enum
 {
@@ -942,9 +944,10 @@ rhythmdb_entry_allocate (RhythmDB *db, R
 	ret->album = rb_refstring_ref (db->priv->empty_string);
 	ret->mimetype = rb_refstring_ref (db->priv->octet_stream_str);
 
-	rhythmdb_entry_sync_mirrored (db, ret, RHYTHMDB_PROP_LAST_PLAYED);
-	rhythmdb_entry_sync_mirrored (db, ret, RHYTHMDB_PROP_FIRST_SEEN);
-	
+	ret->flags |= RHYTHMDB_ENTRY_LAST_PLAYED_DIRTY |
+		      RHYTHMDB_ENTRY_FIRST_SEEN_DIRTY |
+		      RHYTHMDB_ENTRY_LAST_SEEN_DIRTY;
+
 	/* The refcount is initially 0, we want to set it to 1 */
 	g_atomic_int_inc (&ret->refcount);
 
@@ -1972,6 +1975,8 @@ void
 rhythmdb_entry_get (RhythmDB *db, RhythmDBEntry *entry, 
 		    RhythmDBPropType propid, GValue *val)
 {
+	rhythmdb_entry_sync_mirrored (entry, propid);
+
 	g_assert (G_VALUE_TYPE (val) == rhythmdb_get_property_type (db, propid));
 	switch (rhythmdb_property_type_map[propid]) {
 	case G_TYPE_STRING:
@@ -2558,9 +2563,11 @@ rhythmdb_entry_set_internal (RhythmDB *d
 			break;
 		case RHYTHMDB_PROP_FIRST_SEEN:
 			entry->first_seen = g_value_get_ulong (value);
+			entry->flags |= RHYTHMDB_ENTRY_FIRST_SEEN_DIRTY;
 			break;
 		case RHYTHMDB_PROP_LAST_SEEN:
 			entry->last_seen = g_value_get_ulong (value);
+			entry->flags |= RHYTHMDB_ENTRY_LAST_SEEN_DIRTY;
 			break;
 		case RHYTHMDB_PROP_RATING:
 			entry->rating = g_value_get_double (value);
@@ -2570,6 +2577,7 @@ rhythmdb_entry_set_internal (RhythmDB *d
 			break;
 		case RHYTHMDB_PROP_LAST_PLAYED:
 			entry->last_played = g_value_get_ulong (value);
+			entry->flags |= RHYTHMDB_ENTRY_LAST_PLAYED_DIRTY;
 			break;
 		case RHYTHMDB_PROP_HIDDEN:
 			if (g_value_get_boolean (value)) {
@@ -2577,6 +2585,7 @@ rhythmdb_entry_set_internal (RhythmDB *d
 			} else {
 				entry->flags &= ~RHYTHMDB_ENTRY_HIDDEN;
 			}
+			entry->flags |= RHYTHMDB_ENTRY_LAST_SEEN_DIRTY;
 			break;
 		case RHYTHMDB_PROP_STATUS:
 			g_assert (podcast);
@@ -2621,7 +2630,6 @@ rhythmdb_entry_set_internal (RhythmDB *d
 			break;
 		}
 	}
-	rhythmdb_entry_sync_mirrored (db, entry, propid);
 	
 	/* set the dirty state */
 	db->priv->dirty = TRUE;
@@ -2641,8 +2649,8 @@ rhythmdb_entry_set_internal (RhythmDB *d
  **/
 
 
-void
-rhythmdb_entry_sync_mirrored (RhythmDB *db, RhythmDBEntry *entry, guint propid)
+static void
+rhythmdb_entry_sync_mirrored (RhythmDBEntry *entry, guint propid)
 {
 	static const char *format;
 	static const char *never;
@@ -2655,38 +2663,68 @@ rhythmdb_entry_sync_mirrored (RhythmDB *
 		never = _("Never");
 	
 	switch (propid) {
-	case RHYTHMDB_PROP_LAST_PLAYED:
+	case RHYTHMDB_PROP_LAST_PLAYED_STR:
 	{
-		rb_refstring_unref (entry->last_played_str);
+		RBRefString *old, *new;
+
+		if (!(entry->flags & RHYTHMDB_ENTRY_LAST_PLAYED_DIRTY))
+			break;
+
+		old = g_atomic_pointer_get (&entry->last_played_str);
 		if (entry->last_played == 0) {
-			entry->last_played_str = rb_refstring_new (never);
+			new = rb_refstring_new (never);
 		} else {
 			val = eel_strdup_strftime (format, localtime ((glong*)&entry->last_played));
-			entry->last_played_str = rb_refstring_new (val);
+			new = rb_refstring_new (val);
 			g_free (val);
 		}
+
+		if (g_atomic_pointer_compare_and_exchange ((gpointer*)&entry->last_played_str, old, new))
+			rb_refstring_unref (old);
+		else
+			rb_refstring_unref (new);
+
 		break;
 	}
-	case RHYTHMDB_PROP_FIRST_SEEN:
+	case RHYTHMDB_PROP_FIRST_SEEN_STR:
 	{
-		rb_refstring_unref (entry->first_seen_str);
+		RBRefString *old, *new;
+
+		if (!(entry->flags & RHYTHMDB_ENTRY_FIRST_SEEN_DIRTY))
+			break;
+
+		old = g_atomic_pointer_get (&entry->first_seen_str);
 		val = eel_strdup_strftime (format, localtime ((glong*)&entry->first_seen));
-		entry->first_seen_str = rb_refstring_new (val);
+		new = rb_refstring_new (val);
 		g_free (val);
+
+		if (g_atomic_pointer_compare_and_exchange ((gpointer*)&entry->first_seen_str, old, new))
+			rb_refstring_unref (old);
+		else
+			rb_refstring_unref (new);
 		break;
 	}
-	case RHYTHMDB_PROP_LAST_SEEN:
-	case RHYTHMDB_PROP_HIDDEN:
+	case RHYTHMDB_PROP_LAST_SEEN_STR:
 	{
+		RBRefString *old, *new;
+
+		if (!(entry->flags & RHYTHMDB_ENTRY_LAST_SEEN_DIRTY))
+			break;
+
+		old = g_atomic_pointer_get (&entry->last_seen_str);
 		/* only store last seen time as a string for hidden entries */
-		rb_refstring_unref (entry->last_seen_str);
 		if (entry->flags & RHYTHMDB_ENTRY_HIDDEN) {
 			val = eel_strdup_strftime (format, localtime ((glong*)&entry->last_seen));
-			entry->last_seen_str = rb_refstring_new (val);
+			new = rb_refstring_new (val);
 			g_free (val);
 		} else {
-			entry->last_seen_str = NULL;
+			new = NULL;
 		}
+
+		if (g_atomic_pointer_compare_and_exchange ((gpointer*)&entry->first_seen_str, old, new))
+			rb_refstring_unref (old);
+		else
+			rb_refstring_unref (new);
 		break;
 	}
 	default:
@@ -3557,8 +3595,6 @@ rhythmdb_entry_set_visibility (RhythmDB 
 		rhythmdb_entry_set_internal (db, entry, TRUE,
 					     RHYTHMDB_PROP_HIDDEN, &new_val);
 		g_value_unset (&new_val);
-
-		rhythmdb_entry_sync_mirrored (db, entry, RHYTHMDB_PROP_LAST_SEEN);
 	}
 	g_value_unset (&old_val);
 }
@@ -3632,6 +3668,8 @@ rhythmdb_entry_get_string (RhythmDBEntry
 	if (entry->type == RHYTHMDB_ENTRY_TYPE_PODCAST_FEED ||
 	    entry->type == RHYTHMDB_ENTRY_TYPE_PODCAST_POST)
 		podcast = RHYTHMDB_ENTRY_GET_TYPE_DATA (entry, RhythmDBPodcastFields);
+
+	rhythmdb_entry_sync_mirrored (entry, propid);
 
 	switch (propid) {
 	case RHYTHMDB_PROP_TITLE:
diff -u -p -u -r1.87 rhythmdb.h
--- rhythmdb/rhythmdb.h	19 Jun 2006 04:38:45 -0000	1.87
+++ rhythmdb/rhythmdb.h	26 Jun 2006 10:40:49 -0000
@@ -374,8 +374,6 @@ void		rhythmdb_do_full_query_async_parse
 							 RhythmDBQueryResults *results,
 							 GPtrArray *query);
 
-void		rhythmdb_entry_sync_mirrored		(RhythmDB *db, RhythmDBEntry *entry, guint propid);
-
 GPtrArray *	rhythmdb_query_parse			(RhythmDB *db, ...);
 void		rhythmdb_query_append			(RhythmDB *db, GPtrArray *query, ...);
 void		rhythmdb_query_append_prop_multiple	(RhythmDB *db, GPtrArray *query, RhythmDBPropType propid, GList *items);
diff -u -p -u -r1.11 Makefile.am
--- tests/Makefile.am	2 Jun 2006 13:46:16 -0000	1.11
+++ tests/Makefile.am	26 Jun 2006 10:40:49 -0000
@@ -1,10 +1,19 @@
 ## arch-tag: Automake rules for test programs
 ## Process this file with automake to produce Makefile.in
 
-TESTS =
+TESTS = bench-rhythmdb-load
 
 test_rhythmdb_SOURCES = test-rhythmdb.c
 test_rhythmdb_LDADD = \
+	$(CHECK_LIBS)						\
+	$(top_builddir)/rhythmdb/librhythmdb.la 		\
+	$(top_builddir)/lib/librb.la				\
+	$(top_builddir)/metadata/librbmetadata.la		\
+	$(top_builddir)/widgets/librbwidgets.la			\
+	$(RHYTHMBOX_LIBS)
+
+bench_rhythmdb_load_SOURCES = bench-rhythmdb-load.c
+bench_rhythmdb_load_LDADD = \
 	$(CHECK_LIBS)						\
 	$(top_builddir)/rhythmdb/librhythmdb.la 		\
 	$(top_builddir)/lib/librb.la				\
--- /dev/null	2006-05-23 00:25:23.000000000 +1000
+++ tests/bench-rhythmdb-load.c	2006-06-26 20:13:11.000000000 +1000
@@ -0,0 +1,113 @@
+#include <gtk/gtk.h>
+#include <string.h>
+
+#include "rb-debug.h"
+#include "rb-file-helpers.h"
+#include "rb-util.h"
+
+#include "rhythmdb.h"
+#include "rhythmdb-tree.h"
+
+/* test utils */
+gboolean waiting, signaled;
+char *sig_name;
+
+
+static void
+mark_signal (void)
+{
+	if (signaled) {
+		rb_debug ("got signal '%s' multiple times", sig_name);
+	} else {
+		rb_debug ("got signal '%s'", sig_name);
+		signaled = TRUE;
+		if (waiting)
+			gtk_main_quit ();
+	}
+}
+
+static void
+set_waiting_signal (GObject *o, const char *name)
+{
+	signaled = FALSE;
+	waiting = FALSE;
+	sig_name = g_strdup (name);
+	g_signal_connect (o, sig_name, G_CALLBACK (mark_signal), NULL);
+}
+
+static void wait_for_signal (void)
+{
+	if (!signaled) {
+		rb_debug ("waiting for signal '%s'", sig_name);
+		waiting = TRUE;
+		gtk_main ();
+	} else {
+		rb_debug ("no need to wait for signal '%s', already received", sig_name);
+	}
+
+	g_free (sig_name);
+	sig_name = NULL;
+}
+
+
+int 
+main (int argc, char **argv)
+{
+	RhythmDB *db;
+	char *name;
+	int i;
+
+	if (argc < 2) {
+		g_print ("using ~/.gnome2/rhythmbox/rhythmdb.xml\n");
+		name = g_strdup_printf ("%s/rhythmdb.xml", rb_dot_dir ());
+	} else {
+		name = g_strdup (argv[1]);
+	}
+
+	rb_profile_start ("load test");
+
+	g_thread_init (NULL);
+	rb_threads_init ();
+	gtk_set_locale ();
+	gtk_init (&argc, &argv);
+	gnome_vfs_init ();
+	rb_debug_init (FALSE);
+	rb_refstring_system_init ();
+	rb_file_helpers_init ();
+
+	GDK_THREADS_ENTER ();
+
+	db = rhythmdb_tree_new ("test");
+	g_object_set (G_OBJECT (db), "name", name, NULL);
+	g_free (name);
+
+	for (i = 1; i <= 10; i++) {
+		int j;
+		rb_profile_start ("10 rhythmdb loads");
+		for (j = 1; j <= 10; j++) {
+			set_waiting_signal (G_OBJECT (db), "load-complete");
+			rhythmdb_load (db);
+			wait_for_signal ();
+
+			rhythmdb_entry_delete_by_type (db, RHYTHMDB_ENTRY_TYPE_SONG);
+			rhythmdb_entry_delete_by_type (db, RHYTHMDB_ENTRY_TYPE_IRADIO_STATION);
+			rhythmdb_entry_delete_by_type (db, RHYTHMDB_ENTRY_TYPE_PODCAST_FEED);
+			rhythmdb_entry_delete_by_type (db, RHYTHMDB_ENTRY_TYPE_PODCAST_POST);
+		}
+		rb_profile_end ("10 rhythmdb loads");
+		g_print ("completed %d loads\n", i * 10);
+	}
+
+	rhythmdb_shutdown (db);
+	g_object_unref (G_OBJECT (db));
+	db = NULL;
+
+	
+	rb_file_helpers_shutdown ();
+        rb_refstring_system_shutdown ();
+        gnome_vfs_shutdown ();
+
+
+	rb_profile_end ("load test");
+	return 0;
+}
