diff options
author | Matthias Clasen <mclasen@redhat.com> | 2009-04-21 02:11:20 -0400 |
---|---|---|
committer | Behdad Esfahbod <behdad@behdad.org> | 2009-04-21 02:11:20 -0400 |
commit | e9489a1746b9df1983c8ae7331443d197e23d40b (patch) | |
tree | 38c3248a9a23d4217f2b6f45b07aca9491b47128 | |
parent | 5a18e7925b73d0a5b7e84b42513e4e84bc2b14ff (diff) | |
download | gconf-e9489a1746b9df1983c8ae7331443d197e23d40b.tar.gz |
Track fully-cached directories in the client
This is used to do negative-hit caching, as well as listing all entries
from the client cache.
-rw-r--r-- | gconf/gconf-client.c | 95 | ||||
-rw-r--r-- | gconf/gconf-client.h | 4 |
2 files changed, 80 insertions, 19 deletions
diff --git a/gconf/gconf-client.c b/gconf/gconf-client.c index ed1ddfd2..cb052cd5 100644 --- a/gconf/gconf-client.c +++ b/gconf/gconf-client.c @@ -230,6 +230,8 @@ gconf_client_init (GConfClient *client) client->error_mode = GCONF_CLIENT_HANDLE_UNRETURNED; client->dir_hash = g_hash_table_new (g_str_hash, g_str_equal); client->cache_hash = g_hash_table_new (g_str_hash, g_str_equal); + client->cache_dirs = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, NULL); /* We create the listeners only if they're actually used */ client->listeners = NULL; client->notify_list = NULL; @@ -307,6 +309,9 @@ gconf_client_finalize (GObject* object) g_hash_table_destroy (client->cache_hash); client->cache_hash = NULL; + g_hash_table_destroy (client->cache_dirs); + client->cache_dirs = NULL; + unregister_client (client); set_engine (client, NULL); @@ -653,6 +658,19 @@ clear_dir_cache_foreach (char* key, GConfEntry* entry, char *dir) return FALSE; } +static gboolean +clear_cache_dirs_foreach (char *key, gpointer value, char *dir) +{ + if (strcmp (dir, key) == 0 || + gconf_key_is_below (dir, key)) + { + trace ("'%s' no longer fully cached", dir); + return TRUE; + } + + return FALSE; +} + static void gconf_client_real_remove_dir (GConfClient* client, Dir* d, @@ -679,7 +697,9 @@ gconf_client_real_remove_dir (GConfClient* client, g_hash_table_foreach_remove (client->cache_hash, (GHRFunc)clear_dir_cache_foreach, d->name); - + g_hash_table_foreach_remove (client->cache_dirs, + (GHRFunc)clear_cache_dirs_foreach, + d->name); dir_destroy(d); ad.client = client; @@ -709,7 +729,7 @@ gconf_client_remove_dir (GConfClient* client, found->add_count -= 1; if (found->add_count == 0) - gconf_client_real_remove_dir(client, found, err); + gconf_client_real_remove_dir (client, found, err); } #ifndef G_DISABLE_CHECKS else @@ -806,7 +826,7 @@ gconf_client_clear_cache(GConfClient* client) g_hash_table_foreach_remove (client->cache_hash, (GHRFunc)clear_cache_foreach, client); - g_assert (g_hash_table_size(client->cache_hash) == 0); + g_hash_table_remove_all (client->cache_dirs); } static void @@ -913,6 +933,8 @@ cache_pairs_in_dir(GConfClient* client, const gchar* dir) } cache_entry_list_destructively (client, pairs); + trace ("Mark '%s' as fully cached", dir); + g_hash_table_insert (client->cache_dirs, g_strdup (dir), GINT_TO_POINTER (1)); } void @@ -1060,16 +1082,31 @@ gconf_client_all_entries (GConfClient* client, { GError *error = NULL; GSList *retval; - + int dirlen; + trace ("Getting all values in '%s'", dir); - /* We could just use the cache to get all the entries, - * iff we have previously done an all_entries and the - * cache hasn't since been tossed out, and if we are monitoring - * this directory. - * FIXME - */ - + if (g_hash_table_lookup (client->cache_dirs, dir)) + { + GHashTableIter iter; + gchar *key; + GConfEntry *entry; + + trace ("Using cached values"); + + dirlen = strlen (dir); + retval = NULL; + g_hash_table_iter_init (&iter, client->cache_hash); + while (g_hash_table_iter_next (&iter, &key, &entry)) + { + if (g_str_has_prefix (key, dir) && + key + dirlen == strrchr (key, '/')) + retval = g_slist_prepend (retval, gconf_entry_copy (entry)); + } + + return retval; + } + PUSH_USE_ENGINE (client); retval = gconf_engine_all_entries (client->engine, dir, &error); POP_USE_ENGINE (client); @@ -1080,8 +1117,12 @@ gconf_client_all_entries (GConfClient* client, return NULL; if (key_being_monitored (client, dir)) - cache_entry_list_destructively (client, copy_entry_list (retval)); - + { + cache_entry_list_destructively (client, copy_entry_list (retval)); + trace ("Mark '%s' as fully cached", dir); + g_hash_table_insert (client->cache_dirs, g_strdup (dir), GINT_TO_POINTER (1)); + } + return retval; } @@ -1134,9 +1175,9 @@ gconf_client_dir_exists(GConfClient* client, handle_error (client, error, err); if (retval) - trace ("'%s' exists\n", dir); + trace ("'%s' exists", dir); else - trace ("'%s' doesn't exist\n", dir); + trace ("'%s' doesn't exist", dir); return retval; } @@ -1216,7 +1257,8 @@ get (GConfClient *client, { trace ("'%s' was in the client-side cache", key); - g_assert (entry != NULL); + if (entry == NULL) + return NULL; if (gconf_entry_get_is_default (entry) && !use_default) return NULL; @@ -1964,7 +2006,26 @@ gconf_client_lookup (GConfClient *client, entry = g_hash_table_lookup (client->cache_hash, key); *entryp = entry; - + + if (!entry) + { + char *dir, *last_slash; + + dir = g_strdup (key); + last_slash = strrchr (dir, '/'); + g_assert (last_slash != NULL); + *last_slash = 0; + + if (g_hash_table_lookup (client->cache_dirs, dir)) + { + g_free (dir); + trace ("Negative cache hit on %s", key); + return TRUE; + } + + g_free (dir); + } + return entry != NULL; } diff --git a/gconf/gconf-client.h b/gconf/gconf-client.h index 29eec237..ffa63e86 100644 --- a/gconf/gconf-client.h +++ b/gconf/gconf-client.h @@ -100,8 +100,8 @@ struct _GConfClient GSList *notify_list; guint notify_handler; int pending_notify_count; - gpointer pad1; - int pad2; + GHashTable *cache_dirs; + int pad2; }; struct _GConfClientClass |