[next] telepathy-glib: client-factory: keep a cache of TpProtocol objects

Guillaume Desmottes gdesmott at kemper.freedesktop.org
Mon Mar 17 07:25:42 PDT 2014


Module: telepathy-glib
Branch: next
Commit: 2e62efe61bd64d202b5012b9653a7e7b0b518eb9
URL:    http://cgit.freedesktop.org/telepathy/telepathy-glib/commit/?id=2e62efe61bd64d202b5012b9653a7e7b0b518eb9

Author: Guillaume Desmottes <guillaume.desmottes at collabora.co.uk>
Date:   Thu Mar  6 16:28:11 2014 +0100

client-factory: keep a cache of TpProtocol objects

---

 telepathy-glib/client-factory.c |   61 +++++++++++++++++++++++++++++++++++++--
 tests/dbus/protocol-objects.c   |   28 ++++++++++++++++++
 2 files changed, 87 insertions(+), 2 deletions(-)

diff --git a/telepathy-glib/client-factory.c b/telepathy-glib/client-factory.c
index 1e86de9..f3e14a1 100644
--- a/telepathy-glib/client-factory.c
+++ b/telepathy-glib/client-factory.c
@@ -135,6 +135,10 @@ struct _TpClientFactoryPrivate
   TpDBusDaemon *dbus;
   /* Owned object-path -> weakref to TpProxy */
   GHashTable *proxy_cache;
+  /* TpProtocol aren't requested using their object path so we concat their CM
+   * and name to identifiy them.
+   * Owned "cm-name protocol-name" -> weakref to TpProtocol */
+  GHashTable *protocols_cache;
   GArray *desired_account_features;
   GArray *desired_connection_features;
   GArray *desired_channel_features;
@@ -330,6 +334,7 @@ tp_client_factory_finalize (GObject *object)
 
   g_clear_object (&self->priv->dbus);
   tp_clear_pointer (&self->priv->proxy_cache, g_hash_table_unref);
+  tp_clear_pointer (&self->priv->protocols_cache, g_hash_table_unref);
   tp_clear_pointer (&self->priv->desired_account_features, g_array_unref);
   tp_clear_pointer (&self->priv->desired_connection_features, g_array_unref);
   tp_clear_pointer (&self->priv->desired_channel_features, g_array_unref);
@@ -347,6 +352,8 @@ tp_client_factory_init (TpClientFactory *self)
       TpClientFactoryPrivate);
 
   self->priv->proxy_cache = g_hash_table_new (g_str_hash, g_str_equal);
+  self->priv->protocols_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
+      g_free, NULL);
 
   self->priv->desired_account_features = g_array_new (TRUE, FALSE,
       sizeof (GQuark));
@@ -1275,6 +1282,27 @@ _tp_client_factory_ensure_channel_dispatch_operation (
   return dispatch;
 }
 
+static void
+protocol_destroyed_cb (gpointer data,
+    GObject *protocol)
+{
+  /* We can't compute the key as @protocol has been destroyed so look for it
+   * in the hash table. */
+  TpClientFactory *self = data;
+  GHashTableIter iter;
+  gpointer p;
+
+  g_hash_table_iter_init (&iter, self->priv->protocols_cache);
+  while (g_hash_table_iter_next (&iter, NULL, &p))
+    {
+      if (p == protocol)
+        {
+          g_hash_table_iter_remove (&iter);
+          return;
+        }
+    }
+}
+
 /**
  * tp_client_factory_ensure_protocol:
  * @self: a #TpClientFactory
@@ -1308,8 +1336,37 @@ tp_client_factory_ensure_protocol (TpClientFactory *self,
     GVariant *immutable_properties,
     GError **error)
 {
+  TpProtocol *protocol;
+  gchar *key;
+
   g_return_val_if_fail (TP_IS_CLIENT_FACTORY (self), NULL);
 
-  return TP_CLIENT_FACTORY_GET_CLASS (self)->create_protocol (self,
-      cm_name, protocol_name, immutable_properties, error);
+  if (immutable_properties == NULL)
+    immutable_properties = g_variant_new ("a{sv}", NULL);
+
+  g_variant_ref_sink (immutable_properties);
+
+  key = g_strdup_printf ("%s %s", cm_name, protocol_name);
+
+  protocol = g_hash_table_lookup (self->priv->protocols_cache, key);
+  if (protocol != NULL)
+    {
+      g_object_ref (protocol);
+
+      g_free (key);
+    }
+  else
+    {
+      protocol = TP_CLIENT_FACTORY_GET_CLASS (self)->create_protocol (
+          self, cm_name, protocol_name, immutable_properties, error);
+
+      g_object_weak_ref (G_OBJECT (protocol), protocol_destroyed_cb, self);
+
+      /* pass ownership of 'key' to the hash table */
+      g_hash_table_insert (self->priv->protocols_cache, key, protocol);
+    }
+
+  g_variant_unref (immutable_properties);
+
+  return protocol;
 }
diff --git a/tests/dbus/protocol-objects.c b/tests/dbus/protocol-objects.c
index bf1c7dd..139f7d5 100644
--- a/tests/dbus/protocol-objects.c
+++ b/tests/dbus/protocol-objects.c
@@ -615,6 +615,32 @@ test_id (Test *test,
   g_clear_error (&test->error);
 }
 
+static void
+test_factory (Test *test,
+    gconstpointer data G_GNUC_UNUSED)
+{
+  TpProtocol *p1, *p2, *p3;
+
+  p1 = tp_client_factory_ensure_protocol (test->factory,
+      "example_echo_2", "example", NULL, NULL);
+  g_assert (TP_IS_PROTOCOL (p1));
+
+  p2 = tp_client_factory_ensure_protocol (test->factory,
+      "example_echo_2", "example", NULL, NULL);
+  g_assert (p1 == p2);
+
+  g_object_unref (p1);
+  g_object_unref (p2);
+
+  p3 = tp_client_factory_ensure_protocol (test->factory,
+      "example_echo_2", "example", NULL, NULL);
+  g_assert (TP_IS_PROTOCOL (p3));
+  /* the object has been removed from the cache */
+  g_assert (p3 != p1);
+
+  g_object_unref (p3);
+}
+
 int
 main (int argc,
       char **argv)
@@ -638,6 +664,8 @@ main (int argc,
       test_normalize, teardown);
   g_test_add ("/protocol-objects/id", Test, NULL, setup,
       test_id, teardown);
+  g_test_add ("/protocol-objects/factory", Test, NULL, setup,
+      test_factory, teardown);
 
   return tp_tests_run_with_bus ();
 }



More information about the telepathy-commits mailing list