5 static void remove_entry(flxCache *c, flxCacheEntry *e, gboolean remove_from_hash_table) {
9 if (remove_from_hash_table) {
11 t = g_hash_table_lookup(c->hash_table, e->record->key);
12 FLX_LLIST_REMOVE(flxCacheEntry, by_name, t, e);
14 g_hash_table_replace(c->hash_table, t->record->key, t);
16 g_hash_table_remove(c->hash_table, e->record->key);
19 flx_record_unref(e->record);
22 flx_time_event_queue_remove(c->server->time_event_queue, e->time_event);
27 flxCache *flx_cache_new(flxServer *server, flxInterface *iface, guchar protocol) {
31 c = g_new(flxCache, 1);
34 c->protocol = protocol;
35 c->hash_table = g_hash_table_new((GHashFunc) flx_key_hash, (GEqualFunc) flx_key_equal);
40 gboolean remove_func(gpointer key, gpointer value, gpointer user_data) {
41 flxCacheEntry *e, *next;
43 for (e = value; e; e = next) {
44 next = e->by_name_next;
45 remove_entry(user_data, e, FALSE);
51 void flx_cache_free(flxCache *c) {
54 g_hash_table_foreach_remove(c->hash_table, remove_func, c);
55 g_hash_table_destroy(c->hash_table);
60 flxCacheEntry *flx_cache_lookup_key(flxCache *c, flxKey *k) {
64 return g_hash_table_lookup(c->hash_table, k);
67 flxCacheEntry *flx_cache_lookup_record(flxCache *c, flxRecord *r) {
72 for (e = flx_cache_lookup_key(c, r->key); e; e = e->by_name_next)
73 if (e->record->size == r->size && !memcmp(e->record->data, r->data, r->size))
79 static void next_expiry(flxCache *c, flxCacheEntry *e, guint percent);
81 static void elapse_func(flxTimeEvent *t, void *userdata) {
82 flxCacheEntry *e = userdata;
87 if (e->state == FLX_CACHE_FINAL) {
88 remove_entry(e->cache, e, TRUE);
89 g_message("Removing entry from cache due to expiration");
95 e->state = FLX_CACHE_EXPIRY1;
99 case FLX_CACHE_EXPIRY1:
100 e->state = FLX_CACHE_EXPIRY2;
103 case FLX_CACHE_EXPIRY2:
104 e->state = FLX_CACHE_EXPIRY3;
108 case FLX_CACHE_EXPIRY3:
109 e->state = FLX_CACHE_FINAL;
117 g_assert(percent > 0);
119 g_message("Requesting cache entry update at %i%%.", percent);
121 /* Request a cache update */
122 flx_interface_post_query(e->cache->interface, e->cache->protocol, e->record->key);
124 /* Check again later */
125 next_expiry(e->cache, e, percent);
129 static void next_expiry(flxCache *c, flxCacheEntry *e, guint percent) {
134 g_assert(percent > 0 && percent <= 100);
136 e->expiry = e->timestamp;
138 usec = e->record->ttl * 10000;
141 usec = g_random_int_range(usec*percent, usec*(percent+2));
143 g_time_val_add(&e->expiry, usec);
146 flx_time_event_queue_update(c->server->time_event_queue, e->time_event, &e->expiry);
148 e->time_event = flx_time_event_queue_add(c->server->time_event_queue, &e->expiry, elapse_func, e);
151 flxCacheEntry *flx_cache_update(flxCache *c, flxRecord *r, gboolean unique, const flxAddress *a) {
152 flxCacheEntry *e, *t;
156 g_assert(r && r->ref >= 1);
158 g_message("cache update: %s", (txt = flx_record_to_string(r)));
161 if ((t = e = flx_cache_lookup_key(c, r->key))) {
163 /* g_message("found prev cache entry"); */
166 /* Drop all entries but the first which we replace */
167 while (e->by_name_next)
168 remove_entry(c, e->by_name_next, TRUE);
171 /* Look for exactly the same entry */
172 for (; e; e = e->by_name_next)
173 if (flx_record_equal(e->record, r))
180 /* g_message("found matching cache entry"); */
182 /* We are the first in the linked list so let's replace the hash table key with the new one */
183 if (e->by_name_prev == NULL)
184 g_hash_table_replace(c->hash_table, r->key, e);
186 /* Update the record */
187 flx_record_unref(e->record);
188 e->record = flx_record_ref(r);
192 /* No entry found, therefore we create a new one */
194 /* g_message("couldn't find matching cache entry"); */
196 e = g_new(flxCacheEntry, 1);
198 e->time_event = NULL;
199 e->record = flx_record_ref(r);
200 FLX_LLIST_PREPEND(flxCacheEntry, by_name, t, e);
201 g_hash_table_replace(c->hash_table, e->record->key, t);
205 g_get_current_time(&e->timestamp);
206 next_expiry(c, e, 80);
207 e->state = FLX_CACHE_VALID;
212 void flx_cache_drop_key(flxCache *c, flxKey *k) {
218 while ((e = flx_cache_lookup_key(c, k)))
219 remove_entry(c, e, TRUE);
222 void flx_cache_drop_record(flxCache *c, flxRecord *r) {
228 if ((e = flx_cache_lookup_record(c, r)))
229 remove_entry(c, e, TRUE);
232 static void func(gpointer key, gpointer data, gpointer userdata) {
233 flxCacheEntry *e = data;
238 s = flx_key_to_string(k);
239 t = flx_record_to_string(e->record);
241 fprintf((FILE*) userdata, "%s %s\n", s, t);
247 void flx_cache_dump(flxCache *c, FILE *f) {
251 fprintf(f, ";;; CACHE DUMP FOLLOWS ;;;\n");
252 g_hash_table_foreach(c->hash_table, func, f);