[evolution-data-server] Reduce frequency of CamelFolder::changed emissions.



commit d2dfeeef62f9b588ddcb858dc20903320ffee276
Author: Matthew Barnes <mbarnes redhat com>
Date:   Tue Nov 29 16:58:32 2011 -0600

    Reduce frequency of CamelFolder::changed emissions.
    
    If camel_folder_changed() is called after an idle callback for the
    signal emission has already been scheduled but not yet dispatched,
    append the new change info to the pending change info instead of
    scheduling another idle callback.
    
    Virtual folders schedule a background job for every "changed" signal
    emission, and this taxes the CPU unnecessarily hard, especially when
    IMAPX is downloading folder summaries for the first time.
    
    These changes are still not optimal, but my own measurements showed
    a significant reduction in CamelFolder::changed signal emissions.

 camel/camel-folder.c |   61 ++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 45 insertions(+), 16 deletions(-)
---
diff --git a/camel/camel-folder.c b/camel/camel-folder.c
index d0fec0d..ae0b405 100644
--- a/camel/camel-folder.c
+++ b/camel/camel-folder.c
@@ -54,9 +54,12 @@ struct _CamelFolderPrivate {
 	GStaticMutex change_lock;
 	/* must require the 'change_lock' to access this */
 	gint frozen;
-	struct _CamelFolderChangeInfo *changed_frozen; /* queues changed events */
+	CamelFolderChangeInfo *changed_frozen; /* queues changed events */
 	gboolean skip_folder_lock;
 
+	/* Changes to be emitted from an idle callback. */
+	CamelFolderChangeInfo *pending_changes;
+
 	gpointer parent_store;  /* weak pointer */
 
 	gchar *full_name;
@@ -88,7 +91,6 @@ struct _CamelFolderChangeInfoPrivate {
 
 struct _SignalData {
 	CamelFolder *folder;
-	CamelFolderChangeInfo *changes;
 	gchar *folder_name;
 };
 
@@ -159,9 +161,6 @@ signal_data_free (SignalData *data)
 	if (data->folder != NULL)
 		g_object_unref (data->folder);
 
-	if (data->changes != NULL)
-		camel_folder_change_info_free (data->changes);
-
 	g_free (data->folder_name);
 
 	g_slice_free (SignalData, data);
@@ -170,7 +169,16 @@ signal_data_free (SignalData *data)
 static gboolean
 folder_emit_changed_cb (SignalData *data)
 {
-	g_signal_emit (data->folder, signals[CHANGED], 0, data->changes);
+	CamelFolderChangeInfo *changes;
+
+	camel_folder_lock (data->folder, CAMEL_FOLDER_CHANGE_LOCK);
+	changes = data->folder->priv->pending_changes;
+	data->folder->priv->pending_changes = NULL;
+	camel_folder_unlock (data->folder, CAMEL_FOLDER_CHANGE_LOCK);
+
+	g_signal_emit (data->folder, signals[CHANGED], 0, changes);
+
+	camel_folder_change_info_free (changes);
 
 	return FALSE;
 }
@@ -549,6 +557,9 @@ folder_finalize (GObject *object)
 
 	camel_folder_change_info_free (priv->changed_frozen);
 
+	if (priv->pending_changes != NULL)
+		camel_folder_change_info_free (priv->pending_changes);
+
 	g_static_rec_mutex_free (&priv->lock);
 	g_static_mutex_free (&priv->change_lock);
 
@@ -2690,7 +2701,7 @@ camel_folder_rename (CamelFolder *folder,
  * @changes: change information for @folder
  *
  * Emits the #CamelFolder::changed signal from an idle source on the
- * main loop.  The idle source's priority is #G_PRIORITY_DEFAULT_IDLE.
+ * main loop.  The idle source's priority is #G_PRIORITY_LOW.
  *
  * Since: 2.32
  **/
@@ -2698,7 +2709,7 @@ void
 camel_folder_changed (CamelFolder *folder,
                       CamelFolderChangeInfo *changes)
 {
-	SignalData *data;
+	CamelFolderChangeInfo *pending_changes;
 
 	g_return_if_fail (CAMEL_IS_FOLDER (folder));
 	g_return_if_fail (changes != NULL);
@@ -2710,16 +2721,34 @@ camel_folder_changed (CamelFolder *folder,
 		return;
 	}
 
-	data = g_slice_new0 (SignalData);
-	data->folder = g_object_ref (folder);
-	data->changes = camel_folder_change_info_new ();
+	/* If a "changed" signal has already been scheduled but not yet
+	 * emitted, just append our changes to the pending changes, and
+	 * skip scheduling our own "changed" signal.  This helps to cut
+	 * down on the frequency of signal emissions so virtual folders
+	 * won't have to work so hard. */
+
+	camel_folder_lock (folder, CAMEL_FOLDER_CHANGE_LOCK);
 
-	camel_folder_change_info_cat (data->changes, changes);
+	pending_changes = folder->priv->pending_changes;
 
-	g_idle_add_full (
-		G_PRIORITY_DEFAULT_IDLE,
-		(GSourceFunc) folder_emit_changed_cb,
-		data, (GDestroyNotify) signal_data_free);
+	if (pending_changes == NULL) {
+		SignalData *data;
+
+		pending_changes = camel_folder_change_info_new ();
+		folder->priv->pending_changes = pending_changes;
+
+		data = g_slice_new0 (SignalData);
+		data->folder = g_object_ref (folder);
+
+		g_idle_add_full (
+			G_PRIORITY_LOW,
+			(GSourceFunc) folder_emit_changed_cb,
+			data, (GDestroyNotify) signal_data_free);
+	}
+
+	camel_folder_change_info_cat (pending_changes, changes);
+
+	camel_folder_unlock (folder, CAMEL_FOLDER_CHANGE_LOCK);
 }
 
 /**



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