summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAllison Lortie <desrt@desrt.ca>2016-08-12 11:13:18 +0200
committerAllison Lortie <desrt@desrt.ca>2016-10-14 10:03:07 +0200
commit4f0688a7009eb2fd8f7ad5e701cd62b4bb2b4b28 (patch)
tree2b23c6074b8dd865238e5d0e4ef6cc112dd82765
parent9385c9a8c383486e083c4b019df31b10aabbffbd (diff)
downloaddconf-4f0688a7009eb2fd8f7ad5e701cd62b4bb2b4b28.tar.gz
engine: optimise the no-locks case
Add a fast path for avoiding writability checks for the very common case where there are no databases installed that have locks (ie: the default configuration). This allows us to avoid iterating a changeset to check for writability before sending it off to the service, for example.
-rw-r--r--engine/dconf-engine-source.h2
-rw-r--r--engine/dconf-engine.c40
2 files changed, 36 insertions, 6 deletions
diff --git a/engine/dconf-engine-source.h b/engine/dconf-engine-source.h
index 802f09d..71e03a6 100644
--- a/engine/dconf-engine-source.h
+++ b/engine/dconf-engine-source.h
@@ -44,7 +44,7 @@ struct _DConfEngineSource
GvdbTable *values;
GvdbTable *locks;
GBusType bus_type;
- gboolean writable;
+ gboolean writable; /* this is not allowed to change */
gboolean did_warn;
gchar *bus_name;
gchar *object_path;
diff --git a/engine/dconf-engine.c b/engine/dconf-engine.c
index bc36e52..aca2dd3 100644
--- a/engine/dconf-engine.c
+++ b/engine/dconf-engine.c
@@ -14,7 +14,7 @@
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*
- * Author: Ryan Lortie <desrt@desrt.ca>
+ * Author: Allison Lortie <desrt@desrt.ca>
*/
#include "config.h"
@@ -162,6 +162,7 @@ struct _DConfEngine
guint64 state; /* Counter that changes every time a source is refreshed. */
DConfEngineSource **sources; /* Array never changes, but each source changes internally. */
gint n_sources;
+ gboolean has_locks; /* Must be updated when refreshing the source list. */
GMutex queue_lock; /* This lock is for pending, in_flight, queue_cond */
GCond queue_cond; /* Signalled when the queues empty */
@@ -195,13 +196,32 @@ struct _DConfEngine
static void
dconf_engine_acquire_sources (DConfEngine *engine)
{
+ gboolean changed = FALSE;
gint i;
g_mutex_lock (&engine->sources_lock);
for (i = 0; i < engine->n_sources; i++)
- if (dconf_engine_source_refresh (engine->sources[i]))
+ changed |= dconf_engine_source_refresh (engine->sources[i]);
+
+ if (changed)
+ {
+ gboolean has_locks;
+
+ /* If we have no sources, or if the first source is non-writable, the
+ * effect is as-if everything is locked.
+ *
+ * Note: nothing in this line can change as a result of a refresh.
+ */
+ has_locks = engine->n_sources == 0 || !engine->sources[0]->writable;
+
+ /* Now we check if the refresh had any effect. */
+ for (i = 1; !has_locks && i < engine->n_sources; i++)
+ has_locks |= engine->sources[i]->locks != NULL;
+
+ engine->has_locks = has_locks;
engine->state++;
+ }
}
static void
@@ -234,6 +254,12 @@ dconf_engine_new (const gchar *profile,
engine->free_func = free_func;
engine->ref_count = 1;
+ /* The engine starts with zero sources, which means that every key is
+ * effectively locked. If the engine has more than zero sources, this
+ * will be updated when the first refresh is done.
+ */
+ engine->has_locks = TRUE;
+
g_mutex_init (&engine->sources_lock);
g_mutex_init (&engine->queue_lock);
g_cond_init (&engine->queue_cond);
@@ -354,10 +380,13 @@ gboolean
dconf_engine_is_writable (DConfEngine *engine,
const gchar *key)
{
- gboolean writable;
+ gboolean writable = TRUE;
dconf_engine_acquire_sources (engine);
- writable = dconf_engine_is_writable_internal (engine, key);
+
+ if (engine->has_locks)
+ writable = dconf_engine_is_writable_internal (engine, key);
+
dconf_engine_release_sources (engine);
return writable;
@@ -1115,7 +1144,8 @@ dconf_engine_changeset_changes_only_writable_keys (DConfEngine *engine,
dconf_engine_acquire_sources (engine);
- if (!dconf_changeset_all (changeset, dconf_engine_is_writable_changeset_predicate, engine))
+ if (engine->has_locks &&
+ !dconf_changeset_all (changeset, dconf_engine_is_writable_changeset_predicate, engine))
{
g_set_error_literal (error, DCONF_ERROR, DCONF_ERROR_NOT_WRITABLE,
"The operation attempted to modify one or more non-writable keys");