diff --git a/cache.c b/cache.c new file mode 100644 index 00000000..c9a6e85d --- /dev/null +++ b/cache.c @@ -0,0 +1,125 @@ +#include "uwsgi.h" + +extern struct uwsgi_server uwsgi; + +uint32_t djb33x_hash(char *key, int keylen) { + + register uint32_t hash = 5381; + int i; + + for(i=0;i %d %d %d %.*s %d\n", i, uwsgi.cache_items[i].used, uwsgi.cache_items[i].djbhash, uwsgi.cache_items[i].keysize, uwsgi.cache_items[i].keysize, uwsgi.cache_items[i].key, uwsgi.cache_items[i].valsize); + if (uwsgi.cache_items[i].used == 0) break; + + // hash comparison + if (uwsgi.cache_items[i].djbhash != hash) continue; + + // keysize comparison + if (uwsgi.cache_items[i].keysize != keylen) continue ; + + // key comparison + if (!memcmp(uwsgi.cache_items[i].key, key, keylen)) return i; + + } + + return 0; +} + + +char *uwsgi_cache_get(char *key, uint16_t keylen, uint16_t *valsize) { + + uint16_t index = uwsgi_cache_get_index(key, keylen); + + /* is locking needed for reading ? + I do not think so: + + case1 => reading during delete -> the worst case is receiving corrupted data for a item that must not exists + case2 => reading during set -> the worst case is receiving corrupted data for an incomplete item + + */ + + if (index) { + *valsize = uwsgi.cache_items[index].valsize; + // no locking needed, as this is only an hint + uwsgi.cache_items[index].hits++; + return uwsgi.cache+(index*32768); + } + + return NULL; +} + +int uwsgi_cache_del(char *key, uint16_t keylen) { + + uint16_t index = 0; + struct uwsgi_cache_item *uci; + int ret = -1; + + uwsgi_lock(uwsgi.cache_lock); + + index = uwsgi_cache_get_index(key, keylen); + if (index) { + uci = &uwsgi.cache_items[index] ; + uci->keysize = 0; + uwsgi.shared->cache_first_available_item_tmp = uwsgi.shared->cache_first_available_item; + uwsgi.shared->cache_first_available_item = index; + ret = 0; + } + + uwsgi_unlock(uwsgi.cache_lock); + + return ret; +} + +int uwsgi_cache_set(char *key, uint16_t keylen, char *val, uint16_t vallen, uint64_t expires) { + + uint16_t index = 0 ; + struct uwsgi_cache_item *uci; + int ret = -1; + if (!keylen || !vallen) return -1; + if (keylen > UWSGI_CACHE_MAX_KEY_SIZE) return -1; + + uwsgi_lock(uwsgi.cache_lock); + if (uwsgi.shared->cache_first_available_item >= uwsgi.cache_max_items) goto end; + + index = uwsgi_cache_get_index(key, keylen); + if (!index) { + index = uwsgi.shared->cache_first_available_item; + uci = &uwsgi.cache_items[index] ; + uci->expires = expires; + uci->djbhash = djb33x_hash(key, keylen); + uci->hits = 0; + uci->used = 1; + memcpy(uci->key, key, keylen); + memcpy(uwsgi.cache+(index*32768), val, vallen); + // set this as late as possibile (to minimize locking) + uci->valsize = vallen; + uci->keysize = keylen; + ret = 0; + if (uwsgi.shared->cache_first_available_item_tmp) { + uwsgi.shared->cache_first_available_item = uwsgi.shared->cache_first_available_item_tmp ; + uwsgi.shared->cache_first_available_item_tmp = 0; + } + else { + uwsgi.shared->cache_first_available_item++; + } + } + +end: + uwsgi_unlock(uwsgi.cache_lock); + + return ret; + +}