2019-05-03 23:20:47 +08:00
|
|
|
#include <uthash.h>
|
|
|
|
|
2019-08-10 07:56:04 +08:00
|
|
|
#include "compiler.h"
|
2019-05-03 23:20:47 +08:00
|
|
|
#include "utils.h"
|
|
|
|
#include "cache.h"
|
|
|
|
|
|
|
|
struct cache_entry {
|
|
|
|
char *key;
|
|
|
|
void *value;
|
|
|
|
UT_hash_handle hh;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct cache {
|
|
|
|
cache_getter_t getter;
|
|
|
|
cache_free_t free;
|
|
|
|
void *user_data;
|
|
|
|
struct cache_entry *entries;
|
|
|
|
};
|
|
|
|
|
2019-05-06 07:28:22 +08:00
|
|
|
void *cache_get(struct cache *c, const char *key, int *err) {
|
2019-05-03 23:20:47 +08:00
|
|
|
struct cache_entry *e;
|
|
|
|
HASH_FIND_STR(c->entries, key, e);
|
|
|
|
if (e) {
|
|
|
|
return e->value;
|
|
|
|
}
|
|
|
|
|
2019-05-06 07:28:22 +08:00
|
|
|
int tmperr;
|
|
|
|
if (!err) {
|
|
|
|
err = &tmperr;
|
|
|
|
}
|
|
|
|
|
|
|
|
*err = 0;
|
2019-05-03 23:20:47 +08:00
|
|
|
e = ccalloc(1, struct cache_entry);
|
|
|
|
e->key = strdup(key);
|
2019-05-06 07:28:22 +08:00
|
|
|
e->value = c->getter(c->user_data, key, err);
|
|
|
|
if (*err) {
|
|
|
|
free(e->key);
|
|
|
|
free(e);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2019-05-03 23:20:47 +08:00
|
|
|
HASH_ADD_STR(c->entries, key, e);
|
|
|
|
return e->value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void _cache_invalidate(struct cache *c, struct cache_entry *e) {
|
|
|
|
if (c->free) {
|
|
|
|
c->free(c->user_data, e->value);
|
|
|
|
}
|
2019-05-05 11:55:42 +08:00
|
|
|
free(e->key);
|
2019-05-03 23:20:47 +08:00
|
|
|
HASH_DEL(c->entries, e);
|
|
|
|
free(e);
|
|
|
|
}
|
|
|
|
|
|
|
|
void cache_invalidate(struct cache *c, const char *key) {
|
|
|
|
struct cache_entry *e;
|
|
|
|
HASH_FIND_STR(c->entries, key, e);
|
|
|
|
|
|
|
|
if (e) {
|
|
|
|
_cache_invalidate(c, e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void cache_invalidate_all(struct cache *c) {
|
|
|
|
struct cache_entry *e, *tmpe;
|
|
|
|
HASH_ITER(hh, c->entries, e, tmpe) {
|
|
|
|
_cache_invalidate(c, e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void *cache_free(struct cache *c) {
|
|
|
|
void *ret = c->user_data;
|
|
|
|
cache_invalidate_all(c);
|
|
|
|
free(c);
|
|
|
|
return ret;
|
|
|
|
}
|
2019-05-05 11:55:42 +08:00
|
|
|
|
|
|
|
struct cache *new_cache(void *ud, cache_getter_t getter, cache_free_t f) {
|
|
|
|
auto c = ccalloc(1, struct cache);
|
|
|
|
c->user_data = ud;
|
|
|
|
c->getter = getter;
|
|
|
|
c->free = f;
|
|
|
|
return c;
|
|
|
|
}
|