#include "cookie_cache.h" #include #include #include "compat.h" #include "helpers.h" #include "poller.h" #include "str.h" INLINE void cookie_cache_state_init(struct cookie_cache_state *s) { s->in_use = g_hash_table_new(str_hash, str_equal); s->cookies = g_hash_table_new_full(str_hash, str_equal, free, free); } INLINE void cookie_cache_state_cleanup(struct cookie_cache_state *s) { g_hash_table_destroy(s->cookies); g_hash_table_destroy(s->in_use); } void cookie_cache_init(struct cookie_cache *c) { cookie_cache_state_init(&c->current); cookie_cache_state_init(&c->old); c->swap_time = rtpe_now.tv_sec; mutex_init(&c->lock); cond_init(&c->cond); } /* lock must be held */ static void __cookie_cache_check_swap(struct cookie_cache *c) { if (rtpe_now.tv_sec - c->swap_time >= 30) { g_hash_table_remove_all(c->old.cookies); swap_ptrs(&c->old.cookies, &c->current.cookies); c->swap_time = rtpe_now.tv_sec; } } str *cookie_cache_lookup(struct cookie_cache *c, const str *s) { str *ret; mutex_lock(&c->lock); __cookie_cache_check_swap(c); restart: ret = g_hash_table_lookup(c->current.cookies, s); if (!ret) ret = g_hash_table_lookup(c->old.cookies, s); if (ret) { ret = str_dup(ret); mutex_unlock(&c->lock); return ret; } // is it being worked on right now by another thread? void *p = g_hash_table_lookup(c->current.in_use, s); if (!p) p = g_hash_table_lookup(c->old.in_use, s); if (p) { cond_wait(&c->cond, &c->lock); goto restart; } // caller is required to call cookie_cache_insert or cookie_cache_remove // before `s` runs out of scope g_hash_table_replace(c->current.in_use, (void *) s, (void *) 0x1); mutex_unlock(&c->lock); return NULL; } void cookie_cache_insert(struct cookie_cache *c, const str *s, const str *r) { mutex_lock(&c->lock); g_hash_table_remove(c->current.in_use, s); g_hash_table_remove(c->old.in_use, s); g_hash_table_replace(c->current.cookies, str_dup(s), str_dup(r)); g_hash_table_remove(c->old.cookies, s); cond_broadcast(&c->cond); mutex_unlock(&c->lock); } void cookie_cache_remove(struct cookie_cache *c, const str *s) { mutex_lock(&c->lock); g_hash_table_remove(c->current.in_use, s); g_hash_table_remove(c->old.in_use, s); g_hash_table_remove(c->current.cookies, s); g_hash_table_remove(c->old.cookies, s); cond_broadcast(&c->cond); mutex_unlock(&c->lock); } void cookie_cache_cleanup(struct cookie_cache *c) { cookie_cache_state_cleanup(&c->current); cookie_cache_state_cleanup(&c->old); }