[evolution-data-server] CamelVeeFolder: Process folder changes more efficiently.



commit 0aa975e6a2c28099ea589d782d2f77ffc4ae9c6e
Author: Matthew Barnes <mbarnes redhat com>
Date:   Sat Jan 21 00:33:40 2012 -0500

    CamelVeeFolder: Process folder changes more efficiently.
    
    CamelVeeFolder submits a new background job every time it receives a
    CamelFolder::changed signal.  So the background jobs tend to pile up,
    and there's no guarantee the jobs will be dispatched in the order
    they were submitted since they're dispatched from a thread pool.
    
    Instead, run one background job at a time, and have the job process
    FolderChangedData from a queue until the queue is empty.  If another
    CamelFolder::changed signal is received while the background job is
    still running, the changes are simply be appended to the queue.

 camel/camel-vee-folder.c |   76 +++++++++++++++++++++++++++++++++++----------
 1 files changed, 59 insertions(+), 17 deletions(-)
---
diff --git a/camel/camel-vee-folder.c b/camel/camel-vee-folder.c
index 9df452e..f8a6308 100644
--- a/camel/camel-vee-folder.c
+++ b/camel/camel-vee-folder.c
@@ -52,6 +52,10 @@ struct _CamelVeeFolderPrivate {
 	GHashTable *ignore_changed;	/* hash of subfolder pointers to ignore the next folder's 'changed' signal */
 	GHashTable *skipped_changes;	/* CamelFolder -> CamelFolderChangeInfo accumulating ignored changes */
 
+	/* Processing queue for folder changes. */
+	GAsyncQueue *change_queue;
+	gboolean change_queue_busy;
+
 	GMutex *summary_lock;		/* for locking vfolder summary */
 	GMutex *subfolder_lock;		/* for locking the subfolder list */
 	GMutex *changed_lock;		/* for locking the folders-changed list */
@@ -73,7 +77,6 @@ struct _update_data {
 struct _FolderChangedData {
 	CamelFolderChangeInfo *changes;
 	CamelFolder *sub;
-	CamelVeeFolder *vee_folder;
 };
 
 G_DEFINE_TYPE (CamelVeeFolder, camel_vee_folder, CAMEL_TYPE_FOLDER)
@@ -82,7 +85,6 @@ static void
 folder_changed_data_free (FolderChangedData *data)
 {
 	camel_folder_change_info_free (data->changes);
-	g_object_unref (data->vee_folder);
 	g_object_unref (data->sub);
 
 	g_slice_free (FolderChangedData, data);
@@ -331,14 +333,13 @@ vfolder_add_remove_transaction (CamelStore *parent_store,
 }
 
 static void
-folder_changed_change (CamelSession *session,
+folder_changed_change (CamelVeeFolder *vf,
                        GCancellable *cancellable,
                        FolderChangedData *data,
                        GError **error)
 {
 	CamelFolder *sub = data->sub;
-	CamelFolder *folder = CAMEL_FOLDER (data->vee_folder);
-	CamelVeeFolder *vf = data->vee_folder;
+	CamelFolder *folder = CAMEL_FOLDER (vf);
 	CamelFolderChangeInfo *changes = data->changes;
 	gchar *vuid = NULL, hash[8];
 	const gchar *uid;
@@ -359,15 +360,11 @@ folder_changed_change (CamelSession *session,
 	/* See vee_folder_rebuild_folder. */
 	gboolean correlating = expression_is_correlating (vf->expression);
 
-	camel_operation_push_message (
-		cancellable, _("Updating %s folder"),
-		camel_folder_get_display_name (folder));
-
 	/* Check the folder hasn't beem removed while we weren't watching */
 	camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
 	if (g_list_find (vf->priv->folders, sub) == NULL) {
 		camel_vee_folder_unlock (vf, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
-		goto exit;
+		return;
 	}
 
 	camel_vee_folder_hash_folder (sub, hash);
@@ -628,8 +625,37 @@ folder_changed_change (CamelSession *session,
 		camel_folder_changed (CAMEL_FOLDER (vf), vf_changes);
 		camel_folder_change_info_free (vf_changes);
 	}
+}
+
+static void
+vee_folder_process_changes (CamelSession *session,
+                            GCancellable *cancellable,
+                            CamelVeeFolder *vee_folder,
+                            GError **error)
+{
+	CamelFolder *folder;
+	FolderChangedData *data;
+	GAsyncQueue *change_queue;
+	const gchar *display_name;
+
+	folder = CAMEL_FOLDER (vee_folder);
+	display_name = camel_folder_get_display_name (folder);
+
+	change_queue = vee_folder->priv->change_queue;
+
+	camel_operation_push_message (
+		cancellable, _("Updating %s folder"), display_name);
+
+	while ((data = g_async_queue_try_pop (change_queue)) != NULL) {
+		folder_changed_change (vee_folder, cancellable, data, error);
+		folder_changed_data_free (data);
+
+		if (g_cancellable_is_cancelled (cancellable))
+			break;
+	}
+
+	vee_folder->priv->change_queue_busy = FALSE;
 
-exit:
 	camel_operation_pop_message (cancellable);
 }
 
@@ -1012,6 +1038,8 @@ vee_folder_finalize (GObject *object)
 	g_hash_table_destroy (vf->priv->ignore_changed);
 	g_hash_table_destroy (vf->priv->skipped_changes);
 
+	g_async_queue_unref (vf->priv->change_queue);
+
 	/* Chain up to parent's finalize () method. */
 	G_OBJECT_CLASS (camel_vee_folder_parent_class)->finalize (object);
 }
@@ -1943,25 +1971,36 @@ vee_folder_folder_changed (CamelVeeFolder *vee_folder,
 {
 	CamelVeeFolderPrivate *p = vee_folder->priv;
 	FolderChangedData *data;
+	CamelFolder *folder;
 	CamelStore *parent_store;
 	CamelSession *session;
 
 	if (p->destroyed)
 		return;
 
-	parent_store = camel_folder_get_parent_store (CAMEL_FOLDER (vee_folder));
+	folder = CAMEL_FOLDER (vee_folder);
+	parent_store = camel_folder_get_parent_store (folder);
 	session = camel_service_get_session (CAMEL_SERVICE (parent_store));
 
+	g_async_queue_lock (vee_folder->priv->change_queue);
+
 	data = g_slice_new0 (FolderChangedData);
 	data->changes = camel_folder_change_info_new ();
 	camel_folder_change_info_cat (data->changes, changes);
 	data->sub = g_object_ref (sub);
-	data->vee_folder = g_object_ref (vee_folder);
 
-	camel_session_submit_job (
-		session, (CamelSessionCallback)
-		folder_changed_change, data,
-		(GDestroyNotify) folder_changed_data_free);
+	g_async_queue_push_unlocked (vee_folder->priv->change_queue, data);
+
+	if (!vee_folder->priv->change_queue_busy) {
+		camel_session_submit_job (
+			session, (CamelSessionCallback)
+			vee_folder_process_changes,
+			g_object_ref (vee_folder),
+			(GDestroyNotify) g_object_unref);
+		vee_folder->priv->change_queue_busy = TRUE;
+	}
+
+	g_async_queue_unlock (vee_folder->priv->change_queue);
 }
 
 static void
@@ -2049,6 +2088,9 @@ camel_vee_folder_init (CamelVeeFolder *vee_folder)
 	vee_folder->priv->changed_lock = g_mutex_new ();
 	vee_folder->priv->ignore_changed = g_hash_table_new (g_direct_hash, g_direct_equal);
 	vee_folder->priv->skipped_changes = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+	vee_folder->priv->change_queue = g_async_queue_new_full (
+		(GDestroyNotify) folder_changed_data_free);
 }
 
 void



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