[Pkg-clamav-commits] [SCM] Debian repository for ClamAV branch, debian/unstable, updated. debian/0.95+dfsg-1-6156-g094ec9b
Török Edvin
edwin at clamav.net
Sun Apr 4 01:14:14 UTC 2010
The following commit has been merged in the debian/unstable branch:
commit a99a6040dde48e6a650a444c744369c3e738df97
Author: Török Edvin <edwin at clamav.net>
Date: Wed Jan 6 19:32:34 2010 +0200
a fixed size, LRU hash-based cache.
diff --git a/libclamav/cache.c b/libclamav/cache.c
index 290b212..834fe4c 100644
--- a/libclamav/cache.c
+++ b/libclamav/cache.c
@@ -1,10 +1,10 @@
-#include <string.h>
-#include <stdlib.h>
-#include <pthread.h>
-
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
+#include <string.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <assert.h>
#include "md5.h"
#include "mpool.h"
@@ -14,7 +14,6 @@
#define CACHE_PERTURB 10
/* 1/10th */
-
static mpool_t *mempool = NULL;
static struct CACHE {
struct CACHE_ENTRY {
@@ -183,3 +182,278 @@ int cache_check(unsigned char *hash, cli_ctx *ctx) {
cli_md5_final(hash, &md5);
return cache_lookup_hash(hash, ctx);
}
+
+struct cache_key {
+ char digest[16];
+ uint32_t size; /* 0 is used to mark an empty hash slot! */
+ struct cache_key *lru_next, *lru_prev;
+};
+
+struct cache_set {
+ struct cache_key *data;
+ size_t capacity;
+ size_t maxelements;/* considering load factor */
+ size_t elements;
+ size_t version;
+ struct cache_key *lru_head, *lru_tail;
+ pthread_mutex_t mutex;
+};
+
+#define CACHE_INVALID_VERSION ~0u
+
+/* size must be power of 2! */
+static int cacheset_init(struct cache_set* map, size_t maxsize, uint8_t loadfactor)
+{
+ map->data = cli_calloc(maxsize, sizeof(*map->data));
+ if (!map->data)
+ return CL_EMEM;
+ map->capacity = maxsize;
+ map->maxelements = loadfactor*maxsize / 100;
+ map->elements = 0;
+ map->version = CACHE_INVALID_VERSION;
+ map->lru_head = map->lru_tail = NULL;
+ if (pthread_mutex_init(&map->mutex, NULL)) {
+ cli_errmsg("mutex init fail\n");
+ return CL_EMEM;
+ }
+}
+
+static void cacheset_destroy(struct cache_set *map)
+{
+ pthread_mutex_destroy(&map->mutex);
+ free(map->data);
+}
+
+static void cacheset_acquire(struct cache_set *map)
+{
+ pthread_mutex_lock(&map->mutex);
+}
+
+static void cache_setversion(struct cache_set* map, uint32_t version)
+{
+ unsigned i;
+ if (map->version == version)
+ return;
+ map->version = version;
+ map->elements = 0;/* all elements have expired now */
+ for (i=0;i<map->capacity;i++)
+ map->data[i].size = 0;
+ map->lru_head = map->lru_tail = NULL;
+}
+
+static void cacheset_lru_remove(struct cache_set *map, size_t howmany)
+{
+ while (howmany--) {
+ struct cache_key *old;
+ assert(map->lru_head);
+ assert(!old->lru_prev);
+ // Remove a key from the head of the list
+ old = map->lru_head;
+ map->lru_head = old->lru_next;
+ old->size = 0; /* this slot is now empty */
+ if (old == map->lru_tail)
+ map->lru_tail = 0;
+ }
+}
+
+static inline uint32_t hash32shift(uint32_t key)
+{
+ key = ~key + (key << 15);
+ key = key ^ (key >> 12);
+ key = key + (key << 2);
+ key = key ^ (key >> 4);
+ key = (key + (key << 3)) + (key << 11);
+ key = key ^ (key >> 16);
+ return key;
+}
+
+static inline size_t hash(const unsigned char* k,const size_t len,const size_t SIZE)
+{
+ size_t Hash = 1;
+ size_t i;
+ for(i=0;i<len;i++) {
+ /* a simple add is good, because we use the mixing function below */
+ Hash += k[i];
+ /* mixing function */
+ Hash = hash32shift(Hash);
+ }
+ /* SIZE is power of 2 */
+ return Hash & (SIZE - 1);
+}
+
+int cacheset_lookup_internal(struct cache_set *map, const struct cache_key *key,
+ uint32_t *insert_pos)
+{
+ uint32_t idx = hash((const unsigned char*)key, sizeof(*key), map->capacity);
+ uint32_t tries = 0;
+ struct cache_key *k = &map->data[idx];
+ while (k->size) {
+ if (k->size == key->size &&
+ !memcmp(k->digest, key, 16)) {
+ /* found key */
+ *insert_pos = idx;
+ return 1;
+ }
+ idx = (idx + tries++)&(map->capacity-1);
+ k = &map->data[idx];
+ }
+ /* found empty pos */
+ *insert_pos = idx;
+ return 0;
+}
+
+static inline void lru_remove(struct cache_set *map, struct cache_key *newkey)
+{
+ if (newkey->lru_next)
+ newkey->lru_next->lru_prev = newkey->lru_prev;
+ if (newkey->lru_prev)
+ newkey->lru_prev->lru_next = newkey->lru_next;
+ if (newkey == map->lru_head)
+ map->lru_head = newkey->lru_next;
+}
+
+static inline void lru_addtail(struct cache_set *map, struct cache_key *newkey)
+{
+ if (!map->lru_head)
+ map->lru_head = newkey;
+ if (map->lru_tail)
+ map->lru_tail->lru_next = newkey;
+ newkey->lru_next = NULL;
+ newkey->lru_prev = map->lru_tail;
+ map->lru_tail = newkey;
+}
+
+static void cacheset_add(struct cache_set *map, const struct cache_key *key)
+{
+ int ret;
+ uint32_t pos;
+ struct cache_key *newkey;
+ if (map->elements >= map->maxelements)
+ cacheset_lru_remove(map, 1);
+ assert(map->elements < map->maxelements);
+
+ ret = cacheset_lookup_internal(map, key, &pos);
+ newkey = &map->data[pos];
+ if (ret) {
+ /* was already added, remove from LRU list */
+ lru_remove(map, newkey);
+ }
+ /* add new key to tail of LRU list */
+ lru_addtail(map, newkey);
+
+ map->elements++;
+
+ assert(pos < map->maxelements);
+
+ memcpy(&map->data[pos], key, sizeof(*key));
+}
+
+static int cacheset_lookup(struct cache_set *map, const struct cache_key *key)
+{
+ struct cache_key *newkey;
+ int ret;
+ uint32_t pos;
+ ret = cacheset_lookup_internal(map, key, &pos);
+ if (!ret)
+ return CACHE_INVALID_VERSION;
+ newkey = &map->data[pos];
+ /* update LRU position: move to tail */
+ lru_remove(map, newkey);
+ lru_addtail(map, newkey);
+
+ return map->version;
+}
+
+static void cacheset_release(struct cache_set *map)
+{
+ pthread_mutex_unlock(&map->mutex);
+}
+
+#if 0
+int main(int argc, char **argv)
+{
+ struct cache_key key;
+ struct cache_set map;
+ cacheset_init(&map, 256, 80);
+ cacheset_acquire(&map);
+ cache_setversion(&map, 10);
+
+ key.size = 1024;
+ memcpy(key.digest, "1234567890123456", 16);
+ cacheset_add(&map, &key);
+ memcpy(key.digest, "1234567890123457", 16);
+ cacheset_add(&map, &key);
+ memcpy(key.digest, "0123456789012345", 16);
+ cacheset_add(&map, &key);
+
+ key.size = 1024;
+ memcpy(key.digest, "1234567890123456", 16);
+ if (cacheset_lookup(&map, &key) != 10)
+ abort();
+ memcpy(key.digest, "1234567890123456", 16);
+ if (cacheset_lookup(&map, &key) != 10)
+ abort();
+ memcpy(key.digest, "1234567890123457", 16);
+ if (cacheset_lookup(&map, &key) != 10)
+ abort();
+ memcpy(key.digest, "0123456789012345", 16);
+ if (cacheset_lookup(&map, &key) != 10)
+ abort();
+ memcpy(key.digest, "0123456789012346", 16);
+ if (cacheset_lookup(&map, &key) == 10)
+ abort();
+
+ cache_setversion(&map, 1);
+ memcpy(key.digest, "1234567890123456", 16);
+ if (cacheset_lookup(&map, &key) != CACHE_INVALID_VERSION)
+ abort();
+ memcpy(key.digest, "1234567890123456", 16);
+ if (cacheset_lookup(&map, &key) != CACHE_INVALID_VERSION)
+ abort();
+ memcpy(key.digest, "1234567890123457", 16);
+ if (cacheset_lookup(&map, &key) != CACHE_INVALID_VERSION)
+ abort();
+ memcpy(key.digest, "0123456789012345", 16);
+ if (cacheset_lookup(&map, &key) != CACHE_INVALID_VERSION)
+ abort();
+
+ cacheset_release(&map);
+
+ cacheset_destroy(&map);
+
+ cacheset_init(&map, 8, 50);
+ cacheset_acquire(&map);
+ cache_setversion(&map, 10);
+
+ key.size = 416;
+ memcpy(key.digest, "1234567890123456", 16);
+ cacheset_add(&map, &key);
+ memcpy(key.digest, "1234567890123457", 16);
+ cacheset_add(&map, &key);
+ memcpy(key.digest, "1234567890123459", 16);
+ cacheset_add(&map, &key);
+ key.size = 400;
+ memcpy(key.digest, "1234567890123450", 16);
+ cacheset_add(&map, &key);
+
+ key.size = 416;
+ memcpy(key.digest, "1234567890123456", 16);
+ if (cacheset_lookup(&map, &key) != 10)
+ abort();
+ if (cacheset_lookup(&map, &key) != 10)
+ abort();
+ if (cacheset_lookup(&map, &key) != 10)
+ abort();
+
+ key.size = 500;
+ cacheset_add(&map, &key);
+ memcpy(key.digest, "1234567890123457", 16);
+ if (cacheset_lookup(&map, &key) == 10)
+ abort();
+
+ cacheset_release(&map);
+ cacheset_destroy(&map);
+
+ return 0;
+}
+#endif
--
Debian repository for ClamAV
More information about the Pkg-clamav-commits
mailing list