2
* Copyright (C) 1999, 2000 Red Hat Inc.
4
* This library is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU Library General Public
6
* License as published by the Free Software Foundation; either
7
* version 2 of the License, or (at your option) any later version.
9
* This library is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* Library General Public License for more details.
14
* You should have received a copy of the GNU Library General Public
15
* License along with this library; if not, write to the
16
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17
* Boston, MA 02111-1307, USA.
20
#include "xml-cache.h"
21
#include <gconf/gconf-internals.h>
25
/* This makes hash table safer when debugging */
26
#ifndef GCONF_ENABLE_DEBUG
27
#define safe_g_hash_table_insert g_hash_table_insert
30
safe_g_hash_table_insert(GHashTable* ht, gpointer key, gpointer value)
32
gpointer oldkey = NULL, oldval = NULL;
34
if (g_hash_table_lookup_extended(ht, key, &oldkey, &oldval))
36
gconf_log(GCL_WARNING, "Hash key `%s' is already in the table!",
42
g_hash_table_insert(ht, key, value);
48
cache_is_nonexistent(Cache* cache,
52
cache_set_nonexistent (Cache* cache,
57
cache_insert (Cache* cache,
63
GHashTable* nonexistent_cache;
65
List of lists of dirs marked deleted, in the
66
proper order; should be synced by deleting each
67
list from front to end, starting with the first
76
cache_new (const gchar *root_dir,
82
cache = g_new(Cache, 1);
84
cache->root_dir = g_strdup(root_dir);
86
cache->cache = g_hash_table_new(g_str_hash, g_str_equal);
87
cache->nonexistent_cache = g_hash_table_new(g_str_hash, g_str_equal);
89
cache->deleted = NULL;
91
cache->dir_mode = dir_mode;
92
cache->file_mode = file_mode;
97
static void cache_destroy_foreach(const gchar* key,
98
Dir* dir, gpointer data);
100
static void cache_destroy_nonexistent_foreach(gchar* key,
105
cache_destroy (Cache *cache)
109
g_free(cache->root_dir);
110
g_hash_table_foreach(cache->cache, (GHFunc)cache_destroy_foreach,
112
g_hash_table_foreach(cache->nonexistent_cache,
113
(GHFunc)cache_destroy_nonexistent_foreach,
115
g_hash_table_destroy(cache->cache);
116
g_hash_table_destroy(cache->nonexistent_cache);
118
if (cache->deleted != NULL)
119
gconf_log(GCL_WARNING, _("Unsynced directory deletions when shutting down XML backend"));
121
iter = cache->deleted;
125
g_slist_free(iter->data);
127
iter = g_slist_next(iter);
129
g_slist_free(cache->deleted);
135
typedef struct _SyncData SyncData;
142
cache_sync_foreach(const gchar* key,
146
GError* error = NULL;
148
/* log errors but don't report the specific ones */
149
if (!dir_sync(dir, &error))
152
g_return_if_fail(error != NULL);
153
gconf_log(GCL_ERR, "%s", error->message);
155
g_return_if_fail(dir_sync_pending(dir));
159
g_return_if_fail(error == NULL);
160
g_return_if_fail(!dir_sync_pending(dir));
165
cache_sync (Cache *cache,
168
SyncData sd = { FALSE, NULL };
172
/* First delete pending directories */
173
delete_list = cache->deleted;
175
while (delete_list != NULL)
179
tmp = delete_list->data;
185
if (!dir_sync(d, NULL)) /* don't get errors, they'd pile up */
188
tmp = g_slist_next(tmp);
191
g_slist_free(delete_list->data);
193
delete_list = g_slist_next(delete_list);
196
g_slist_free(cache->deleted);
197
cache->deleted = NULL;
199
g_hash_table_foreach(cache->cache, (GHFunc)cache_sync_foreach,
205
typedef struct _CleanData CleanData;
213
cache_clean_foreach(const gchar* key,
214
Dir* dir, CleanData* cd)
218
last_access = dir_get_last_access(dir);
220
if ((cd->now - last_access) >= cd->length)
222
if (!dir_sync_pending(dir))
229
gconf_log(GCL_WARNING, _("Unable to remove directory `%s' from the XML backend cache, because it has not been successfully synced to disk"),
239
cache_clean (Cache *cache,
242
CleanData cd = { 0, 0, 0 };
245
cd.length = older_than;
247
cd.now = time(NULL); /* ha ha, it's an online store! */
249
g_hash_table_foreach_remove(cache->cache, (GHRFunc)cache_clean_foreach,
252
size = g_hash_table_size(cache->cache);
255
gconf_log (GCL_DEBUG,
256
_("%u items remain in the cache after cleaning already-synced items older than %u seconds"),
262
cache_delete_dir_by_pointer(Cache* cache,
267
cache_delete_recursive(Cache* cache, Dir* d, GSList** hit_list, GError** err)
271
gboolean failure = FALSE;
273
subdirs = dir_all_subdirs(d, err);
275
if (subdirs == NULL && err && *err != NULL)
279
while (tmp != NULL && !failure)
284
fullkey = gconf_concat_dir_and_key(dir_get_name(d), (gchar*)tmp->data);
286
subd = cache_lookup(cache, fullkey, FALSE, err);
291
if (subd == NULL && err && *err)
293
else if (subd != NULL &&
294
!dir_is_deleted(subd))
296
/* recurse, whee! (unless the subdir is already deleted) */
297
cache_delete_dir_by_pointer(cache, subd, err);
303
tmp = g_slist_next(tmp);
306
g_slist_free(subdirs);
308
/* The first directories to be deleted (fringes) go on the front
310
*hit_list = g_slist_prepend(*hit_list, d);
312
/* We go ahead and mark the dir deleted */
315
/* be sure we set error if failure occurred */
316
g_return_if_fail( (!failure) || (err == NULL) || (*err != NULL));
321
cache_delete_dir_by_pointer(Cache* cache,
325
GSList* hit_list = NULL;
327
cache_delete_recursive(cache, d, &hit_list, err);
329
/* If you first dir_cache_delete() a subdir, then dir_cache_delete()
330
its parent, without syncing, first the list generated by
331
the subdir delete then the list from the parent delete should
332
be nuked. If you first delete a parent, then its subdir,
333
really only the parent list should be nuked, but
334
in effect it's OK to nuke the parent first then
335
fail to nuke the subdir. So, if we prepend here,
336
then nuke the list in order, it will work fine.
339
cache->deleted = g_slist_prepend(cache->deleted, hit_list);
343
cache_delete_dir (Cache *cache,
349
d = cache_lookup(cache, key, FALSE, err);
353
g_assert(err == NULL || *err == NULL);
354
cache_delete_dir_by_pointer(cache, d, err);
359
cache_lookup (Cache *cache,
361
gboolean create_if_missing,
366
g_assert(key != NULL);
367
g_return_val_if_fail(cache != NULL, NULL);
370
dir = g_hash_table_lookup(cache->cache, key);
374
gconf_log(GCL_DEBUG, "Using dir %s from cache", key);
379
/* Not in cache, check whether we already failed
381
if (cache_is_nonexistent(cache, key))
383
if (!create_if_missing)
388
/* Didn't already fail to load, try to load */
389
dir = dir_load(key, cache->root_dir, err);
393
g_assert(err == NULL || *err == NULL);
396
cache_insert(cache, dir);
402
/* Remember that we failed to load it */
403
if (!create_if_missing)
405
cache_set_nonexistent(cache, key, TRUE);
421
g_assert(dir == NULL);
422
g_assert(create_if_missing);
423
g_assert(err == NULL || *err == NULL);
427
gconf_log(GCL_DEBUG, "Creating new dir %s", key);
429
dir = dir_new(key, cache->root_dir, cache->dir_mode, cache->file_mode);
431
if (!dir_ensure_exists(dir, err))
435
g_return_val_if_fail((err == NULL) ||
441
cache_insert(cache, dir);
448
cache_is_nonexistent(Cache* cache,
451
return GPOINTER_TO_INT(g_hash_table_lookup(cache->nonexistent_cache,
456
cache_set_nonexistent (Cache* cache,
462
/* don't use safe_ here, doesn't matter */
463
g_hash_table_insert(cache->nonexistent_cache,
465
GINT_TO_POINTER(TRUE));
472
if (g_hash_table_lookup_extended(cache->nonexistent_cache,
477
g_hash_table_remove(cache->nonexistent_cache,
484
cache_insert (Cache* cache,
487
g_return_if_fail(d != NULL);
489
gconf_log(GCL_DEBUG, "Caching dir %s", dir_get_name(d));
491
safe_g_hash_table_insert(cache->cache, (gchar*)dir_get_name(d), d);
495
cache_destroy_foreach(const gchar* key,
496
Dir* dir, gpointer data)
498
#ifdef GCONF_ENABLE_DEBUG
499
if (dir_sync_pending(dir))
500
gconf_log(GCL_DEBUG, "Destroying a directory (%s) with sync still pending",
507
cache_destroy_nonexistent_foreach(gchar* key,