[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