From 632a5c13072312015226c408ddb3d4eb478abe6f Mon Sep 17 00:00:00 2001 From: Daiki Ueno Date: Fri, 12 Jul 2013 18:39:54 +0900 Subject: [PATCH] registry: use binary format instead of XML for cache Currently the registry cache is in the XML format, that may cause unnecessary parsing overhead on ibus-daemon startup. This patch changes the format to GVariant based binary representation. BUG= R=takao.fujiwara1@gmail.com Review URL: https://codereview.appspot.com/9963043 --- src/ibusregistry.c | 259 ++++++++++++++++++++++++++++++++++++++--------------- src/ibusregistry.h | 4 +- src/ibusshare.c | 2 + tools/main.vala | 3 +- 4 files changed, 194 insertions(+), 74 deletions(-) diff --git a/src/ibusregistry.c b/src/ibusregistry.c index d239955..c76fae7 100644 --- a/src/ibusregistry.c +++ b/src/ibusregistry.c @@ -28,6 +28,9 @@ #include "ibusmarshalers.h" #include "ibusregistry.h" +#define IBUS_CACHE_MAGIC 0x49425553 /* "IBUS" */ +#define IBUS_CACHE_VERSION 0x00010502 + enum { CHANGED, LAST_SIGNAL, @@ -57,17 +60,30 @@ struct _IBusRegistryPrivate { /* functions prototype */ static void ibus_registry_destroy (IBusRegistry *registry); static void ibus_registry_remove_all (IBusRegistry *registry); +static gboolean ibus_registry_serialize (IBusRegistry *registry, + GVariantBuilder *builder); +static gint ibus_registry_deserialize (IBusRegistry *registry, + GVariant *variant); +static gboolean ibus_registry_copy (IBusRegistry *dest, + const IBusRegistry *src); -G_DEFINE_TYPE (IBusRegistry, ibus_registry, IBUS_TYPE_OBJECT) +G_DEFINE_TYPE (IBusRegistry, ibus_registry, IBUS_TYPE_SERIALIZABLE) static void ibus_registry_class_init (IBusRegistryClass *class) { GObjectClass *gobject_class = G_OBJECT_CLASS (class); IBusObjectClass *ibus_object_class = IBUS_OBJECT_CLASS (class); + IBusSerializableClass *serializable_class = IBUS_SERIALIZABLE_CLASS (class); ibus_object_class->destroy = (IBusObjectDestroyFunc) ibus_registry_destroy; + serializable_class->serialize = + (IBusSerializableSerializeFunc) ibus_registry_serialize; + serializable_class->deserialize = + (IBusSerializableDeserializeFunc) ibus_registry_deserialize; + serializable_class->copy = (IBusSerializableCopyFunc) ibus_registry_copy; + g_type_class_add_private (class, sizeof (IBusRegistryPrivate)); /* install signals */ @@ -124,6 +140,91 @@ ibus_registry_destroy (IBusRegistry *registry) destroy (IBUS_OBJECT (registry)); } +static gboolean +ibus_registry_serialize (IBusRegistry *registry, + GVariantBuilder *builder) +{ + gboolean retval; + + retval = IBUS_SERIALIZABLE_CLASS (ibus_registry_parent_class)-> + serialize ((IBusSerializable *)registry, builder); + g_return_val_if_fail (retval, FALSE); + + GList *p; + GVariantBuilder *array; + + array = g_variant_builder_new (G_VARIANT_TYPE ("av")); + for (p = registry->priv->observed_paths; p != NULL; p = p->next) { + IBusSerializable *serializable = (IBusSerializable *) p->data; + g_variant_builder_add (array, + "v", + ibus_serializable_serialize (serializable)); + } + g_variant_builder_add (builder, "av", array); + g_variant_builder_unref (array); + + array = g_variant_builder_new (G_VARIANT_TYPE ("av")); + for (p = registry->priv->components; p != NULL; p = p->next) { + IBusSerializable *serializable = (IBusSerializable *) p->data; + g_variant_builder_add (array, + "v", + ibus_serializable_serialize (serializable)); + } + g_variant_builder_add (builder, "av", array); + g_variant_builder_unref (array); + + return TRUE; +} + +static gint +ibus_registry_deserialize (IBusRegistry *registry, + GVariant *variant) +{ + GVariant *var; + GVariantIter *iter; + gint retval; + + retval = IBUS_SERIALIZABLE_CLASS (ibus_registry_parent_class)-> + deserialize ((IBusSerializable *)registry, variant); + g_return_val_if_fail (retval, 0); + + g_variant_get_child (variant, retval++, "av", &iter); + while (g_variant_iter_loop (iter, "v", &var)) { + IBusSerializable *serializable = ibus_serializable_deserialize (var); + registry->priv->observed_paths = + g_list_append (registry->priv->observed_paths, + IBUS_OBSERVED_PATH (serializable)); + } + g_variant_iter_free (iter); + + g_variant_get_child (variant, retval++, "av", &iter); + while (g_variant_iter_loop (iter, "v", &var)) { + IBusSerializable *serializable = ibus_serializable_deserialize (var); + registry->priv->components = + g_list_append (registry->priv->components, + IBUS_COMPONENT (serializable)); + } + g_variant_iter_free (iter); + + return retval; +} + +static gboolean +ibus_registry_copy (IBusRegistry *dest, + const IBusRegistry *src) +{ + gboolean retval; + + retval = IBUS_SERIALIZABLE_CLASS (ibus_registry_parent_class)-> + copy ((IBusSerializable *)dest, (IBusSerializable *)src); + g_return_val_if_fail (retval, FALSE); + + dest->priv->components = g_list_copy (src->priv->components); + dest->priv->observed_paths = g_list_copy (src->priv->observed_paths); + + return TRUE; +} + /** * ibus_registry_remove_all: * @@ -182,7 +283,8 @@ ibus_registry_load (IBusRegistry *registry) } gboolean -ibus_registry_load_cache (IBusRegistry *registry, gboolean is_user) +ibus_registry_load_cache (IBusRegistry *registry, + gboolean is_user) { gchar *filename; gboolean retval; @@ -191,10 +293,10 @@ ibus_registry_load_cache (IBusRegistry *registry, gboolean is_user) if (is_user) { filename = g_build_filename (g_get_user_cache_dir (), - "ibus", "bus", "registry.xml", NULL); + "ibus", "bus", "registry", NULL); } else { filename = g_build_filename (IBUS_CACHE_DIR, - "bus", "registry.xml", NULL); + "bus", "registry", NULL); } retval = ibus_registry_load_cache_file (registry, filename); @@ -204,60 +306,63 @@ ibus_registry_load_cache (IBusRegistry *registry, gboolean is_user) } gboolean -ibus_registry_load_cache_file (IBusRegistry *registry, const gchar *filename) +ibus_registry_load_cache_file (IBusRegistry *registry, + const gchar *filename) { - XMLNode *node; - GList *p; + gchar *contents, *p; + gsize length; + GVariant *variant; + GError *error; g_assert (IBUS_IS_REGISTRY (registry)); g_assert (filename != NULL); - node = ibus_xml_parse_file (filename); + if (!g_file_test (filename, G_FILE_TEST_EXISTS)) + return FALSE; - if (node == NULL) { + error = NULL; + if (!g_file_get_contents (filename, &contents, &length, &error)) { + g_warning ("cannot read %s: %s", filename, error->message); + g_error_free (error); return FALSE; } - if (g_strcmp0 (node->name, "ibus-registry") != 0) { - ibus_xml_free (node); + p = contents; + + /* read file header including magic and version */ + if (length < 8) { + g_free (contents); return FALSE; } - for (p = node->sub_nodes; p != NULL; p = p->next) { - XMLNode *sub_node = (XMLNode *) p->data; - - if (g_strcmp0 (sub_node->name, "observed-paths") == 0) { - GList *pp; - for (pp = sub_node->sub_nodes; pp != NULL; pp = pp->next) { - IBusObservedPath *path; - path = ibus_observed_path_new_from_xml_node (pp->data, FALSE); - if (path) { - g_object_ref_sink (path); - registry->priv->observed_paths = - g_list_append (registry->priv->observed_paths, - path); - } - } - continue; - } - if (g_strcmp0 (sub_node->name, "components") == 0) { - GList *pp; - for (pp = sub_node->sub_nodes; pp != NULL; pp = pp->next) { - IBusComponent *component; - component = ibus_component_new_from_xml_node (pp->data); - if (component) { - g_object_ref_sink (component); - registry->priv->components = - g_list_append (registry->priv->components, component); - } - } + if (GUINT32_FROM_BE (*(guint32 *) p) != IBUS_CACHE_MAGIC) { + g_free (contents); + return FALSE; + } + p += 4; - continue; - } - g_warning ("Unknown element <%s>", sub_node->name); + if (GUINT32_FROM_BE (*(guint32 *) p) != IBUS_CACHE_VERSION) { + g_free (contents); + return FALSE; + } + p += 4; + + /* read serialized IBusRegistry */ + variant = g_variant_new_from_data (G_VARIANT_TYPE ("(sa{sv}avav)"), + p, + length - (p - contents), + FALSE, + (GDestroyNotify) g_free, + NULL); + if (variant == NULL) { + g_free (contents); + return FALSE; } - ibus_xml_free (node); + ibus_registry_deserialize (registry, variant); + g_variant_unref (variant); + g_free (contents); + return TRUE; } @@ -283,7 +388,8 @@ ibus_registry_check_modification (IBusRegistry *registry) } gboolean -ibus_registry_save_cache (IBusRegistry *registry, gboolean is_user) +ibus_registry_save_cache (IBusRegistry *registry, + gboolean is_user) { gchar *filename; gboolean retval; @@ -292,10 +398,10 @@ ibus_registry_save_cache (IBusRegistry *registry, gboolean is_user) if (is_user) { filename = g_build_filename (g_get_user_cache_dir (), - "ibus", "bus", "registry.xml", NULL); + "ibus", "bus", "registry", NULL); } else { filename = g_build_filename (IBUS_CACHE_DIR, - "bus", "registry.xml", NULL); + "bus", "registry", NULL); } retval = ibus_registry_save_cache_file (registry, filename); @@ -305,14 +411,16 @@ ibus_registry_save_cache (IBusRegistry *registry, gboolean is_user) } gboolean -ibus_registry_save_cache_file (IBusRegistry *registry, const gchar *filename) +ibus_registry_save_cache_file (IBusRegistry *registry, + const gchar *filename) { gchar *cachedir; - const gchar *user_cachedir; - gboolean is_user = TRUE; - GString *output; - FILE *pf; - size_t items = 0; + GVariant *variant; + gchar *contents, *p; + gsize length; + gboolean retval; + guint32 intval; + GError *error; g_assert (IBUS_IS_REGISTRY (registry)); g_assert (filename != NULL); @@ -320,29 +428,40 @@ ibus_registry_save_cache_file (IBusRegistry *registry, const gchar *filename) cachedir = g_path_get_dirname (filename); g_mkdir_with_parents (cachedir, 0775); g_free (cachedir); - pf = g_fopen (filename, "w"); - if (pf == NULL) { - g_warning ("create %s failed", filename); - return FALSE; - } + variant = ibus_serializable_serialize (IBUS_SERIALIZABLE (registry)); + length = 8 + g_variant_get_size (variant); + p = contents = g_slice_alloc (length); + + /* write file header */ + intval = GUINT32_TO_BE (IBUS_CACHE_MAGIC); + memcpy (p, (gchar *) &intval, 4); + p += 4; - output = g_string_new (""); + intval = GUINT32_TO_BE (IBUS_CACHE_VERSION); + memcpy (p, (gchar *) &intval, 4); + p += 4; - ibus_registry_output (registry, output, 1); + /* write serialized IBusRegistry */ + g_variant_store (variant, p); - items = fwrite (output->str, output->len, 1, pf); - g_string_free (output, TRUE); - fclose (pf); + error = NULL; + retval = g_file_set_contents (filename, contents, length, &error); - user_cachedir = g_get_user_cache_dir (); - is_user = (strncmp (user_cachedir, filename, strlen (user_cachedir)) == 0); + g_variant_unref (variant); + g_slice_free1 (length, contents); - if (!is_user) { + if (!retval) { + g_warning ("cannot write %s: %s", filename, error->message); + g_error_free (error); + return FALSE; + } + + if (g_str_has_prefix (filename, g_get_user_cache_dir ())) { g_chmod (filename, 0644); } - return (items == 1 ? TRUE : FALSE); + return TRUE; } #define g_string_append_indent(string, indent) \ @@ -354,7 +473,9 @@ ibus_registry_save_cache_file (IBusRegistry *registry, const gchar *filename) } void -ibus_registry_output (IBusRegistry *registry, GString *output, int indent) +ibus_registry_output (IBusRegistry *registry, + GString *output, + int indent) { GList *p; @@ -362,10 +483,6 @@ ibus_registry_output (IBusRegistry *registry, GString *output, int indent) g_return_if_fail (output != NULL); g_string_append (output, "\n"); - g_string_append (output, "\n"); g_string_append (output, "\n"); if (registry->priv->observed_paths) { diff --git a/src/ibusregistry.h b/src/ibusregistry.h index 288dc07..3369447 100644 --- a/src/ibusregistry.h +++ b/src/ibusregistry.h @@ -74,14 +74,14 @@ typedef struct _IBusRegistryClass IBusRegistryClass; struct _IBusRegistry { /* instance members */ /*< private >*/ - IBusObject parent; + IBusSerializable parent; IBusRegistryPrivate *priv; }; struct _IBusRegistryClass { /* class members */ /*< private >*/ - IBusObjectClass parent; + IBusSerializableClass parent; }; GType ibus_registry_get_type (void); diff --git a/src/ibusshare.c b/src/ibusshare.c index 79c2e08..20a144f 100644 --- a/src/ibusshare.c +++ b/src/ibusshare.c @@ -285,6 +285,8 @@ ibus_init (void) IBUS_TYPE_LOOKUP_TABLE; IBUS_TYPE_COMPONENT; IBUS_TYPE_ENGINE_DESC; + IBUS_TYPE_OBSERVED_PATH; + IBUS_TYPE_REGISTRY; } static GMainLoop *main_loop = NULL; diff --git a/tools/main.vala b/tools/main.vala index b358974..f3959af 100644 --- a/tools/main.vala +++ b/tools/main.vala @@ -30,7 +30,6 @@ class EngineList { } IBus.Bus? get_bus() { - IBus.init(); var bus = new IBus.Bus(); if (!bus.is_connected ()) return null; @@ -310,6 +309,8 @@ public int main(string[] argv) { GLib.Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.GLIB_LOCALE_DIR); GLib.Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8"); + IBus.init(); + program_name = Path.get_basename(argv[0]); if (argv.length < 2) { print_usage(stderr); -- 2.7.4