diff options
Diffstat (limited to 'cache.c')
-rw-r--r-- | cache.c | 139 |
1 files changed, 110 insertions, 29 deletions
@@ -8,25 +8,30 @@ static void remove_entry(flxCache *c, flxCacheEntry *e, gboolean remove_from_has if (remove_from_hash_table) { flxCacheEntry *t; - t = g_hash_table_lookup(c->hash_table, &e->record->key); + t = g_hash_table_lookup(c->hash_table, e->record->key); FLX_LLIST_REMOVE(flxCacheEntry, by_name, t, e); if (t) - g_hash_table_replace(c->hash_table, &t->record->key, t); + g_hash_table_replace(c->hash_table, t->record->key, t); else - g_hash_table_remove(c->hash_table, &e->record->key); + g_hash_table_remove(c->hash_table, e->record->key); } flx_record_unref(e->record); + + if (e->time_event) + flx_time_event_queue_remove(c->server->time_event_queue, e->time_event); + g_free(e); } -flxCache *flx_cache_new(flxServer *server, flxInterface *iface) { +flxCache *flx_cache_new(flxServer *server, flxInterface *iface, guchar protocol) { flxCache *c; g_assert(server); c = g_new(flxCache, 1); c->server = server; c->interface = iface; + c->protocol = protocol; c->hash_table = g_hash_table_new((GHashFunc) flx_key_hash, (GEqualFunc) flx_key_equal); return c; @@ -71,58 +76,134 @@ flxCacheEntry *flx_cache_lookup_record(flxCache *c, flxRecord *r) { return NULL; } +static void next_expiry(flxCache *c, flxCacheEntry *e, guint percent); + +static void elapse_func(flxTimeEvent *t, void *userdata) { + flxCacheEntry *e = userdata; + + g_assert(t); + g_assert(e); + + if (e->state == FLX_CACHE_FINAL) { + remove_entry(e->cache, e, TRUE); + g_message("Removing entry from cache due to expiration"); + } else { + guint percent = 0; + + switch (e->state) { + case FLX_CACHE_VALID: + e->state = FLX_CACHE_EXPIRY1; + percent = 85; + break; + + case FLX_CACHE_EXPIRY1: + e->state = FLX_CACHE_EXPIRY2; + percent = 90; + break; + case FLX_CACHE_EXPIRY2: + e->state = FLX_CACHE_EXPIRY3; + percent = 95; + break; + + case FLX_CACHE_EXPIRY3: + e->state = FLX_CACHE_FINAL; + percent = 100; + break; + + default: + ; + } + + g_assert(percent > 0); + + g_message("Requesting cache entry update at %i%%.", percent); + + /* Request a cache update */ + flx_interface_post_query(e->cache->interface, e->cache->protocol, e->record->key); + + /* Check again later */ + next_expiry(e->cache, e, percent); + } +} + +static void next_expiry(flxCache *c, flxCacheEntry *e, guint percent) { + gulong usec; + + g_assert(c); + g_assert(e); + g_assert(percent > 0 && percent <= 100); + + e->expiry = e->timestamp; + + usec = e->record->ttl * 10000; + + /* 2% jitter */ + usec = g_random_int_range(usec*percent, usec*(percent+2)); + + g_time_val_add(&e->expiry, usec); + + if (e->time_event) + flx_time_event_queue_update(c->server->time_event_queue, e->time_event, &e->expiry); + else + e->time_event = flx_time_event_queue_add(c->server->time_event_queue, &e->expiry, elapse_func, e); +} + flxCacheEntry *flx_cache_update(flxCache *c, flxRecord *r, gboolean unique, const flxAddress *a) { flxCacheEntry *e, *t; + gchar *txt; g_assert(c); - g_assert(r); + g_assert(r && r->ref >= 1); + + g_message("cache update: %s", (txt = flx_record_to_string(r))); + g_free(txt); if ((t = e = flx_cache_lookup_key(c, r->key))) { +/* g_message("found prev cache entry"); */ + if (unique) { - flxCacheEntry *n; /* Drop all entries but the first which we replace */ - while (e->by_name_next) remove_entry(c, e->by_name_next, TRUE); - g_free(e->record->data); - e->record->data = g_memdup(r->data, r->size); - e->record->size = r->size; - e->record->ttl = r->ttl; - } else { /* Look for exactly the same entry */ - - for (; e; e = e->by_name_next) { - if (e->record->size == r->size && - !memcmp(e->record->data, r->data, r->size)) { - - /* We found it, so let's update the TTL */ - e->record->ttl = r->ttl; + for (; e; e = e->by_name_next) + if (flx_record_equal(e->record, r)) break; - } - } } } + + if (e) { + +/* g_message("found matching cache entry"); */ + + /* We are the first in the linked list so let's replace the hash table key with the new one */ + if (e->by_name_prev == NULL) + g_hash_table_replace(c->hash_table, r->key, e); + + /* Update the record */ + flx_record_unref(e->record); + e->record = flx_record_ref(r); - if (!e) { + + } else { /* No entry found, therefore we create a new one */ + +/* g_message("couldn't find matching cache entry"); */ e = g_new(flxCacheEntry, 1); - e->node = NULL; - + e->cache = c; + e->time_event = NULL; e->record = flx_record_ref(r); FLX_LLIST_PREPEND(flxCacheEntry, by_name, t, e); - g_hash_table_replace(c->hash_table, e->record->key, e); + g_hash_table_replace(c->hash_table, e->record->key, t); } e->origin = *a; - g_get_current_time(&e->timestamp); - e->expiry = e->timestamp; - g_time_val_add(&e->expiry, e->record->ttl * 1000000); - + next_expiry(c, e, 80); e->state = FLX_CACHE_VALID; return e; |