summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Playfair Cal <daniel.playfair.cal@gmail.com>2017-12-11 17:11:14 +1100
committerDaniel Playfair Cal <daniel.playfair.cal@gmail.com>2019-12-29 20:06:20 +1100
commit5974d2d08b2d4dffffd348d240aba8afb9dfeb35 (patch)
tree868c255ef024abe4527b647a9baddd74ad39d1e4
parent7ad890fb7a2ec90a777a756a1fa20a615ec7245e (diff)
downloaddconf-5974d2d08b2d4dffffd348d240aba8afb9dfeb35.tar.gz
Service: filter changesets when performing writes such that changed events are only emitted if new values differ from existing values
-rw-r--r--common/dconf-changeset.c70
-rw-r--r--common/dconf-changeset.h3
-rw-r--r--service/dconf-writer.c24
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
@@ -772,6 +772,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
* @to: 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