[evolution-data-server] CamelVeeFolder: Fix a deadlock.



commit 6bc75c47f516301364d653140fcf82193d0a2d52
Author: Matthew Barnes <mbarnes redhat com>
Date:   Sun May 29 18:34:49 2011 -0400

    CamelVeeFolder: Fix a deadlock.
    
    folder_added_uid() was trying to obtain a reader lock while holding a
    writer lock, since a DB transaction had already been started.
    
    To work around the issue, queue up message UIDs in folder_added_uid(),
    and then execute a DB transaction using the queued message UIDs AFTER
    we're done iterating over the 'matchhash' hash table.

 camel/camel-vee-folder.c |   82 ++++++++++++++++++++++++++++------------------
 1 files changed, 50 insertions(+), 32 deletions(-)
---
diff --git a/camel/camel-vee-folder.c b/camel/camel-vee-folder.c
index c8f172e..aef735b 100644
--- a/camel/camel-vee-folder.c
+++ b/camel/camel-vee-folder.c
@@ -63,6 +63,7 @@ struct _update_data {
 	CamelVeeFolder *folder_unmatched;
 	GHashTable *unmatched_uids;
 	gboolean rebuilt, correlating;
+	GQueue *message_uids;
 };
 
 struct _FolderChangedData {
@@ -707,36 +708,40 @@ folder_added_uid (gchar *uidin, gpointer value, struct _update_data *u)
 	CamelVeeMessageInfo *mi;
 	gchar *oldkey;
 	gpointer oldval;
+	const gchar *uid;
 	gint n;
 
-	if ((mi = vee_folder_add_uid (u->vee_folder, u->source, uidin, u->hash)) != NULL) {
-		camel_folder_change_info_add_uid (u->vee_folder->changes, camel_message_info_uid (mi));
-		/* FIXME[disk-summary] Handle exceptions */
-		/* FIXME[disk-summary] Make all these as transactions, just
-		 * testing atm */
-		if (u->rebuilt && !u->correlating) {
-			CamelStore *parent_store;
-			const gchar *full_name;
+	mi = vee_folder_add_uid (u->vee_folder, u->source, uidin, u->hash);
+	if (mi == NULL)
+		return;
 
-			full_name = camel_folder_get_full_name (
-				CAMEL_FOLDER (u->vee_folder));
-			parent_store = camel_folder_get_parent_store (
-				CAMEL_FOLDER (u->vee_folder));
-			camel_db_add_to_vfolder_transaction (
-				parent_store->cdb_w, full_name,
-				camel_message_info_uid (mi), NULL);
-		}
-		if (!CAMEL_IS_VEE_FOLDER (u->source) && u->unmatched_uids != NULL) {
-			if (g_hash_table_lookup_extended (u->unmatched_uids, camel_message_info_uid (mi), (gpointer *)&oldkey, &oldval)) {
-				n = GPOINTER_TO_INT (oldval);
-				g_hash_table_insert (u->unmatched_uids, oldkey, GINT_TO_POINTER (n+1));
-			} else {
-				g_hash_table_insert (u->unmatched_uids, g_strdup (camel_message_info_uid (mi)), GINT_TO_POINTER (1));
-			}
-		}
+	uid = camel_message_info_uid (mi);
 
-		camel_message_info_free ((CamelMessageInfo *) mi);
+	if (u->message_uids != NULL)
+		g_queue_push_tail (u->message_uids, g_strdup (uid));
+
+	camel_folder_change_info_add_uid (u->vee_folder->changes, uid);
+
+	if (!CAMEL_IS_VEE_FOLDER (u->source) && u->unmatched_uids != NULL) {
+		gboolean found_uid;
+
+		found_uid = g_hash_table_lookup_extended (
+			u->unmatched_uids, uid,
+			(gpointer *) &oldkey, &oldval);
+
+		if (found_uid) {
+			n = GPOINTER_TO_INT (oldval);
+			g_hash_table_insert (
+				u->unmatched_uids,
+				oldkey, GINT_TO_POINTER (n + 1));
+		} else {
+			g_hash_table_insert (
+				u->unmatched_uids,
+				g_strdup (uid), GINT_TO_POINTER (1));
+		}
 	}
+
+	camel_message_info_free ((CamelMessageInfo *) mi);
 }
 
 static gint
@@ -1775,21 +1780,34 @@ vee_folder_rebuild_folder (CamelVeeFolder *vee_folder,
 	if (last != -1)
 		camel_folder_summary_remove_range (folder->summary, start, last);
 
+	if (rebuilded && !correlating)
+		u.message_uids = g_queue_new ();
+	else
+		u.message_uids = NULL;
+
 	/* now matchhash contains any new uid's, add them, etc */
-	if (rebuilded && !correlating) {
+	g_hash_table_foreach (matchhash, (GHFunc) folder_added_uid, &u);
+
+	if (u.message_uids != NULL) {
 		CamelStore *parent_store;
+		const gchar *full_name;
+		gchar *uid;
 
+		full_name = camel_folder_get_full_name (folder);
 		parent_store = camel_folder_get_parent_store (folder);
-		camel_db_begin_transaction (parent_store->cdb_w, NULL);
-	}
 
-	g_hash_table_foreach (matchhash, (GHFunc) folder_added_uid, &u);
+		camel_db_begin_transaction (parent_store->cdb_w, NULL);
 
-	if (rebuilded && !correlating) {
-		CamelStore *parent_store;
+		while ((uid = g_queue_pop_head (u.message_uids)) != NULL) {
+			camel_db_add_to_vfolder_transaction (
+				parent_store->cdb_w, full_name, uid, NULL);
+			g_free (uid);
+		}
 
-		parent_store = camel_folder_get_parent_store (folder);
 		camel_db_end_transaction (parent_store->cdb_w, NULL);
+
+		g_queue_free (u.message_uids);
+		u.message_uids = NULL;
 	}
 
 	if (folder_unmatched != NULL) {



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