[evolution-data-server] EDataFactory: Keep only weak references to backends.



commit da511b9d80abdfbea2ff8bb0eaf6c05b6ef426ab
Author: Matthew Barnes <mbarnes redhat com>
Date:   Mon Apr 16 09:43:09 2012 -0400

    EDataFactory: Keep only weak references to backends.
    
    Have EDataFactory keep only weak references to the EBackend instances it
    creates.  Then, when the last client connection to a backend closes, the
    backend finalizes automatically.  No explicit action required.
    
    This breaks the API slightly by renaming e_data_factory_get_backend() to
    e_data_factory_ref_backend() to reflect the fact that a strong reference
    is now returned to the caller, and the caller must call g_object_unref()
    when finished with it.  The impact of the API break should be contained
    within E-D-S.
    
    This uses the new GWeakRef API in GLib 2.32 to ensure thread-safety.
    
    The libebackend shared object name has already been bumped for 3.5.1.

 addressbook/libedata-book/e-data-book-factory.c    |   12 ++-
 calendar/libedata-cal/e-data-cal-factory.c         |   14 ++--
 .../reference/libebackend/libebackend-sections.txt |    2 +-
 libebackend/e-data-factory.c                       |   86 ++++++++++++++------
 libebackend/e-data-factory.h                       |    2 +-
 5 files changed, 79 insertions(+), 37 deletions(-)
---
diff --git a/addressbook/libedata-book/e-data-book-factory.c b/addressbook/libedata-book/e-data-book-factory.c
index a900036..0f6ef70 100644
--- a/addressbook/libedata-book/e-data-book-factory.c
+++ b/addressbook/libedata-book/e-data-book-factory.c
@@ -93,9 +93,9 @@ e_data_book_factory_extract_proto_from_uri (const gchar *uri)
 }
 
 static EBackend *
