[evolution-data-server] Reduce frequency of CamelFolder::changed emissions.
- From: Matthew Barnes <mbarnes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Reduce frequency of CamelFolder::changed emissions.
- Date: Tue, 29 Nov 2011 23:14:35 +0000 (UTC)
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]