Blob Blame History Raw
From 40f887db43dc89e546ecef9c2d2f31a61858badc Mon Sep 17 00:00:00 2001
From: Ryan Lortie <desrt@desrt.ca>
Date: Tue, 25 Jun 2013 14:39:26 -0400
Subject: [PATCH 1/2] DConfChangeset: expose concept of "sealing"

DConfChangeset is a partially threadsafe type.

when first created, it is mutable and can only be used from one thread.
After it is filled in, the intention is that it can be shared between
threads as long as it isn't changed.

Previously, this transition was made when dconf_changeset_describe() was
called.  After that, it was not possible to make any more changes.

Formalise and document this concept and add an explicit call for it:
dconf_changeset_seal().

https://bugzilla.gnome.org/show_bug.cgi?id=703073
---
 common/dconf-changeset.c | 49 ++++++++++++++++++++++++++++++++++++++++++------
 common/dconf-changeset.h |  2 ++
 2 files changed, 45 insertions(+), 6 deletions(-)

diff --git a/common/dconf-changeset.c b/common/dconf-changeset.c
index d9b9f41..54be719 100644
--- a/common/dconf-changeset.c
+++ b/common/dconf-changeset.c
@@ -54,7 +54,8 @@
 struct _DConfChangeset
 {
   GHashTable *table;
-  gboolean is_database;
+  guint is_database : 1;
+  guint is_sealed : 1;
   gint ref_count;
 
   gchar *prefix;
@@ -195,7 +196,7 @@ dconf_changeset_set (DConfChangeset *changeset,
                      const gchar    *path,
                      GVariant       *value)
 {
-  g_return_if_fail (changeset->prefix == NULL);
+  g_return_if_fail (!changeset->is_sealed);
   g_return_if_fail (dconf_is_path (path, NULL));
 
   /* Check if we are performing a path reset */
@@ -366,12 +367,44 @@ dconf_changeset_string_ptr_compare (gconstpointer a_p,
   return strcmp (*a, *b);
 }
 
-static void
-dconf_changeset_build_description (DConfChangeset *changeset)
+/**
+ * dconf_changeset_seal:
+ * @changeset: a #DConfChangeset
+ *
+ * Seals @changeset.
+ *
+ * When a #DConfChangeset is first created, it is mutable and
+ * non-threadsafe.  Once the changeset is populated with the required
+ * changes, it can be shared between multiple threads, but only by
+ * making it immutable by "sealing" it.
+ *
+ * After the changeset is sealed, you cannot call dconf_changeset_set()
+ * or any other functions that would modify it.  It is safe, however, to
+ * share it between multiple threads.
+ *
+ * All changesets are unsealed on creation, including those that are
+ * made by copying changesets that are sealed.
+ * dconf_changeset_describe() will implicitly seal a changeset.
+ *
+ * This function is idempotent.
+ *
+ * Since: 0.18
+ **/
+void
+dconf_changeset_seal (DConfChangeset *changeset)
 {
   gsize prefix_length;
   gint n_items;
 
+  if (changeset->is_sealed)
+    return;
+
+  changeset->is_sealed = TRUE;
+
+  /* This function used to be called dconf_changeset_build_description()
+   * because that's basically what sealing is...
+   */
+
   n_items = g_hash_table_size (changeset->table);
 
   /* If there are no items then what is there to describe? */
@@ -501,6 +534,9 @@ dconf_changeset_build_description (DConfChangeset *changeset)
  * The @paths array is returned in an order such that dir will always
  * come before keys contained within those dirs.
  *
+ * If @changeset is not already sealed then this call will implicitly
+ * seal it.  See dconf_changeset_seal().
+ *
  * Returns: the number of changes (the length of @changes and @values).
  **/
 guint
@@ -513,8 +549,7 @@ dconf_changeset_describe (DConfChangeset       *changeset,
 
   n_items = g_hash_table_size (changeset->table);
 
-  if (n_items && !changeset->prefix)
-    dconf_changeset_build_description (changeset);
+  dconf_changeset_seal (changeset);
 
   if (prefix)
     *prefix = changeset->prefix;
@@ -664,6 +699,8 @@ dconf_changeset_change (DConfChangeset *changeset,
   gsize prefix_len;
   gint i;
 
+  g_return_if_fail (!changeset->is_sealed);
+
   /* Handling resets is a little bit tricky...
    *
    * Consider the case that we have @changeset containing a key /a/b and
diff --git a/common/dconf-changeset.h b/common/dconf-changeset.h
index 7228105..8a9cb48 100644
--- a/common/dconf-changeset.h
+++ b/common/dconf-changeset.h
@@ -70,4 +70,6 @@ void                    dconf_changeset_change                          (DConfCh
 DConfChangeset *        dconf_changeset_diff                            (DConfChangeset           *from,
                                                                          DConfChangeset           *to);
 
+void                    dconf_changeset_seal                            (DConfChangeset           *changeset);
+
 #endif /* __dconf_changeset_h__ */
-- 
1.8.3.1