5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2000 - 2001 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "silcincludes.h"
25 /* Static prototypes */
26 static void silc_idcache_destructor(void *key, void *context,
28 static SilcIDCacheList silc_idcache_list_alloc();
29 static void silc_idcache_list_add(SilcIDCacheList list,
30 SilcIDCacheEntry cache);
35 This is context for the ID cache system. This includes all the cache
36 entries and other internal data. This is read-only object and not
37 visible outside this cache system.
39 Fields are as follows:
41 SilcHashTable id_table
43 Hash table using the ID as the key.
45 SilcHashTable name_table
47 Hash table using the name as the key.
49 SilcHashTable context_table
51 Hash table using the context as the key.
53 SilcIDCacheDestructor destructor
55 Destructor callback that is called when an cache entry expires or is
56 purged from the ID cache. The application must not free cache entry
57 because the library will do it automatically. The appliation, however,
58 is responsible of freeing any data in the entry.
62 Indicates the type of the ID's this cache holds.
65 struct SilcIDCacheStruct {
66 SilcHashTable id_table;
67 SilcHashTable name_table;
68 SilcHashTable context_table;
69 SilcIDCacheDestructor destructor;
76 This is returned when searching the cache. Enumeration functions are
77 provided to traverse the list; actually this is used as table not as
80 By default the found cache entries are saved into the static cache
81 table to provide access without reallocation. However, if the static
82 table is full, rest of the cache entries are dynamically allocated
83 into `cache_dyn' table. Traversing functions automatically handles
87 struct SilcIDCacheListStruct {
88 SilcIDCacheEntry cache[64];
89 SilcIDCacheEntry *cache_dyn;
90 uint32 cache_dyn_count;
95 /* Allocates new ID cache object. The initial amount of allocated entries
96 can be sent as argument. If `count' is 0 the system uses default values.
97 The `id_type' defines the types of the ID's that will be saved to the
100 SilcIDCache silc_idcache_alloc(uint32 count, SilcIdType id_type,
101 SilcIDCacheDestructor destructor)
105 SILC_LOG_DEBUG(("Allocating new cache"));
107 cache = silc_calloc(1, sizeof(*cache));
108 cache->id_table = silc_hash_table_alloc(count, silc_hash_id,
109 (void *)(uint32)id_type,
110 silc_hash_id_compare,
111 (void *)(uint32)id_type,
112 silc_idcache_destructor, NULL);
113 cache->name_table = silc_hash_table_alloc(count, silc_hash_string, NULL,
114 silc_hash_string_compare, NULL,
116 cache->context_table = silc_hash_table_alloc(count, silc_hash_ptr, NULL,
117 NULL, NULL, NULL, NULL);
118 cache->destructor = destructor;
119 cache->type = id_type;
124 /* Free's ID cache object and cache entries */
126 void silc_idcache_free(SilcIDCache cache)
129 silc_hash_table_free(cache->id_table);
130 silc_hash_table_free(cache->name_table);
131 silc_hash_table_free(cache->context_table);
136 /* Add new entry to the cache. */
138 bool silc_idcache_add(SilcIDCache cache, char *name, void *id,
139 void *context, int expire)
142 uint32 curtime = time(NULL);
144 SILC_LOG_DEBUG(("Adding cache entry"));
146 /* Allocate new cache entry */
147 c = silc_calloc(1, sizeof(*c));
150 c->expire = (expire ? (curtime + SILC_ID_CACHE_EXPIRE) : 0);
151 c->context = context;
153 /* Add the new entry to the hash tables */
156 silc_hash_table_add(cache->id_table, id, c);
158 silc_hash_table_add(cache->name_table, name, c);
160 silc_hash_table_add(cache->context_table, context, c);
162 /* See whether we have time to rehash the tables */
163 if ((silc_hash_table_count(cache->id_table) / 2) >
164 silc_hash_table_size(cache->id_table)) {
165 silc_hash_table_rehash(cache->id_table, 0);
166 silc_hash_table_rehash(cache->name_table, 0);
167 silc_hash_table_rehash(cache->context_table, 0);
173 /* Destructor for the ID Cache entry */
175 static void silc_idcache_destructor(void *key, void *context,
181 /* Delete cache entry from cache. */
183 bool silc_idcache_del(SilcIDCache cache, SilcIDCacheEntry old)
187 SILC_LOG_DEBUG(("Deleting cache entry"));
190 ret = silc_hash_table_del_by_context(cache->name_table, old->name, old);
192 ret = silc_hash_table_del(cache->context_table, old->context);
194 ret = silc_hash_table_del(cache->id_table, old->id);
199 /* Deletes ID cache entry by ID. */
201 bool silc_idcache_del_by_id(SilcIDCache cache, void *id)
205 if (!silc_hash_table_find(cache->id_table, id, NULL, (void *)&c))
208 return silc_idcache_del(cache, c);
211 /* Same as above but with specific hash and comparison functions. If the
212 functions are NULL then default values are used. */
214 bool silc_idcache_del_by_id_ext(SilcIDCache cache, void *id,
215 SilcHashFunction hash,
217 SilcHashCompare compare,
218 void *compare_context)
223 SILC_LOG_DEBUG(("Deleting cache entry"));
225 if (!silc_hash_table_find_ext(cache->id_table, id, NULL, (void *)&c,
226 hash, hash_context, compare,
231 ret = silc_hash_table_del_by_context(cache->name_table, c->name, c);
233 ret = silc_hash_table_del(cache->context_table, c->context);
235 ret = silc_hash_table_del_ext(cache->id_table, c->id, hash,
236 hash_context, compare, compare_context);
241 /* Deletes ID cache entry by context. */
243 bool silc_idcache_del_by_context(SilcIDCache cache, void *context)
248 SILC_LOG_DEBUG(("Deleting cache entry"));
250 if (!silc_hash_table_find(cache->context_table, context, NULL, (void *)&c))
254 ret = silc_hash_table_del_by_context(cache->name_table, c->name, c);
256 ret = silc_hash_table_del(cache->context_table, c->context);
258 ret = silc_hash_table_del_by_context(cache->id_table, c->id, c);
263 /* Deletes all ID entries from cache. Free's memory as well. */
265 bool silc_idcache_del_all(SilcIDCache cache)
267 silc_hash_table_free(cache->id_table);
268 silc_hash_table_free(cache->name_table);
269 silc_hash_table_free(cache->context_table);
274 /* Foreach callback fro silc_idcache_purge. */
276 static void silc_idcache_purge_foreach(void *key, void *context,
279 SilcIDCache cache = (SilcIDCache)user_context;
280 uint32 curtime = time(NULL);
281 SilcIDCacheEntry c = (SilcIDCacheEntry)context;
283 if (c->expire && c->expire < curtime) {
284 /* Call the destructor */
285 if (cache->destructor)
286 cache->destructor(cache, c);
288 /* Delete the entry */
289 silc_idcache_del(cache, c);
293 /* Purges the cache by removing expired cache entires. Note that this
294 may be very slow operation. */
296 bool silc_idcache_purge(SilcIDCache cache)
298 silc_hash_table_foreach(cache->id_table, silc_idcache_purge_foreach, cache);
302 /* Purges the specific entry by context. */
304 bool silc_idcache_purge_by_context(SilcIDCache cache, void *context)
306 SilcIDCacheEntry entry;
309 if (!silc_hash_table_find(cache->context_table, context, NULL,
313 /* Call the destructor */
314 if (cache->destructor)
315 cache->destructor(cache, entry);
318 ret = silc_hash_table_del_by_context(cache->name_table, entry->name,
321 ret = silc_hash_table_del(cache->context_table, entry->context);
323 ret = silc_hash_table_del_by_context(cache->id_table, entry->id, entry);
328 /* Callback that is called by the hash table routine when traversing
329 entrys in the hash table. */
331 static void silc_idcache_get_all_foreach(void *key, void *context,
334 SilcIDCacheList list = (SilcIDCacheList)user_context;
335 silc_idcache_list_add(list, (SilcIDCacheEntry)context);
338 /* Returns all cache entrys from the ID cache to the `ret' ID Cache List. */
340 bool silc_idcache_get_all(SilcIDCache cache, SilcIDCacheList *ret)
342 SilcIDCacheList list;
347 list = silc_idcache_list_alloc();
348 silc_hash_table_foreach(cache->id_table, silc_idcache_get_all_foreach, list);
350 if (silc_idcache_list_count(list) == 0) {
351 silc_idcache_list_free(list);
360 /* Find ID Cache entry by ID. May return multiple entries. */
362 bool silc_idcache_find_by_id(SilcIDCache cache, void *id,
363 SilcIDCacheList *ret)
365 SilcIDCacheList list;
367 list = silc_idcache_list_alloc();
372 silc_hash_table_find_foreach(cache->id_table, id,
373 silc_idcache_get_all_foreach, list);
375 if (silc_idcache_list_count(list) == 0) {
376 silc_idcache_list_free(list);
385 /* Find specific ID with specific hash function and comparison functions.
386 If `hash' is NULL then the default hash funtion is used and if `compare'
387 is NULL default comparison function is used. */
389 bool silc_idcache_find_by_id_one_ext(SilcIDCache cache, void *id,
390 SilcHashFunction hash,
392 SilcHashCompare compare,
393 void *compare_context,
394 SilcIDCacheEntry *ret)
396 return silc_hash_table_find_ext(cache->id_table, id, NULL, (void *)ret,
397 hash, hash_context, compare,
401 /* Find one specific ID entry. */
403 bool silc_idcache_find_by_id_one(SilcIDCache cache, void *id,
404 SilcIDCacheEntry *ret)
406 return silc_hash_table_find(cache->id_table, id, NULL, (void *)ret);
409 /* Finds cache entry by context. */
411 bool silc_idcache_find_by_context(SilcIDCache cache, void *context,
412 SilcIDCacheEntry *ret)
414 return silc_hash_table_find(cache->context_table, context, NULL,
418 /* Find ID Cache entry by name. Returns list of cache entries. */
420 bool silc_idcache_find_by_name(SilcIDCache cache, char *name,
421 SilcIDCacheList *ret)
423 SilcIDCacheList list;
425 list = silc_idcache_list_alloc();
430 silc_hash_table_find_foreach(cache->name_table, name,
431 silc_idcache_get_all_foreach, list);
433 if (silc_idcache_list_count(list) == 0) {
434 silc_idcache_list_free(list);
443 /* Find ID Cache entry by name. Returns one cache entry. */
445 bool silc_idcache_find_by_name_one(SilcIDCache cache, char *name,
446 SilcIDCacheEntry *ret)
448 if (!silc_hash_table_find(cache->name_table, name, NULL, (void *)ret))
454 /* Allocates ID cache list. */
456 static SilcIDCacheList silc_idcache_list_alloc()
458 SilcIDCacheList list;
460 list = silc_calloc(1, sizeof(*list));
465 /* Adds cache entry to the ID cache list. If needed reallocates memory
468 static void silc_idcache_list_add(SilcIDCacheList list, SilcIDCacheEntry cache)
472 /* Try to add to static cache */
473 if (!list->cache_dyn_count)
474 for (i = 0; i < sizeof(list->cache); i++) {
475 if (!list->cache[i]) {
476 list->cache[i] = cache;
482 /* Static cache is full, allocate dynamic cache */
483 for (i = 0; i < list->cache_dyn_count; i++) {
484 if (!list->cache_dyn[i]) {
485 list->cache_dyn[i] = cache;
491 if (i >= list->cache_dyn_count) {
495 list->cache_dyn = silc_realloc(list->cache_dyn,
496 sizeof(*list->cache) * (i));
498 /* NULL the reallocated area */
499 for (k = list->cache_dyn_count; k < i; k++)
500 list->cache_dyn[k] = NULL;
502 list->cache_dyn[list->cache_dyn_count] = cache;
503 list->cache_dyn_count = i;
508 /* Returns number of cache entries in the ID cache list. */
510 int silc_idcache_list_count(SilcIDCacheList list)
512 return list->cache_count;
515 /* Returns first entry from the ID cache list. */
517 bool silc_idcache_list_first(SilcIDCacheList list, SilcIDCacheEntry *ret)
521 if (!list->cache[list->pos])
525 *ret = list->cache[list->pos];
530 /* Returns next entry from the ID cache list. */
532 bool silc_idcache_list_next(SilcIDCacheList list, SilcIDCacheEntry *ret)
537 if (list->pos >= sizeof(list->cache)) {
542 if (dyn && list->pos >= list->cache_dyn_count)
545 if (!dyn && !list->cache[list->pos])
548 if (dyn && !list->cache_dyn[list->pos])
553 *ret = list->cache[list->pos];
555 *ret = list->cache_dyn[list->pos];
561 /* Free's ID cache list. User must free the list object returned by
562 any of the searching functions. */
564 void silc_idcache_list_free(SilcIDCacheList list)
568 silc_free(list->cache_dyn);