5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 2000 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.
23 * Revision 1.5 2000/07/18 06:51:48 priikone
24 * Use length of data found from cache instead of length of searched
27 * Revision 1.4 2000/07/17 11:46:36 priikone
30 * Revision 1.3 2000/07/12 05:54:01 priikone
31 * Major rewrite of whole ID Cache system.
33 * Revision 1.2 2000/07/05 06:06:35 priikone
34 * Global cosmetic change.
36 * Revision 1.1.1.1 2000/06/27 11:36:55 priikone
37 * Imported from internal CVS/Added Log headers.
42 #include "silcincludes.h"
45 /* Static prototypes */
46 static int silc_idcache_sorter(const void *a, const void *b);
47 static SilcIDCacheList silc_idcache_list_alloc();
48 static void silc_idcache_list_add(SilcIDCacheList list,
49 SilcIDCacheEntry cache);
54 This is context for the ID cache system. This includes all the cache
55 entries and other internal data. This is read-only object and not
56 visible outside this cache system.
58 Fields are as follows:
60 SilcIDCacheEntry cache
62 Table of the cache entries allocated by silc_idcache_add function.
63 This table is reallocated when new entry is added into the cache.
65 unsigned int cache_count
67 Number of cache entries in the cache.
71 Boolean value to indicate whether the cache is sorted or not. If
72 cache is not sorted the fast access (described next) cannot be used.
73 Sorting can be done by calling sorting function or when adding new
78 Table to provide fast access into the cache by index. When searching
79 by data this table is used to get the index to the first occurence
80 of that data (or part of the data) in the cache. Purpose of this
81 is to provide faster access to the cache when searching by data.
82 This is updated by silc_idcache_add and sorting functions.
85 struct SilcIDCacheStruct {
86 SilcIDCacheEntry cache;
87 unsigned int cache_count;
95 This is returned when searching the cache. Enumeration functions are
96 provided to traverse the list; actually this is used as table not as
99 By default the found cache entries are saved into the static cache
100 table to provide access without reallocation. However, if the static
101 table is full, rest of the cache entries are dynamically allocated
102 into `cache_dyn' table. Traversing functions automatically handles
106 struct SilcIDCacheListStruct {
107 SilcIDCacheEntry cache[64];
108 SilcIDCacheEntry *cache_dyn;
109 unsigned int cache_dyn_count;
110 unsigned int cache_count;
114 /* Allocates new ID cache object. The initial amount of allocated entries
115 can be sent as argument. If `count' is 0 the system uses default values. */
117 SilcIDCache silc_idcache_alloc(unsigned int count)
121 SILC_LOG_DEBUG(("Allocating new cache"));
123 cache = silc_calloc(1, sizeof(*cache));
124 cache->cache = silc_calloc(count ? count : 5, sizeof(*cache->cache));
125 cache->cache_count = count ? count : 5;
126 memset(cache->fast_access, -1, sizeof(cache->fast_access));
131 /* Free's ID cache object and cache entries */
133 void silc_idcache_free(SilcIDCache cache)
136 silc_free(cache->cache);
141 /* qsort() sorter function. */
143 static int silc_idcache_sorter(const void *a, const void *b)
145 SilcIDCacheEntry a1, b1;
147 a1 = (SilcIDCacheEntry)a;
148 b1 = (SilcIDCacheEntry)b;
150 if (!a1->data && !b1->data)
159 return a1->data[0] - b1->data[0];
162 /* Sorts given cache by data. After sorting this updates the fast access
163 table that can be used to access the cache faster. */
165 void silc_idcache_sort_by_data(SilcIDCache cache)
169 qsort(cache->cache, cache->cache_count,
170 sizeof(*cache->cache), silc_idcache_sorter);
172 memset(cache->fast_access, -1, sizeof(cache->fast_access));
174 /* Update the fast access table (this of course takes its own time when
175 the cache is very large). */
176 for (i = 0; i < cache->cache_count; i++) {
177 if (cache->cache[i].data &&
178 cache->fast_access[(int)cache->cache[i].data[0]] == -1)
179 cache->fast_access[(int)cache->cache[i].data[0]] = i;
182 cache->sorted = TRUE;
185 /* Find ID Cache entry by data. The data maybe anything that must
186 match exactly. Returns list of cache entries. */
188 int silc_idcache_find_by_data(SilcIDCache cache, char *data,
189 SilcIDCacheList *ret)
192 SilcIDCacheList list;
194 if (!cache || !cache->cache || !data)
197 list = silc_idcache_list_alloc();
200 i = cache->fast_access[(int)data[0]];
204 for (i = i; i < cache->cache_count; i++) {
205 if (cache->sorted && cache->cache[i].data &&
206 cache->cache[i].data[0] != data[0])
209 if (cache->cache[i].data &&
210 !memcmp(cache->cache[i].data, data, strlen(cache->cache[i].data)))
211 silc_idcache_list_add(list, &(cache->cache[i]));
214 if (!silc_idcache_list_count(list))
220 silc_idcache_list_free(list);
225 /* Find ID Cache entry by data. The data maybe anything that must
226 match exactly. Returns one cache entry. */
228 int silc_idcache_find_by_data_one(SilcIDCache cache, char *data,
229 SilcIDCacheEntry *ret)
233 if (!cache || !cache->cache || !data)
237 i = cache->fast_access[(int)data[0]];
241 for (i = i; i < cache->cache_count; i++)
242 if (cache->cache[i].data &&
243 !memcmp(cache->cache[i].data, data, strlen(cache->cache[i].data))) {
245 *ret = &(cache->cache[i]);
252 /* Find ID Cache entry by data, loosely. The data don't have to be 100%
253 match. This ignores data case-sensitivity when searching with this
254 function. Returns list of cache entries. */
256 int silc_idcache_find_by_data_loose(SilcIDCache cache, char *data,
257 SilcIDCacheList *ret)
260 SilcIDCacheList list;
262 if (!cache || !cache->cache || !data)
265 list = silc_idcache_list_alloc();
267 c = tolower((int)data[0]);
270 i = cache->fast_access[c];
274 for (i = i; i < cache->cache_count; i++) {
275 if (cache->sorted && cache->cache[i].data &&
276 cache->cache[i].data[0] != (char)c)
279 if (cache->cache[i].data &&
280 !strcasecmp(cache->cache[i].data, data))
281 silc_idcache_list_add(list, &(cache->cache[i]));
285 c = toupper((int)data[0]);
286 i = cache->fast_access[c];
288 for (i = i; i < cache->cache_count; i++) {
289 if (cache->sorted && cache->cache[i].data &&
290 cache->cache[i].data[0] != (char)c)
293 if (cache->cache[i].data &&
294 !strcasecmp(cache->cache[i].data, data))
295 silc_idcache_list_add(list, &(cache->cache[i]));
299 if (!silc_idcache_list_count(list))
305 silc_idcache_list_free(list);
310 /* Find ID Cache entry by ID. Returns list of cache entries. */
311 /* XXX this may be useless, need for list really? */
313 int silc_idcache_find_by_id(SilcIDCache cache, void *id, SilcIdType type,
314 SilcIDCacheList *ret)
317 SilcIDCacheList list;
319 if (!cache || !cache->cache || !id)
322 id_len = silc_id_get_len(type);
324 list = silc_idcache_list_alloc();
326 for (i = 0; i < cache->cache_count; i++)
327 if (cache->cache[i].id && !memcmp(cache->cache[i].id, id, id_len))
328 silc_idcache_list_add(list, &(cache->cache[i]));
330 if (!silc_idcache_list_count(list))
336 silc_idcache_list_free(list);
341 /* Find ID Cache entry by ID. Returns one cache entry. */
343 int silc_idcache_find_by_id_one(SilcIDCache cache, void *id, SilcIdType type,
344 SilcIDCacheEntry *ret)
348 if (!cache || !cache->cache || !id)
351 id_len = silc_id_get_len(type);
353 for (i = 0; i < cache->cache_count; i++)
354 if (cache->cache[i].id && !memcmp(cache->cache[i].id, id, id_len)) {
356 *ret = &(cache->cache[i]);
363 /* Finds cache entry by context. */
365 int silc_idcache_find_by_context(SilcIDCache cache, void *context,
366 SilcIDCacheEntry *ret)
370 if (!cache || !cache->cache || !context)
373 for (i = 0; i < cache->cache_count; i++)
374 if (cache->cache[i].context && cache->cache[i].context == context) {
376 *ret = &(cache->cache[i]);
383 /* Add new entry to the cache. Returns TRUE or FALSE. If `sort' is TRUE
384 then the cache is sorted after the new entry has been added. The
385 cache must be sorted in order for the fast access feature to work,
386 however, it is not mandatory. */
388 int silc_idcache_add(SilcIDCache cache, char *data, SilcIdType id_type,
389 void *id, void *context, int sort)
393 unsigned long curtime = time(NULL);
396 if (!cache || !cache->cache)
399 SILC_LOG_DEBUG(("Adding cache entry"));
402 count = cache->cache_count;
405 c = silc_calloc(5, sizeof(*c));
409 /* See if it exists already */
410 /* XXX this slows down this function. */
411 if (silc_idcache_find_by_id(cache, id, id_type, NULL))
414 for (i = 0; i < count; i++) {
415 if (c[i].data == NULL) {
419 c[i].expire = curtime + SILC_ID_CACHE_EXPIRE;
420 c[i].context = context;
426 c = silc_realloc(c, sizeof(*c) * (count + 5));
427 for (i = count; i < count + 5; i++) {
431 c[count].data = data;
432 c[count].type = id_type;
434 c[count].expire = curtime + SILC_ID_CACHE_EXPIRE;
435 c[count].context = context;
440 cache->cache_count = count;
441 cache->sorted = sort;
444 silc_idcache_sort_by_data(cache);
449 /* Delete cache entry from cache. */
452 int silc_idcache_del(SilcIDCache cache, SilcIDCacheEntry old)
460 int silc_idcache_del_by_data(SilcIDCache cache, char *data)
466 /* Deletes ID cache entry by ID. */
468 int silc_idcache_del_by_id(SilcIDCache cache, SilcIdType type, void *id)
472 if (!cache || !cache->cache || !id)
475 id_len = silc_id_get_len(type);
477 for (i = 0; i < cache->cache_count; i++)
478 if (cache->cache[i].id && !memcmp(cache->cache[i].id, id, id_len)) {
479 cache->cache[i].id = NULL;
480 cache->cache[i].data = NULL;
481 cache->cache[i].type = 0;
482 cache->cache[i].context = NULL;
489 /* Deletes all ID entries from cache. Free's memory as well. */
491 int silc_idcache_del_all(SilcIDCache cache)
493 if (!cache || !cache->cache)
496 silc_free(cache->cache);
498 cache->cache_count = 0;
503 /* Purges the cache by removing expired cache entires. This does not
504 free any memory though. */
506 int silc_idcache_purge(SilcIDCache cache)
509 unsigned long curtime = time(NULL);
512 if (!cache || !cache->cache)
517 for (i = 0; i < cache->cache_count; i++) {
519 (c[i].expire == 0 || c[i].expire < curtime)) {
531 /* Allocates ID cache list. */
533 static SilcIDCacheList silc_idcache_list_alloc()
535 SilcIDCacheList list;
537 list = silc_calloc(1, sizeof(*list));
542 /* Adds cache entry to the ID cache list. If needed reallocates memory
545 static void silc_idcache_list_add(SilcIDCacheList list, SilcIDCacheEntry cache)
549 /* Try to add to static cache */
550 if (!list->cache_dyn_count)
551 for (i = 0; i < sizeof(list->cache); i++) {
552 if (!list->cache[i]) {
553 list->cache[i] = cache;
559 /* Static cache is full, allocate dynamic cache */
560 for (i = 0; i < list->cache_dyn_count; i++) {
561 if (!list->cache_dyn[i]) {
562 list->cache_dyn[i] = cache;
568 if (i >= list->cache_dyn_count) {
572 list->cache_dyn = silc_realloc(list->cache_dyn,
573 sizeof(*list->cache) * (i));
575 /* NULL the reallocated area */
576 for (k = list->cache_dyn_count; k < i; k++)
577 list->cache_dyn[k] = NULL;
579 list->cache_dyn[list->cache_dyn_count] = cache;
580 list->cache_dyn_count = i;
585 /* Returns number of cache entries in the ID cache list. */
587 int silc_idcache_list_count(SilcIDCacheList list)
589 return list->cache_count;
592 /* Returns first entry from the ID cache list. */
594 int silc_idcache_list_first(SilcIDCacheList list, SilcIDCacheEntry *ret)
598 if (!list->cache[list->pos])
602 *ret = list->cache[list->pos];
607 /* Returns next entry from the ID cache list. */
609 int silc_idcache_list_next(SilcIDCacheList list, SilcIDCacheEntry *ret)
614 if (list->pos >= sizeof(list->cache)) {
619 if (dyn && list->pos >= list->cache_dyn_count)
622 if (!dyn && !list->cache[list->pos])
625 if (dyn && !list->cache_dyn[list->pos])
630 *ret = list->cache[list->pos];
632 *ret = list->cache_dyn[list->pos];
638 /* Free's ID cache list. User must free the list object returned by
639 any of the searching functions. */
641 void silc_idcache_list_free(SilcIDCacheList list)
645 silc_free(list->cache_dyn);