From 5974d2d08b2d4dffffd348d240aba8afb9dfeb35 Mon Sep 17 00:00:00 2001 From: Daniel Playfair Cal Date: Mon, 11 Dec 2017 17:11:14 +1100 Subject: Service: filter changesets when performing writes such that changed events are only emitted if new values differ from existing values --- common/dconf-changeset.c | 70 +++++++++++++++++++++++++++++++++++++----------- common/dconf-changeset.h | 3 +++ service/dconf-writer.c | 24 ++++++++++------- 3 files changed, 72 insertions(+), 25 deletions(-) diff --git a/common/dconf-changeset.c b/common/dconf-changeset.c index c80c88c..705fec9 100644 --- a/common/dconf-changeset.c +++ b/common/dconf-changeset.c @@ -771,6 +771,57 @@ dconf_changeset_change (DConfChangeset *changeset, } } +/** + * dconf_changeset_filter_changes: + * @base: a database mode changeset + * @changes: a changeset + * + * Produces a changeset that contains all the changes in @changes that + * are not already present in @base + * + * If there are no such changes, %NULL is returned + * + * Applying the result to @base will yield the same result as applying + * @changes to @base + * + * Returns: (transfer full) (nullable): the minimal changes, or %NULL + * + * Since: 0.35.1 + */ +DConfChangeset * +dconf_changeset_filter_changes (DConfChangeset *base, + DConfChangeset *changes) +{ + DConfChangeset *result = NULL; + GHashTableIter iter; + gpointer key, val; + + g_return_val_if_fail (base->is_database, NULL); + + /* We create the list of changes by iterating the 'changes' changeset + * and noting any keys that are not in the 'base' changeset or do not + * have the same value in the 'base' changeset + * + * Note: because 'base' is a database changeset we don't have to + * worry about it containing NULL values (dir resets). + */ + g_hash_table_iter_init (&iter, changes->table); + while (g_hash_table_iter_next (&iter, &key, &val)) + { + GVariant *base_val = g_hash_table_lookup (base->table, key); + + if (base_val == NULL || !g_variant_equal (val, base_val)) + { + if (!result) + result = dconf_changeset_new (); + + dconf_changeset_set (result, key, val); + } + } + + return result; +} + /** * dconf_changeset_diff: * @from: a database mode changeset @@ -793,7 +844,7 @@ DConfChangeset * dconf_changeset_diff (DConfChangeset *from, DConfChangeset *to) { - DConfChangeset *changeset = NULL; + DConfChangeset *changeset; GHashTableIter iter; gpointer key, val; @@ -806,8 +857,8 @@ dconf_changeset_diff (DConfChangeset *from, * * We create our list of changes in two steps: * - * - iterate the 'to' changeset and note any keys that do not have - * the same value in the 'from' changeset + * - call dconf_changeset_filter_changes to find values from 'to' + * which are not present in 'from' or hold different values to 'to' * * - iterate the 'from' changeset and note any keys not present in * the 'to' changeset, recording resets for them @@ -817,19 +868,8 @@ dconf_changeset_diff (DConfChangeset *from, * Note: because 'from' and 'to' are database changesets we don't have * to worry about seeing NULL values or dirs. */ - g_hash_table_iter_init (&iter, to->table); - while (g_hash_table_iter_next (&iter, &key, &val)) - { - GVariant *from_val = g_hash_table_lookup (from->table, key); - if (from_val == NULL || !g_variant_equal (val, from_val)) - { - if (!changeset) - changeset = dconf_changeset_new (); - - dconf_changeset_set (changeset, key, val); - } - } + changeset = dconf_changeset_filter_changes (from, to); g_hash_table_iter_init (&iter, from->table); while (g_hash_table_iter_next (&iter, &key, &val)) diff --git a/common/dconf-changeset.h b/common/dconf-changeset.h index b0ce450..6fe60f2 100644 --- a/common/dconf-changeset.h +++ b/common/dconf-changeset.h @@ -65,6 +65,9 @@ DConfChangeset * dconf_changeset_deserialise (GVarian void dconf_changeset_change (DConfChangeset *changeset, DConfChangeset *changes); +DConfChangeset * dconf_changeset_filter_changes (DConfChangeset *from, + DConfChangeset *changes); + DConfChangeset * dconf_changeset_diff (DConfChangeset *from, DConfChangeset *to); diff --git a/service/dconf-writer.c b/service/dconf-writer.c index 26f66dd..8b59019 100644 --- a/service/dconf-writer.c +++ b/service/dconf-writer.c @@ -130,21 +130,25 @@ dconf_writer_real_change (DConfWriter *writer, const gchar *tag) { g_return_if_fail (writer->priv->uncommited_values != NULL); + DConfChangeset *effective_changeset = dconf_changeset_filter_changes (writer->priv->uncommited_values, + changeset); - dconf_changeset_change (writer->priv->uncommited_values, changeset); - - if (tag) + if (effective_changeset) { - TaggedChange *change; + dconf_changeset_change (writer->priv->uncommited_values, effective_changeset); + if (tag) + { + TaggedChange *change; - change = g_slice_new (TaggedChange); - change->changeset = dconf_changeset_ref (changeset); - change->tag = g_strdup (tag); + change = g_slice_new (TaggedChange); + change->changeset = dconf_changeset_ref (effective_changeset); + change->tag = g_strdup (tag); - g_queue_push_tail (&writer->priv->uncommited_changes, change); - } + g_queue_push_tail (&writer->priv->uncommited_changes, change); + } - writer->priv->need_write = TRUE; + writer->priv->need_write = TRUE; + } } static gboolean -- cgit v1.2.1