[evolution-data-server] EDataFactory: Keep only weak references to backends.
- From: Matthew Barnes <mbarnes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] EDataFactory: Keep only weak references to backends.
- Date: Mon, 16 Apr 2012 16:05:41 +0000 (UTC)
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]