5 static void remove_entry(flxCache *c, flxCacheEntry *e, gboolean remove_from_hash_table) {
9 g_message("remvoin from cache: %p %p", c, e);
11 if (remove_from_hash_table) {
13 t = g_hash_table_lookup(c->hash_table, e->record->key);
14 FLX_LLIST_REMOVE(flxCacheEntry, by_name, t, e);
16 g_hash_table_replace(c->hash_table, t->record->key, t);
18 g_hash_table_remove(c->hash_table, e->record->key);
21 flx_record_unref(e->record);
24 flx_time_event_queue_remove(c->server->time_event_queue, e->time_event);
29 flxCache *flx_cache_new(flxServer *server, flxInterface *iface) {
33 c = g_new(flxCache, 1);
36 c->hash_table = g_hash_table_new((GHashFunc) flx_key_hash, (GEqualFunc) flx_key_equal);
41 gboolean remove_func(gpointer key, gpointer value, gpointer user_data) {
42 flxCacheEntry *e, *next;
44 for (e = value; e; e = next) {
45 next = e->by_name_next;
46 remove_entry(user_data, e, FALSE);
52 void flx_cache_free(flxCache *c) {
55 g_hash_table_foreach_remove(c->hash_table, remove_func, c);
56 g_hash_table_destroy(c->hash_table);
61 flxCacheEntry *flx_cache_lookup_key(flxCache *c, flxKey *k) {
65 return g_hash_table_lookup(c->hash_table, k);
68 flxCacheEntry *flx_cache_lookup_record(flxCache *c, flxRecord *r) {
73 for (e = flx_cache_lookup_key(c, r->key); e; e = e->by_name_next)
74 if (e->record->size == r->size && !memcmp(e->record->data, r->data, r->size))
80 static void next_expiry(flxCache *c, flxCacheEntry *e, guint percent);
82 static void elapse_func(flxTimeEvent *t, void *userdata) {
83 flxCacheEntry *e = userdata;
88 if (e->state == FLX_CACHE_FINAL) {
89 remove_entry(e->cache, e, TRUE);
90 g_message("Removing entry from cache due to expiration");
96 e->state = FLX_CACHE_EXPIRY1;
100 case FLX_CACHE_EXPIRY1:
101 e->state = FLX_CACHE_EXPIRY2;
104 case FLX_CACHE_EXPIRY2:
105 e->state = FLX_CACHE_EXPIRY3;
109 case FLX_CACHE_EXPIRY3:
110 e->state = FLX_CACHE_FINAL;
118 g_assert(percent > 0);
120 g_message("Requesting cache entry update at %i%%.", percent);
122 /* Request a cache update */
123 flx_interface_post_query(e->cache->interface, e->record->key);
125 /* Check again later */
126 next_expiry(e->cache, e, percent);
130 static void next_expiry(flxCache *c, flxCacheEntry *e, guint percent) {
135 g_assert(percent > 0 && percent <= 100);
137 e->expiry = e->timestamp;
139 usec = e->record->ttl * 10000;
142 usec = g_random_int_range(usec*percent, usec*(percent+2));
144 g_time_val_add(&e->expiry, usec);
147 flx_time_event_queue_update(c->server->time_event_queue, e->time_event, &e->expiry);
149 e->time_event = flx_time_event_queue_add(c->server->time_event_queue, &e->expiry, elapse_func, e);
152 flxCacheEntry *flx_cache_update(flxCache *c, flxRecord *r, gboolean unique, const flxAddress *a) {
153 flxCacheEntry *e, *t;
157 g_assert(r && r->ref >= 1);
159 g_message("cache update: %s", (txt = flx_record_to_string(r)));
162 if ((t = e = flx_cache_lookup_key(c, r->key))) {
164 /* g_message("found prev cache entry"); */
167 /* Drop all entries but the first which we replace */
168 while (e->by_name_next)
169 remove_entry(c, e->by_name_next, TRUE);
172 /* Look for exactly the same entry */
173 for (; e; e = e->by_name_next)
174 if (flx_record_equal(e->record, r))
181 /* g_message("found matching cache entry"); */
183 /* We are the first in the linked list so let's replace the hash table key with the new one */
184 if (e->by_name_prev == NULL)
185 g_hash_table_replace(c->hash_table, r->key, e);
187 /* Update the record */
188 flx_record_unref(e->record);
189 e->record = flx_record_ref(r);
193 /* No entry found, therefore we create a new one */
195 /* g_message("couldn't find matching cache entry"); */
197 e = g_new(flxCacheEntry, 1);
199 e->time_event = NULL;
200 e->record = flx_record_ref(r);
201 FLX_LLIST_PREPEND(flxCacheEntry, by_name, t, e);
202 g_hash_table_replace(c->hash_table, e->record->key, t);
206 g_get_current_time(&e->timestamp);
207 next_expiry(c, e, 80);
208 e->state = FLX_CACHE_VALID;
213 void flx_cache_drop_key(flxCache *c, flxKey *k) {
219 while ((e = flx_cache_lookup_key(c, k)))
220 remove_entry(c, e, TRUE);
223 void flx_cache_drop_record(flxCache *c, flxRecord *r) {
229 if ((e = flx_cache_lookup_record(c, r)))
230 remove_entry(c, e, TRUE);
233 static void func(gpointer key, gpointer data, gpointer userdata) {
234 flxCacheEntry *e = data;
238 t = flx_record_to_string(e->record);
239 fprintf((FILE*) userdata, "%s\n", t);
243 void flx_cache_dump(flxCache *c, FILE *f) {
247 fprintf(f, ";;; CACHE DUMP FOLLOWS ;;;\n");
248 g_hash_table_foreach(c->hash_table, func, f);