mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-03-03 22:52:09 +01:00
GDBus: Add mechanism to make lookup on interfaces constant-time
This is used both on the service- and client-side and is currently O(n). Signed-off-by: David Zeuthen <davidz@redhat.com>
This commit is contained in:
parent
5aa8f135c7
commit
5bcf54b29c
@ -2613,6 +2613,8 @@ g_dbus_annotation_info_lookup
|
|||||||
g_dbus_interface_info_lookup_method
|
g_dbus_interface_info_lookup_method
|
||||||
g_dbus_interface_info_lookup_signal
|
g_dbus_interface_info_lookup_signal
|
||||||
g_dbus_interface_info_lookup_property
|
g_dbus_interface_info_lookup_property
|
||||||
|
g_dbus_interface_info_cache_build
|
||||||
|
g_dbus_interface_info_cache_release
|
||||||
g_dbus_interface_info_generate_xml
|
g_dbus_interface_info_generate_xml
|
||||||
g_dbus_node_info_new_for_xml
|
g_dbus_node_info_new_for_xml
|
||||||
g_dbus_node_info_lookup_interface
|
g_dbus_node_info_lookup_interface
|
||||||
|
@ -1868,6 +1868,37 @@ g_dbus_annotation_info_lookup (GDBusAnnotationInfo **annotations,
|
|||||||
|
|
||||||
/* ---------------------------------------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
G_LOCK_DEFINE_STATIC (info_cache_lock);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
gint use_count;
|
||||||
|
|
||||||
|
/* gchar* -> GDBusMethodInfo* */
|
||||||
|
GHashTable *method_name_to_data;
|
||||||
|
|
||||||
|
/* gchar* -> GDBusMethodInfo* */
|
||||||
|
GHashTable *signal_name_to_data;
|
||||||
|
|
||||||
|
/* gchar* -> GDBusMethodInfo* */
|
||||||
|
GHashTable *property_name_to_data;
|
||||||
|
} InfoCacheEntry;
|
||||||
|
|
||||||
|
static void
|
||||||
|
info_cache_free (InfoCacheEntry *cache)
|
||||||
|
{
|
||||||
|
g_assert (cache->use_count == 0);
|
||||||
|
g_hash_table_unref (cache->method_name_to_data);
|
||||||
|
g_hash_table_unref (cache->signal_name_to_data);
|
||||||
|
g_hash_table_unref (cache->property_name_to_data);
|
||||||
|
g_slice_free (InfoCacheEntry, cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* maps from GDBusInterfaceInfo* to InfoCacheEntry* */
|
||||||
|
static GHashTable *info_cache = NULL;
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* g_dbus_interface_info_lookup_method:
|
* g_dbus_interface_info_lookup_method:
|
||||||
* @info: A #GDBusInterfaceInfo.
|
* @info: A #GDBusInterfaceInfo.
|
||||||
@ -1875,7 +1906,8 @@ g_dbus_annotation_info_lookup (GDBusAnnotationInfo **annotations,
|
|||||||
*
|
*
|
||||||
* Looks up information about a method.
|
* Looks up information about a method.
|
||||||
*
|
*
|
||||||
* This cost of this function is O(n) in number of methods.
|
* This cost of this function is O(n) in number of methods unless
|
||||||
|
* g_dbus_interface_info_cache_build() has been used on @info.
|
||||||
*
|
*
|
||||||
* Returns: A #GDBusMethodInfo or %NULL if not found. Do not free, it is owned by @info.
|
* Returns: A #GDBusMethodInfo or %NULL if not found. Do not free, it is owned by @info.
|
||||||
*
|
*
|
||||||
@ -1888,6 +1920,20 @@ g_dbus_interface_info_lookup_method (GDBusInterfaceInfo *info,
|
|||||||
guint n;
|
guint n;
|
||||||
GDBusMethodInfo *result;
|
GDBusMethodInfo *result;
|
||||||
|
|
||||||
|
G_LOCK (info_cache_lock);
|
||||||
|
if (G_LIKELY (info_cache != NULL))
|
||||||
|
{
|
||||||
|
InfoCacheEntry *cache;
|
||||||
|
cache = g_hash_table_lookup (info_cache, info);
|
||||||
|
if (G_LIKELY (cache != NULL))
|
||||||
|
{
|
||||||
|
result = g_hash_table_lookup (cache->method_name_to_data, name);
|
||||||
|
G_UNLOCK (info_cache_lock);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
G_UNLOCK (info_cache_lock);
|
||||||
|
|
||||||
for (n = 0; info->methods != NULL && info->methods[n] != NULL; n++)
|
for (n = 0; info->methods != NULL && info->methods[n] != NULL; n++)
|
||||||
{
|
{
|
||||||
GDBusMethodInfo *i = info->methods[n];
|
GDBusMethodInfo *i = info->methods[n];
|
||||||
@ -1914,7 +1960,8 @@ g_dbus_interface_info_lookup_method (GDBusInterfaceInfo *info,
|
|||||||
*
|
*
|
||||||
* Looks up information about a signal.
|
* Looks up information about a signal.
|
||||||
*
|
*
|
||||||
* This cost of this function is O(n) in number of signals.
|
* This cost of this function is O(n) in number of signals unless
|
||||||
|
* g_dbus_interface_info_cache_build() has been used on @info.
|
||||||
*
|
*
|
||||||
* Returns: A #GDBusSignalInfo or %NULL if not found. Do not free, it is owned by @info.
|
* Returns: A #GDBusSignalInfo or %NULL if not found. Do not free, it is owned by @info.
|
||||||
*
|
*
|
||||||
@ -1927,6 +1974,20 @@ g_dbus_interface_info_lookup_signal (GDBusInterfaceInfo *info,
|
|||||||
guint n;
|
guint n;
|
||||||
GDBusSignalInfo *result;
|
GDBusSignalInfo *result;
|
||||||
|
|
||||||
|
G_LOCK (info_cache_lock);
|
||||||
|
if (G_LIKELY (info_cache != NULL))
|
||||||
|
{
|
||||||
|
InfoCacheEntry *cache;
|
||||||
|
cache = g_hash_table_lookup (info_cache, info);
|
||||||
|
if (G_LIKELY (cache != NULL))
|
||||||
|
{
|
||||||
|
result = g_hash_table_lookup (cache->signal_name_to_data, name);
|
||||||
|
G_UNLOCK (info_cache_lock);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
G_UNLOCK (info_cache_lock);
|
||||||
|
|
||||||
for (n = 0; info->signals != NULL && info->signals[n] != NULL; n++)
|
for (n = 0; info->signals != NULL && info->signals[n] != NULL; n++)
|
||||||
{
|
{
|
||||||
GDBusSignalInfo *i = info->signals[n];
|
GDBusSignalInfo *i = info->signals[n];
|
||||||
@ -1953,7 +2014,8 @@ g_dbus_interface_info_lookup_signal (GDBusInterfaceInfo *info,
|
|||||||
*
|
*
|
||||||
* Looks up information about a property.
|
* Looks up information about a property.
|
||||||
*
|
*
|
||||||
* This cost of this function is O(n) in number of properties.
|
* This cost of this function is O(n) in number of properties unless
|
||||||
|
* g_dbus_interface_info_cache_build() has been used on @info.
|
||||||
*
|
*
|
||||||
* Returns: A #GDBusPropertyInfo or %NULL if not found. Do not free, it is owned by @info.
|
* Returns: A #GDBusPropertyInfo or %NULL if not found. Do not free, it is owned by @info.
|
||||||
*
|
*
|
||||||
@ -1966,6 +2028,20 @@ g_dbus_interface_info_lookup_property (GDBusInterfaceInfo *info,
|
|||||||
guint n;
|
guint n;
|
||||||
GDBusPropertyInfo *result;
|
GDBusPropertyInfo *result;
|
||||||
|
|
||||||
|
G_LOCK (info_cache_lock);
|
||||||
|
if (G_LIKELY (info_cache != NULL))
|
||||||
|
{
|
||||||
|
InfoCacheEntry *cache;
|
||||||
|
cache = g_hash_table_lookup (info_cache, info);
|
||||||
|
if (G_LIKELY (cache != NULL))
|
||||||
|
{
|
||||||
|
result = g_hash_table_lookup (cache->property_name_to_data, name);
|
||||||
|
G_UNLOCK (info_cache_lock);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
G_UNLOCK (info_cache_lock);
|
||||||
|
|
||||||
for (n = 0; info->properties != NULL && info->properties[n] != NULL; n++)
|
for (n = 0; info->properties != NULL && info->properties[n] != NULL; n++)
|
||||||
{
|
{
|
||||||
GDBusPropertyInfo *i = info->properties[n];
|
GDBusPropertyInfo *i = info->properties[n];
|
||||||
@ -1983,6 +2059,95 @@ g_dbus_interface_info_lookup_property (GDBusInterfaceInfo *info,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_dbus_interface_info_cache_build:
|
||||||
|
* @info: A #GDBusInterfaceInfo.
|
||||||
|
*
|
||||||
|
* Builds a lookup-cache to speed up
|
||||||
|
* g_dbus_interface_info_lookup_method(),
|
||||||
|
* g_dbus_interface_info_lookup_signal() and
|
||||||
|
* g_dbus_interface_info_lookup_property().
|
||||||
|
*
|
||||||
|
* If this has already been called with @info, the existing cache is
|
||||||
|
* used and its use count is increased.
|
||||||
|
*
|
||||||
|
* Note that @info cannot be modified until
|
||||||
|
* g_dbus_interface_info_cache_release() is called.
|
||||||
|
*
|
||||||
|
* Since: 2.30
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
g_dbus_interface_info_cache_build (GDBusInterfaceInfo *info)
|
||||||
|
{
|
||||||
|
InfoCacheEntry *cache;
|
||||||
|
guint n;
|
||||||
|
|
||||||
|
G_LOCK (info_cache_lock);
|
||||||
|
if (info_cache == NULL)
|
||||||
|
info_cache = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) info_cache_free);
|
||||||
|
cache = g_hash_table_lookup (info_cache, info);
|
||||||
|
if (cache != NULL)
|
||||||
|
{
|
||||||
|
cache->use_count += 1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
cache = g_slice_new0 (InfoCacheEntry);
|
||||||
|
cache->use_count = 1;
|
||||||
|
cache->method_name_to_data = g_hash_table_new (g_str_hash, g_str_equal);
|
||||||
|
cache->signal_name_to_data = g_hash_table_new (g_str_hash, g_str_equal);
|
||||||
|
cache->property_name_to_data = g_hash_table_new (g_str_hash, g_str_equal);
|
||||||
|
for (n = 0; info->methods != NULL && info->methods[n] != NULL; n++)
|
||||||
|
g_hash_table_insert (cache->method_name_to_data, info->methods[n]->name, info->methods[n]);
|
||||||
|
for (n = 0; info->signals != NULL && info->signals[n] != NULL; n++)
|
||||||
|
g_hash_table_insert (cache->signal_name_to_data, info->signals[n]->name, info->signals[n]);
|
||||||
|
for (n = 0; info->properties != NULL && info->properties[n] != NULL; n++)
|
||||||
|
g_hash_table_insert (cache->property_name_to_data, info->properties[n]->name, info->properties[n]);
|
||||||
|
g_hash_table_insert (info_cache, info, cache);
|
||||||
|
out:
|
||||||
|
G_UNLOCK (info_cache_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_dbus_interface_info_cache_release:
|
||||||
|
* @info: A GDBusInterfaceInfo
|
||||||
|
*
|
||||||
|
* Decrements the usage count for the cache for @info built by
|
||||||
|
* g_dbus_interface_info_cache_build() (if any) and frees the
|
||||||
|
* resources used by the cache if the usage count drops to zero.
|
||||||
|
*
|
||||||
|
* Since: 2.30
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
g_dbus_interface_info_cache_release (GDBusInterfaceInfo *info)
|
||||||
|
{
|
||||||
|
InfoCacheEntry *cache;
|
||||||
|
|
||||||
|
G_LOCK (info_cache_lock);
|
||||||
|
if (G_UNLIKELY (info_cache == NULL))
|
||||||
|
{
|
||||||
|
g_warning ("%s called for interface %s but there is no cache", info->name, G_STRFUNC);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache = g_hash_table_lookup (info_cache, info);
|
||||||
|
if (G_UNLIKELY (cache == NULL))
|
||||||
|
{
|
||||||
|
g_warning ("%s called for interface %s but there is no cache entry", info->name, G_STRFUNC);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
cache->use_count -= 1;
|
||||||
|
if (cache->use_count == 0)
|
||||||
|
{
|
||||||
|
g_hash_table_remove (info_cache, info);
|
||||||
|
/* could nuke info_cache itself if empty */
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
G_UNLOCK (info_cache_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ---------------------------------------------------------------------------------------------------- */
|
/* ---------------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -182,6 +182,9 @@ GDBusSignalInfo *g_dbus_interface_info_lookup_signal (GDBusInterfaceInfo
|
|||||||
const gchar *name);
|
const gchar *name);
|
||||||
GDBusPropertyInfo *g_dbus_interface_info_lookup_property (GDBusInterfaceInfo *info,
|
GDBusPropertyInfo *g_dbus_interface_info_lookup_property (GDBusInterfaceInfo *info,
|
||||||
const gchar *name);
|
const gchar *name);
|
||||||
|
void g_dbus_interface_info_cache_build (GDBusInterfaceInfo *info);
|
||||||
|
void g_dbus_interface_info_cache_release (GDBusInterfaceInfo *info);
|
||||||
|
|
||||||
void g_dbus_interface_info_generate_xml (GDBusInterfaceInfo *info,
|
void g_dbus_interface_info_generate_xml (GDBusInterfaceInfo *info,
|
||||||
guint indent,
|
guint indent,
|
||||||
GString *string_builder);
|
GString *string_builder);
|
||||||
|
@ -1725,6 +1725,8 @@ g_dbus_interface_info_generate_xml
|
|||||||
g_dbus_interface_info_lookup_method
|
g_dbus_interface_info_lookup_method
|
||||||
g_dbus_interface_info_lookup_property
|
g_dbus_interface_info_lookup_property
|
||||||
g_dbus_interface_info_lookup_signal
|
g_dbus_interface_info_lookup_signal
|
||||||
|
g_dbus_interface_info_cache_build
|
||||||
|
g_dbus_interface_info_cache_release
|
||||||
g_dbus_node_info_new_for_xml
|
g_dbus_node_info_new_for_xml
|
||||||
g_dbus_node_info_generate_xml
|
g_dbus_node_info_generate_xml
|
||||||
g_dbus_node_info_lookup_interface
|
g_dbus_node_info_lookup_interface
|
||||||
|
Loading…
x
Reference in New Issue
Block a user