-e_data_book_factory_get_backend (EDataBookFactory *factory,
-                                 ESource *source,
-                                 const gchar *uri)
+data_book_factory_ref_backend (EDataBookFactory *factory,
+                               ESource *source,
+                               const gchar *uri)
 {
 	EBackend *backend;
 	gchar *hash_key;
@@ -106,7 +106,7 @@ e_data_book_factory_get_backend (EDataBookFactory *factory,
 		return NULL;
 	}
 
-	backend = e_data_factory_get_backend (
+	backend = e_data_factory_ref_backend (
 		E_DATA_FACTORY (factory), hash_key, source);
 
 	g_free (hash_key);
@@ -226,7 +226,7 @@ impl_BookFactory_get_book (EGdbusBookFactory *object,
 		return TRUE;
 	}
 
-	backend = e_data_book_factory_get_backend (factory, source, uri);
+	backend = data_book_factory_ref_backend (factory, source, uri);
 
 	if (backend == NULL) {
 		g_free (uri);
@@ -276,6 +276,8 @@ impl_BookFactory_get_book (EGdbusBookFactory *object,
 		G_OBJECT (book), (GWeakNotify)
 		book_freed_cb, factory);
 
+	g_object_unref (backend);
+
 	/* Update the hash of open connections. */
 	g_mutex_lock (priv->connections_lock);
 	list = g_hash_table_lookup (priv->connections, sender);
diff --git a/calendar/libedata-cal/e-data-cal-factory.c b/calendar/libedata-cal/e-data-cal-factory.c
index bfe1696..9b1970f 100644
--- a/calendar/libedata-cal/e-data-cal-factory.c
+++ b/calendar/libedata-cal/e-data-cal-factory.c
@@ -102,10 +102,10 @@ e_data_cal_factory_extract_proto_from_uri (const gchar *uri)
 }
 
 static EBackend *
-e_data_cal_factory_get_backend (EDataCalFactory *factory,
-                                ESource *source,
-                                const gchar *uri,
-                                EDataCalObjType type)
+data_cal_factory_ref_backend (EDataCalFactory *factory,
+                              ESource *source,
+                              const gchar *uri,
+                              EDataCalObjType type)
 {
 	EBackend *backend;
 	gchar *protocol;
@@ -120,7 +120,7 @@ e_data_cal_factory_get_backend (EDataCalFactory *factory,
 	hash_key = g_strdup_printf (
 		"%s:%s", protocol, calobjtype_to_string (type));
 
-	backend = e_data_factory_get_backend (
+	backend = e_data_factory_ref_backend (
 		E_DATA_FACTORY (factory), hash_key, source);
 
 	g_free (hash_key);
@@ -243,7 +243,7 @@ impl_CalFactory_get_cal (EGdbusCalFactory *object,
 		return TRUE;
 	}
 
-	backend = e_data_cal_factory_get_backend (factory, source, uri, type);
+	backend = data_cal_factory_ref_backend (factory, source, uri, type);
 
 	if (backend == NULL) {
 		error = g_error_new (
@@ -269,6 +269,8 @@ impl_CalFactory_get_cal (EGdbusCalFactory *object,
 		G_OBJECT (calendar), (GWeakNotify)
 		calendar_freed_cb, factory);
 
+	g_object_unref (backend);
+
 	/* Update the hash of open connections. */
 	g_mutex_lock (priv->connections_lock);
 	list = g_hash_table_lookup (priv->connections, sender);
diff --git a/docs/reference/libebackend/libebackend-sections.txt b/docs/reference/libebackend/libebackend-sections.txt
index 7f6598b..bf5367f 100644
--- a/docs/reference/libebackend/libebackend-sections.txt
+++ b/docs/reference/libebackend/libebackend-sections.txt
@@ -42,7 +42,7 @@ e_backend_factory_get_type
 <FILE>e-data-factory</FILE>
 <TITLE>EDataFactory</TITLE>
 EDataFactory
-e_data_factory_get_backend
+e_data_factory_ref_backend
 <SUBSECTION Standard>
 E_DATA_FACTORY
 E_IS_DATA_FACTORY
diff --git a/libebackend/e-data-factory.c b/libebackend/e-data-factory.c
index 0d5be47..51b0310 100644
--- a/libebackend/e-data-factory.c
+++ b/libebackend/e-data-factory.c
@@ -40,7 +40,7 @@ struct _EDataFactoryPrivate {
 	 * and is read-only thereafter. */
 	GMutex *mutex;
 
-	/* ESource UID -> EBackend */
+	/* ESource UID -> GWeakRef (EBackend) */
 	GHashTable *backends;
 
 	/* Hash Key -> EBackendFactory */
@@ -50,20 +50,40 @@ struct _EDataFactoryPrivate {
 G_DEFINE_ABSTRACT_TYPE (
 	EDataFactory, e_data_factory, E_TYPE_DBUS_SERVER)
 
+static GWeakRef *
+data_factory_weak_ref_new (void)
+{
+	/* XXX GWeakRef documentation is a little confusing on when
+	 *     g_weak_ref_init() must be called.  The code just zero
+	 *     fills the struct, so it looks like g_weak_ref_init()
+	 *     is only needed when the GWeakRef is a local variable
+	 *     in a call stack frame.  The docs should be clarified. */
+	return g_slice_new0 (GWeakRef);
+}
+
 static void
-data_factory_last_client_gone_cb (EBackend *backend,
-                                  EDataFactory *factory)
+data_factory_weak_ref_free (GWeakRef *weak_ref)
 {
-	ESource *source;
-	const gchar *uid;
+	g_weak_ref_clear (weak_ref);
+	g_slice_free (GWeakRef, weak_ref);
+}
 
-	source = e_backend_get_source (backend);
-	uid = e_source_peek_uid (source);
-	g_return_if_fail (uid != NULL);
+static GWeakRef *
+data_factory_backends_lookup (EDataFactory *factory,
+                              const gchar *uid)
+{
+	GHashTable *backends;
+	GWeakRef *weak_ref;
 
-	g_mutex_lock (factory->priv->mutex);
-	g_hash_table_remove (factory->priv->backends, uid);
-	g_mutex_unlock (factory->priv->mutex);
+	backends = factory->priv->backends;
+	weak_ref = g_hash_table_lookup (backends, uid);
+
+	if (weak_ref == NULL) {
+		weak_ref = data_factory_weak_ref_new ();
+		g_hash_table_insert (backends, g_strdup (uid), weak_ref);
+	}
+
+	return weak_ref;
 }
 
 static void
@@ -182,7 +202,7 @@ e_data_factory_init (EDataFactory *factory)
 		(GHashFunc) g_str_hash,
 		(GEqualFunc) g_str_equal,
 		(GDestroyNotify) g_free,
-		(GDestroyNotify) g_object_unref);
+		(GDestroyNotify) data_factory_weak_ref_free);
 
 	factory->priv->backend_factories = g_hash_table_new_full (
 		(GHashFunc) g_str_hash,
@@ -191,12 +211,35 @@ e_data_factory_init (EDataFactory *factory)
 		(GDestroyNotify) g_object_unref);
 }
 
+/**
+ * e_data_factory_ref_backend:
+ * @factory: an #EDataFactory
+ * @hash_key: hash key for an #EBackendFactory
+ * @source: an #ESource
+ *
+ * Returns either a newly-created or existing #EBackend for #ESource.
+ * The returned #EBackend is referenced for thread-safety and must be
+ * unreferenced with g_object_unref() when finished with it.
+ *
+ * The @factory retains a weak reference to @backend so it can return the
+ * same instance while @backend is in use.  When the last strong reference
+ * to @backend is dropped, @factory will lose its weak reference and will
+ * create a new #EBackend instance the next time the same @hash_key and
+ * @source are requested.
+ *
+ * If no suitable #EBackendFactory exists, the function returns %NULL.
+ *
+ * Returns: an #EBackend for @source, or %NULL
+ *
+ * Since: 3.6
+ **/
 EBackend *
-e_data_factory_get_backend (EDataFactory *factory,
+e_data_factory_ref_backend (EDataFactory *factory,
                             const gchar *hash_key,
                             ESource *source)
 {
 	EBackendFactory *backend_factory;
+	GWeakRef *weak_ref;
 	EBackend *backend;
 	const gchar *uid;
 
@@ -209,8 +252,11 @@ e_data_factory_get_backend (EDataFactory *factory,
 
 	g_mutex_lock (factory->priv->mutex);
 
+	/* The weak ref is already inserted in the hash table. */
+	weak_ref = data_factory_backends_lookup (factory, uid);
+
 	/* Check if we already have a backend for the given source. */
-	backend = g_hash_table_lookup (factory->priv->backends, uid);
+	backend = g_weak_ref_get (weak_ref);
 
 	if (backend != NULL)
 		goto exit;
@@ -225,16 +271,8 @@ e_data_factory_get_backend (EDataFactory *factory,
 	/* Create a new backend for the given source and store it. */
 	backend = e_backend_factory_new_backend (backend_factory, source);
 
-	if (backend == NULL)
-		goto exit;
-
-	g_signal_connect (
-		backend, "last-client-gone",
-		G_CALLBACK (data_factory_last_client_gone_cb), factory);
-
-	g_hash_table_insert (
-		factory->priv->backends,
-		g_strdup (uid), backend);
+	/* This still does the right thing if backend is NULL. */
+	g_weak_ref_set (weak_ref, backend);
 
 exit:
 	g_mutex_unlock (factory->priv->mutex);
diff --git a/libebackend/e-data-factory.h b/libebackend/e-data-factory.h
index 3788789..be6705f 100644
--- a/libebackend/e-data-factory.h
+++ b/libebackend/e-data-factory.h
@@ -69,7 +69,7 @@ struct _EDataFactoryClass {
 };
 
 GType		e_data_factory_get_type		(void) G_GNUC_CONST;
-EBackend *	e_data_factory_get_backend	(EDataFactory *factory,
+EBackend *	e_data_factory_ref_backend	(EDataFactory *factory,
 						 const gchar *hash_key,
 						 ESource *source);
 



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