summaryrefslogtreecommitdiffstats
path: root/src/kvstorage.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/kvstorage.c')
-rw-r--r--src/kvstorage.c1560
1 files changed, 0 insertions, 1560 deletions
diff --git a/src/kvstorage.c b/src/kvstorage.c
deleted file mode 100644
index caa131afe..000000000
--- a/src/kvstorage.c
+++ /dev/null
@@ -1,1560 +0,0 @@
-/* Copyright (c) 2011, Vsevolod Stakhov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "kvstorage.h"
-#include "main.h"
-#include "radix.h"
-#ifdef WITH_JUDY
-#include <Judy.h>
-#endif
-
-#define MAX_EXPIRE_STEPS 10
-
-/** Create new kv storage */
-struct rspamd_kv_storage *
-rspamd_kv_storage_new (gint id,
- const gchar *name,
- struct rspamd_kv_cache *cache,
- struct rspamd_kv_backend *backend,
- struct rspamd_kv_expire *expire,
- gsize max_elts,
- gsize max_memory,
- gboolean no_overwrite)
-{
- struct rspamd_kv_storage *new;
-
- new = g_slice_alloc (sizeof (struct rspamd_kv_storage));
- new->elts = 0;
- new->memory = 0;
-
- new->cache = cache;
- new->backend = backend;
- new->expire = expire;
-
- new->max_elts = max_elts;
- new->max_memory = max_memory;
-
- new->id = id;
-
- new->no_overwrite = no_overwrite;
-
- if (name != NULL) {
- new->name = g_strdup (name);
- }
- else {
- /* Name is absent, use ID as name */
- new->name = g_malloc (sizeof ("18446744073709551616"));
- rspamd_snprintf (new->name, sizeof ("18446744073709551616"), "%d", id);
- }
-#if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION > 30))
- g_rw_lock_init (&new->rwlock);
-#else
- g_static_rw_lock_init (&new->rwlock);
-#endif
-
-
- /* Init structures */
- if (new->cache->init_func) {
- new->cache->init_func (new->cache);
- }
- if (new->backend && new->backend->init_func) {
- new->backend->init_func (new->backend);
- }
- if (new->expire && new->expire->init_func) {
- new->expire->init_func (new->expire);
- }
-
- return new;
-}
-
-/** Internal insertion to the kv storage from backend */
-gboolean
-rspamd_kv_storage_insert_cache (struct rspamd_kv_storage *storage,
- gpointer key,
- guint keylen,
- gpointer data,
- gsize len,
- gint flags,
- guint expire,
- struct rspamd_kv_element **pelt)
-{
- gint steps = 0;
- struct rspamd_kv_element *elt;
-
- RW_W_LOCK (&storage->rwlock);
- /* Hard limit */
- if (storage->max_memory > 0) {
- if (len > storage->max_memory) {
- msg_info (
- "<%s>: trying to insert value of length %z while limit is %z",
- storage->name,
- len,
- storage->max_memory);
- RW_W_UNLOCK (&storage->rwlock);
- return FALSE;
- }
-
- /* Now check limits */
- while (storage->memory + len > storage->max_memory) {
- if (storage->expire) {
- storage->expire->step_func (storage->expire, storage, time (
- NULL), steps);
- }
- else {
- msg_warn (
- "<%s>: storage is full and no expire function is defined",
- storage->name);
- }
- if (++steps > MAX_EXPIRE_STEPS) {
- RW_W_UNLOCK (&storage->rwlock);
- msg_warn ("<%s>: cannot expire enough keys in storage",
- storage->name);
- return FALSE;
- }
- }
- }
-
- /* Insert elt to the cache */
-
- elt = storage->cache->insert_func (storage->cache, key, keylen, data, len);
-
-
- /* Copy data */
- elt->flags = flags;
- elt->expire = expire;
-
- if (pelt != NULL) {
- *pelt = elt;
- }
-
- /* Insert to the expire */
- if (storage->expire) {
- storage->expire->insert_func (storage->expire, elt);
- }
-
- storage->elts++;
- storage->memory += ELT_SIZE (elt);
- RW_W_UNLOCK (&storage->rwlock);
-
- return TRUE;
-}
-
-/** Insert new element to the kv storage */
-gboolean
-rspamd_kv_storage_insert (struct rspamd_kv_storage *storage,
- gpointer key,
- guint keylen,
- gpointer data,
- gsize len,
- gint flags,
- guint expire)
-{
- gint steps = 0;
- struct rspamd_kv_element *elt;
- gboolean res = TRUE;
- glong longval;
-
- /* Hard limit */
- RW_W_LOCK (&storage->rwlock);
- if (storage->max_memory > 0) {
- if (len + sizeof (struct rspamd_kv_element) + keylen >=
- storage->max_memory) {
- msg_warn (
- "<%s>: trying to insert value of length %z while limit is %z",
- storage->name,
- len,
- storage->max_memory);
- RW_W_UNLOCK (&storage->rwlock);
- return FALSE;
- }
-
- /* Now check limits */
- while (storage->memory + len + keylen > storage->max_memory) {
- if (storage->expire) {
- storage->expire->step_func (storage->expire, storage, time (
- NULL), steps);
- }
- else {
- msg_warn (
- "<%s>: storage is full and no expire function is defined",
- storage->name);
- }
- if (++steps > MAX_EXPIRE_STEPS) {
- RW_W_UNLOCK (&storage->rwlock);
- msg_warn ("<%s>: cannot expire enough keys in storage",
- storage->name);
- return FALSE;
- }
- }
- }
- if (storage->max_elts > 0 && storage->elts > storage->max_elts) {
- /* More expire */
- steps = 0;
- while (storage->elts > storage->max_elts) {
- if (storage->expire) {
- storage->expire->step_func (storage->expire, storage, time (
- NULL), steps);
- }
- else {
- msg_warn (
- "<%s>: storage is full and no expire function is defined",
- storage->name);
- }
- if (++steps > MAX_EXPIRE_STEPS) {
- RW_W_UNLOCK (&storage->rwlock);
- msg_warn ("<%s>: cannot expire enough keys in storage",
- storage->name);
- return FALSE;
- }
- }
- }
-
- /* First try to search it in cache */
-
- elt = storage->cache->lookup_func (storage->cache, key, keylen);
- if (elt) {
- if (!storage->no_overwrite) {
- /* Remove old elt */
- if (storage->expire) {
- storage->expire->delete_func (storage->expire, elt);
- }
- storage->memory -= ELT_SIZE (elt);
- storage->cache->steal_func (storage->cache, elt);
- if (elt->flags & KV_ELT_DIRTY) {
- /* Element is in backend storage queue */
- elt->flags |= KV_ELT_NEED_FREE;
- }
- else {
- g_slice_free1 (ELT_SIZE (elt), elt);
- }
- }
- else {
- /* Just do incref and nothing more */
- if (storage->backend && storage->backend->incref_func) {
- if (storage->backend->incref_func (storage->backend, key,
- keylen)) {
- RW_W_UNLOCK (&storage->rwlock);
- return TRUE;
- }
- else {
- RW_W_UNLOCK (&storage->rwlock);
- return FALSE;
- }
- }
- }
- }
-
- /* Insert elt to the cache */
-
- /* First of all check element for integer */
- if (rspamd_strtol (data, len, &longval)) {
- elt = storage->cache->insert_func (storage->cache,
- key,
- keylen,
- &longval,
- sizeof (glong));
- if (elt == NULL) {
- return FALSE;
- }
- else {
- elt->flags |= KV_ELT_INTEGER;
- }
- }
- else {
- elt = storage->cache->insert_func (storage->cache,
- key,
- keylen,
- data,
- len);
- if (elt == NULL) {
- RW_W_UNLOCK (&storage->rwlock);
- return FALSE;
- }
- }
-
- elt->flags |= flags;
- elt->expire = expire;
- if (expire == 0) {
- elt->flags |= KV_ELT_PERSISTENT;
- }
-
- /* Place to the backend */
- if (storage->backend) {
- res =
- storage->backend->insert_func (storage->backend, key, keylen, elt);
- }
-
- /* Insert to the expire */
- if (storage->expire) {
- storage->expire->insert_func (storage->expire, elt);
- }
-
- storage->elts++;
- storage->memory += ELT_SIZE (elt);
- RW_W_UNLOCK (&storage->rwlock);
-
- return res;
-}
-
-/** Replace an element in the kv storage */
-gboolean
-rspamd_kv_storage_replace (struct rspamd_kv_storage *storage,
- gpointer key,
- guint keylen,
- struct rspamd_kv_element *elt)
-{
- gboolean res = TRUE;
- gint steps = 0;
-
- /* Hard limit */
- if (storage->max_memory > 0) {
- if (elt->size > storage->max_memory) {
- msg_info (
- "<%s>: trying to replace value of length %z while limit is %z",
- storage->name,
- elt->size,
- storage->max_memory);
- return FALSE;
- }
-
- /* Now check limits */
- while (storage->memory + ELT_SIZE (elt) > storage->max_memory) {
- if (storage->expire) {
- RW_W_LOCK (&storage->rwlock);
- storage->expire->step_func (storage->expire, storage, time (
- NULL), steps);
- RW_W_UNLOCK (&storage->rwlock);
- }
- else {
- msg_warn (
- "<%s>: storage is full and no expire function is defined",
- storage->name);
- }
- if (++steps > MAX_EXPIRE_STEPS) {
- msg_warn ("<%s>: cannot expire enough keys in storage",
- storage->name);
- return FALSE;
- }
- }
- }
-
- RW_W_LOCK (&storage->rwlock);
- /* Insert elt to the cache */
- res = storage->cache->replace_func (storage->cache, key, keylen, elt);
-
- /* Place to the backend */
- if (res && storage->backend) {
- res =
- storage->backend->replace_func (storage->backend, key, keylen, elt);
- }
- RW_W_UNLOCK (&storage->rwlock);
-
- return res;
-}
-
-/** Increment value in kvstorage */
-gboolean
-rspamd_kv_storage_increment (struct rspamd_kv_storage *storage,
- gpointer key,
- guint keylen,
- glong *value)
-{
- struct rspamd_kv_element *elt = NULL, *belt;
- glong *lp;
-
- /* First try to look at cache */
- RW_W_LOCK (&storage->rwlock);
- elt = storage->cache->lookup_func (storage->cache, key, keylen);
-
- if (elt == NULL && storage->backend) {
- belt = storage->backend->lookup_func (storage->backend, key, keylen);
- if (belt) {
- /* Put this element into cache */
- if ((belt->flags & KV_ELT_INTEGER) != 0) {
- RW_W_UNLOCK (&storage->rwlock);
- rspamd_kv_storage_insert_cache (storage, ELT_KEY (
- belt), keylen, ELT_DATA (belt),
- belt->size, belt->flags,
- belt->expire, &elt);
- RW_W_LOCK (&storage->rwlock);
- }
- if ((belt->flags & KV_ELT_DIRTY) == 0) {
- g_free (belt);
- }
- }
- }
- if (elt && (elt->flags & KV_ELT_INTEGER) != 0) {
- lp = &ELT_LONG (elt);
- /* Handle need expire here */
- if (elt->flags & KV_ELT_NEED_EXPIRE) {
- *lp = *value;
- }
- else {
- *lp += *value;
- *value = *lp;
- }
- elt->age = time (NULL);
- if (storage->backend) {
- if (storage->backend->replace_func (storage->backend, key, keylen,
- elt)) {
- RW_W_UNLOCK (&storage->rwlock);
- return TRUE;
- }
- else {
- RW_W_UNLOCK (&storage->rwlock);
- return FALSE;
- }
- }
- else {
- RW_W_UNLOCK (&storage->rwlock);
- return TRUE;
- }
- }
-
- RW_W_UNLOCK (&storage->rwlock);
-
- return FALSE;
-}
-
-/** Lookup an element inside kv storage */
-struct rspamd_kv_element *
-rspamd_kv_storage_lookup (struct rspamd_kv_storage *storage,
- gpointer key,
- guint keylen,
- time_t now)
-{
- struct rspamd_kv_element *elt = NULL, *belt;
-
- /* First try to look at cache */
- RW_R_LOCK (&storage->rwlock);
- elt = storage->cache->lookup_func (storage->cache, key, keylen);
-
- /* Next look at the backend */
- if (elt == NULL && storage->backend) {
- belt = storage->backend->lookup_func (storage->backend, key, keylen);
-
- if (belt) {
- /* Put this element into cache */
- if ((belt->flags & KV_ELT_DIRTY) == 0) {
- belt->flags |= KV_ELT_NEED_INSERT;
- return belt;
- }
- else {
- elt = belt;
- }
- }
- }
-
- if (elt && (elt->flags & KV_ELT_PERSISTENT) == 0 && elt->expire > 0) {
- /* Check expiration */
- if (now - elt->age > (gint)elt->expire) {
- /* Set need expire as we have no write lock here */
- elt->flags |= KV_ELT_NEED_EXPIRE;
- elt = NULL;
- }
- }
-
- /* RWlock is still locked */
- return elt;
-}
-
-/** Expire an element from kv storage */
-struct rspamd_kv_element *
-rspamd_kv_storage_delete (struct rspamd_kv_storage *storage,
- gpointer key,
- guint keylen)
-{
- struct rspamd_kv_element *elt;
-
- /* First delete key from cache */
- RW_W_LOCK (&storage->rwlock);
- elt = storage->cache->delete_func (storage->cache, key, keylen);
-
- /* Now delete from backend */
- if (storage->backend) {
- storage->backend->delete_func (storage->backend, key, keylen);
- }
- /* Notify expire */
- if (elt) {
- if (storage->expire) {
- storage->expire->delete_func (storage->expire, elt);
- }
- storage->elts--;
- storage->memory -= elt->size;
- if ((elt->flags & KV_ELT_DIRTY) != 0) {
- elt->flags |= KV_ELT_NEED_FREE;
- }
- else {
- g_slice_free1 (ELT_SIZE (elt), elt);
- }
- }
-
- RW_W_UNLOCK (&storage->rwlock);
-
- return elt;
-}
-
-/** Destroy kv storage */
-void
-rspamd_kv_storage_destroy (struct rspamd_kv_storage *storage)
-{
- RW_W_LOCK (&storage->rwlock);
- if (storage->backend && storage->backend->destroy_func) {
- storage->backend->destroy_func (storage->backend);
- }
- if (storage->expire && storage->expire->destroy_func) {
- storage->expire->destroy_func (storage->expire);
- }
- if (storage->cache && storage->cache->destroy_func) {
- storage->cache->destroy_func (storage->cache);
- }
-
- g_free (storage->name);
-
- RW_W_UNLOCK (&storage->rwlock);
- g_slice_free1 (sizeof (struct rspamd_kv_storage), storage);
-}
-
-/** Insert array */
-gboolean
-rspamd_kv_storage_insert_array (struct rspamd_kv_storage *storage,
- gpointer key,
- guint keylen,
- guint elt_size,
- gpointer data,
- gsize len,
- gint flags,
- guint expire)
-{
- struct rspamd_kv_element *elt;
- guint *es;
- gpointer arr_data;
-
- /* Make temporary copy */
- arr_data = g_slice_alloc (len + sizeof (guint));
- es = arr_data;
- *es = elt_size;
- memcpy (arr_data, (gchar *)data + sizeof (guint), len);
- if (!rspamd_kv_storage_insert_cache (storage, key, keylen, arr_data, len +
- sizeof (guint),
- flags, expire, &elt)) {
- g_slice_free1 (len + sizeof (guint), arr_data);
- return FALSE;
- }
- /* Now set special data of element */
- elt->flags |= KV_ELT_ARRAY;
- g_slice_free1 (len + sizeof (guint), arr_data);
- /* Place to the backend */
-
- if (storage->backend) {
- return storage->backend->insert_func (storage->backend, key, keylen,
- elt);
- }
-
- return TRUE;
-}
-
-/** Set element inside array */
-gboolean
-rspamd_kv_storage_set_array (struct rspamd_kv_storage *storage,
- gpointer key,
- guint keylen,
- guint elt_num,
- gpointer data,
- gsize len,
- time_t now)
-{
- struct rspamd_kv_element *elt;
- guint *es;
- gpointer target;
-
- elt = rspamd_kv_storage_lookup (storage, key, keylen, now);
- if (elt == NULL) {
- return FALSE;
- }
-
- if ((elt->flags & KV_ELT_ARRAY) == 0) {
- return FALSE;
- }
- /* Get element size */
- es = (guint *)ELT_DATA (elt);
- if (elt_num > (elt->size - sizeof (guint)) / (*es)) {
- /* Invalid index */
- return FALSE;
- }
- target = (gchar *)ELT_DATA (elt) + sizeof (guint) + (*es) * elt_num;
- if (len != *es) {
- /* Invalid size */
- return FALSE;
- }
- memcpy (target, data, len);
- /* Place to the backend */
- if (storage->backend) {
- return storage->backend->replace_func (storage->backend,
- key,
- keylen,
- elt);
- }
-
- return TRUE;
-}
-
-/** Get element inside array */
-gboolean
-rspamd_kv_storage_get_array (struct rspamd_kv_storage *storage,
- gpointer key,
- guint keylen,
- guint elt_num,
- gpointer *data,
- gsize *len,
- time_t now)
-{
- struct rspamd_kv_element *elt;
- guint *es;
- gpointer target;
-
- elt = rspamd_kv_storage_lookup (storage, key, keylen, now);
- if (elt == NULL) {
- return FALSE;
- }
-
- if ((elt->flags & KV_ELT_ARRAY) == 0) {
- return FALSE;
- }
- /* Get element size */
- es = (guint *)ELT_DATA (elt);
- if (elt_num > (elt->size - sizeof (guint)) / (*es)) {
- /* Invalid index */
- return FALSE;
- }
- target = ELT_DATA (elt) + sizeof (guint) + (*es) * elt_num;
-
- *len = *es;
- *data = target;
-
- return TRUE;
-}
-
-/**
- * LRU expire functions
- */
-
-struct rspamd_kv_lru_expire {
- expire_init init_func; /*< this callback is called on kv storage initialization */
- expire_insert insert_func; /*< this callback is called when element is inserted */
- expire_step step_func; /*< this callback is used when cache is full */
- expire_delete delete_func; /*< this callback is called when an element is deleted */
- expire_destroy destroy_func; /*< this callback is used for destroying all elements inside expire */
-
- TAILQ_HEAD (eltq, rspamd_kv_element) head;
-};
-
-/**
- * Insert an element into expire queue
- */
-static void
-rspamd_lru_insert (struct rspamd_kv_expire *e, struct rspamd_kv_element *elt)
-{
- struct rspamd_kv_lru_expire *expire = (struct rspamd_kv_lru_expire *)e;
-
- /* Get a proper queue */
- TAILQ_INSERT_TAIL (&expire->head, elt, entry);
-}
-/**
- * Delete an element from expire queue
- */
-static void
-rspamd_lru_delete (struct rspamd_kv_expire *e, struct rspamd_kv_element *elt)
-{
- struct rspamd_kv_lru_expire *expire = (struct rspamd_kv_lru_expire *)e;
-
- /* Unlink element */
- TAILQ_REMOVE (&expire->head, elt, entry);
-}
-
-/**
- * Expire elements
- */
-static gboolean
-rspamd_lru_expire_step (struct rspamd_kv_expire *e,
- struct rspamd_kv_storage *storage,
- time_t now,
- gboolean forced)
-{
- struct rspamd_kv_lru_expire *expire = (struct rspamd_kv_lru_expire *)e;
- struct rspamd_kv_element *elt, *oldest_elt = NULL, *temp;
- time_t diff;
- gboolean res = FALSE;
-
- elt = TAILQ_FIRST (&expire->head);
- if (elt &&
- (forced || (elt->flags & (KV_ELT_PERSISTENT | KV_ELT_DIRTY)) == 0)) {
- diff = elt->expire - (now - elt->age);
- if (diff > 0 || (forced && elt->expire == 0)) {
- oldest_elt = elt;
- }
- else {
- /* This element is already expired */
- storage->cache->steal_func (storage->cache, elt);
- storage->memory -= ELT_SIZE (elt);
- storage->elts--;
- TAILQ_REMOVE (&expire->head, elt, entry);
- /* Free memory */
- if ((elt->flags & (KV_ELT_DIRTY | KV_ELT_NEED_INSERT)) != 0) {
- elt->flags |= KV_ELT_NEED_FREE;
- }
- else {
- g_slice_free1 (ELT_SIZE (elt), elt);
- }
- res = TRUE;
- /* Check other elements in this queue */
- TAILQ_FOREACH_SAFE (elt, &expire->head, entry, temp)
- {
- if ((!forced &&
- (elt->flags & (KV_ELT_PERSISTENT | KV_ELT_DIRTY)) != 0) ||
- (gint)elt->expire < (now - elt->age)) {
- break;
- }
- storage->memory -= ELT_SIZE (elt);
- storage->elts--;
- storage->cache->steal_func (storage->cache, elt);
- TAILQ_REMOVE (&expire->head, elt, entry);
- /* Free memory */
- if ((elt->flags & (KV_ELT_DIRTY | KV_ELT_NEED_INSERT)) != 0) {
- elt->flags |= KV_ELT_NEED_FREE;
- }
- else {
- g_slice_free1 (ELT_SIZE (elt), elt);
- }
-
- }
- }
- }
-
- if (!res && oldest_elt != NULL) {
- storage->memory -= ELT_SIZE (oldest_elt);
- storage->elts--;
- storage->cache->steal_func (storage->cache, oldest_elt);
- TAILQ_REMOVE (&expire->head, oldest_elt, entry);
- /* Free memory */
- if ((oldest_elt->flags & (KV_ELT_DIRTY | KV_ELT_NEED_INSERT)) != 0) {
- oldest_elt->flags |= KV_ELT_NEED_FREE;
- }
- else {
- g_slice_free1 (ELT_SIZE (oldest_elt), oldest_elt);
- }
- }
-
- return TRUE;
-}
-
-/**
- * Destroy LRU expire memory
- */
-static void
-rspamd_lru_destroy (struct rspamd_kv_expire *e)
-{
- struct rspamd_kv_lru_expire *expire = (struct rspamd_kv_lru_expire *)e;
-
- g_slice_free1 (sizeof (struct rspamd_kv_lru_expire), expire);
-}
-
-/**
- * Create new LRU cache
- */
-struct rspamd_kv_expire *
-rspamd_lru_expire_new (void)
-{
- struct rspamd_kv_lru_expire *new;
-
- new = g_slice_alloc (sizeof (struct rspamd_kv_lru_expire));
- TAILQ_INIT (&new->head);
-
- /* Set callbacks */
- new->init_func = NULL;
- new->insert_func = rspamd_lru_insert;
- new->delete_func = rspamd_lru_delete;
- new->step_func = rspamd_lru_expire_step;
- new->destroy_func = rspamd_lru_destroy;
-
- return (struct rspamd_kv_expire *)new;
-}
-
-/*
- * KV cache hash table
- */
-struct rspamd_kv_hash_cache {
- cache_init init_func; /*< this callback is called on kv storage initialization */
- cache_insert insert_func; /*< this callback is called when element is inserted */
- cache_replace replace_func; /*< this callback is called when element is replace */
- cache_lookup lookup_func; /*< this callback is used for lookup of element */
- cache_delete delete_func; /*< this callback is called when an element is deleted */
- cache_steal steal_func; /*< this callback is used to replace duplicates in cache */
- cache_destroy destroy_func; /*< this callback is used for destroying all elements inside cache */
- GHashTable *hash;
-};
-
-/**
- * Insert an element inside cache
- */
-static struct rspamd_kv_element *
-rspamd_kv_hash_insert (struct rspamd_kv_cache *c,
- gpointer key,
- guint keylen,
- gpointer value,
- gsize len)
-{
- struct rspamd_kv_element *elt;
- struct rspamd_kv_hash_cache *cache = (struct rspamd_kv_hash_cache *)c;
- struct rspamd_kv_element search_elt;
-
- search_elt.keylen = keylen;
- search_elt.p = key;
-
- if ((elt = g_hash_table_lookup (cache->hash, &search_elt)) == NULL) {
- elt = g_slice_alloc (
- sizeof (struct rspamd_kv_element) + len + keylen + 1);
- elt->age = time (NULL);
- elt->keylen = keylen;
- elt->size = len;
- elt->flags = 0;
- memcpy (ELT_KEY (elt), key, keylen + 1);
- memcpy (ELT_DATA (elt), value, len);
- elt->p = &elt->data;
- g_hash_table_insert (cache->hash, elt, elt);
- }
- else {
- g_hash_table_steal (cache->hash, elt);
- if ((elt->flags & KV_ELT_DIRTY) != 0) {
- elt->flags |= KV_ELT_NEED_FREE;
- }
- else {
- /* Free it by self */
- g_slice_free1 (ELT_SIZE (elt), elt);
- }
- elt = g_slice_alloc (
- sizeof (struct rspamd_kv_element) + len + keylen + 1);
- elt->age = time (NULL);
- elt->keylen = keylen;
- elt->size = len;
- elt->flags = 0;
- memcpy (ELT_KEY (elt), key, keylen + 1);
- memcpy (ELT_DATA (elt), value, len);
- elt->p = &elt->data;
- g_hash_table_insert (cache->hash, elt, elt);
- }
-
- return elt;
-}
-
-/**
- * Lookup an item inside hash
- */
-static struct rspamd_kv_element *
-rspamd_kv_hash_lookup (struct rspamd_kv_cache *c, gpointer key, guint keylen)
-{
- struct rspamd_kv_hash_cache *cache = (struct rspamd_kv_hash_cache *)c;
- struct rspamd_kv_element search_elt;
-
- search_elt.keylen = keylen;
- search_elt.p = key;
-
- return g_hash_table_lookup (cache->hash, &search_elt);
-}
-
-/**
- * Replace an element inside cache
- */
-static gboolean
-rspamd_kv_hash_replace (struct rspamd_kv_cache *c,
- gpointer key,
- guint keylen,
- struct rspamd_kv_element *elt)
-{
- struct rspamd_kv_hash_cache *cache = (struct rspamd_kv_hash_cache *)c;
- struct rspamd_kv_element *oldelt, search_elt;
-
- search_elt.keylen = keylen;
- search_elt.p = key;
-
- if ((oldelt = g_hash_table_lookup (cache->hash, &search_elt)) != NULL) {
- g_hash_table_steal (cache->hash, oldelt);
-
- if ((oldelt->flags & KV_ELT_DIRTY) != 0) {
- oldelt->flags |= KV_ELT_NEED_FREE;
- }
- else {
- /* Free it by self */
- g_slice_free1 (ELT_SIZE (oldelt), oldelt);
- }
- g_hash_table_insert (cache->hash, elt, elt);
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- * Delete an element from cache
- */
-static struct rspamd_kv_element *
-rspamd_kv_hash_delete (struct rspamd_kv_cache *c, gpointer key, guint keylen)
-{
- struct rspamd_kv_hash_cache *cache = (struct rspamd_kv_hash_cache *)c;
- struct rspamd_kv_element *elt;
- struct rspamd_kv_element search_elt;
-
- search_elt.keylen = keylen;
- search_elt.p = key;
-
- elt = g_hash_table_lookup (cache->hash, &search_elt);
- if (elt) {
- g_hash_table_steal (cache->hash, &search_elt);
- }
- return elt;
-}
-
-/**
- * Steal an element from cache
- */
-static void
-rspamd_kv_hash_steal (struct rspamd_kv_cache *c, struct rspamd_kv_element *elt)
-{
- struct rspamd_kv_hash_cache *cache = (struct rspamd_kv_hash_cache *)c;
-
- g_hash_table_steal (cache->hash, elt);
-}
-
-/**
- * Destroy the whole cache
- */
-
-static void
-rspamd_kv_hash_destroy_cb (gpointer key, gpointer value, gpointer unused)
-{
- struct rspamd_kv_element *elt = value;
-
- g_slice_free1 (ELT_SIZE (elt), elt);
-}
-
-static void
-rspamd_kv_hash_destroy (struct rspamd_kv_cache *c)
-{
- struct rspamd_kv_hash_cache *cache = (struct rspamd_kv_hash_cache *)c;
-
- g_hash_table_foreach (cache->hash, rspamd_kv_hash_destroy_cb, NULL);
- g_hash_table_destroy (cache->hash);
- g_slice_free1 (sizeof (struct rspamd_kv_hash_cache), cache);
-}
-
-/**
- * Make hash for element
- */
-#define rot(x,k) (((x) << (k)) ^ ((x) >> (32 - (k))))
-#define mix(a,b,c) \
- { \
- a -= c; a ^= rot (c, 4); c += b; \
- b -= a; b ^= rot (a, 6); a += c; \
- c -= b; c ^= rot (b, 8); b += a; \
- a -= c; a ^= rot (c,16); c += b; \
- b -= a; b ^= rot (a,19); a += c; \
- c -= b; c ^= rot (b, 4); b += a; \
- }
-#define final(a,b,c) \
- { \
- c ^= b; c -= rot (b,14); \
- a ^= c; a -= rot (c,11); \
- b ^= a; b -= rot (a,25); \
- c ^= b; c -= rot (b,16); \
- a ^= c; a -= rot (c,4); \
- b ^= a; b -= rot (a,14); \
- c ^= b; c -= rot (b,24); \
- }
-/*
- * The hash function used here is by Bob Jenkins, 1996:
- * <http://burtleburtle.net/bob/hash/doobs.html>
- * "By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net.
- * You may use this code any way you wish, private, educational,
- * or commercial. It's free."
- *
- */
-guint
-kv_elt_hash_func (gconstpointer e)
-{
- struct rspamd_kv_element *elt = (struct rspamd_kv_element *)e;
- guint32 a, b, c;
- union { const void *ptr; size_t i; } u;
- guint length;
-
- /* Set up the internal state */
- length = elt->keylen;
- a = b = c = 0xdeadbeef + length;
-
- u.ptr = elt->p;
- if (((u.i & 0x3) == 0)) {
- const guint32 *k = (const guint32 *)elt->p; /* read 32-bit chunks */
-
- /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
- while (length > 12) {
- a += k[0];
- b += k[1];
- c += k[2];
- mix (a,b,c);
- length -= 12;
- k += 3;
- }
-
- /*----------------------------- handle the last (probably partial) block */
- /*
- * "k[2]&0xffffff" actually reads beyond the end of the string, but
- * then masks off the part it's not allowed to read. Because the
- * string is aligned, the masked-off tail is in the same word as the
- * rest of the string. Every machine with memory protection I've seen
- * does it on word boundaries, so is OK with this. But VALGRIND will
- * still catch it and complain. The masking trick does make the hash
- * noticably faster for short strings (like English words).
- */
- switch (length)
- {
- case 12: c += k[2]; b += k[1]; a += k[0]; break;
- case 11: c += k[2] & 0xffffff; b += k[1]; a += k[0]; break;
- case 10: c += k[2] & 0xffff; b += k[1]; a += k[0]; break;
- case 9: c += k[2] & 0xff; b += k[1]; a += k[0]; break;
- case 8: b += k[1]; a += k[0]; break;
- case 7: b += k[1] & 0xffffff; a += k[0]; break;
- case 6: b += k[1] & 0xffff; a += k[0]; break;
- case 5: b += k[1] & 0xff; a += k[0]; break;
- case 4: a += k[0]; break;
- case 3: a += k[0] & 0xffffff; break;
- case 2: a += k[0] & 0xffff; break;
- case 1: a += k[0] & 0xff; break;
- case 0: return c; /* zero length strings require no mixing */
- }
-
- } else if (((u.i & 0x1) == 0)) {
- const guint16 *k = (const guint16 *)elt->p; /* read 16-bit chunks */
- const guint8 *k8;
-
- /*--------------- all but last block: aligned reads and different mixing */
- while (length > 12) {
- a += k[0] + (((guint32)k[1]) << 16);
- b += k[2] + (((guint32)k[3]) << 16);
- c += k[4] + (((guint32)k[5]) << 16);
- mix (a,b,c);
- length -= 12;
- k += 6;
- }
-
- /*----------------------------- handle the last (probably partial) block */
- k8 = (const guint8 *)k;
- switch (length)
- {
- case 12: c += k[4] + (((guint32)k[5]) << 16);
- b += k[2] + (((guint32)k[3]) << 16);
- a += k[0] + (((guint32)k[1]) << 16);
- break;
- case 11: c += ((guint32)k8[10]) << 16; /* @fallthrough */
- case 10: c += k[4]; /* @fallthrough@ */
- b += k[2] + (((guint32)k[3]) << 16);
- a += k[0] + (((guint32)k[1]) << 16);
- break;
- case 9: c += k8[8]; /* @fallthrough */
- case 8: b += k[2] + (((guint32)k[3]) << 16);
- a += k[0] + (((guint32)k[1]) << 16);
- break;
- case 7: b += ((guint32)k8[6]) << 16; /* @fallthrough */
- case 6: b += k[2];
- a += k[0] + (((guint32)k[1]) << 16);
- break;
- case 5: b += k8[4]; /* @fallthrough */
- case 4: a += k[0] + (((guint32)k[1]) << 16);
- break;
- case 3: a += ((guint32)k8[2]) << 16; /* @fallthrough */
- case 2: a += k[0];
- break;
- case 1: a += k8[0];
- break;
- case 0: return c; /* zero length strings require no mixing */
- }
-
- } else { /* need to read the key one byte at a time */
- const guint8 *k = elt->p;
-
- /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
- while (length > 12)
- {
- a += k[0];
- a += ((guint32)k[1]) << 8;
- a += ((guint32)k[2]) << 16;
- a += ((guint32)k[3]) << 24;
- b += k[4];
- b += ((guint32)k[5]) << 8;
- b += ((guint32)k[6]) << 16;
- b += ((guint32)k[7]) << 24;
- c += k[8];
- c += ((guint32)k[9]) << 8;
- c += ((guint32)k[10]) << 16;
- c += ((guint32)k[11]) << 24;
- mix (a,b,c);
- length -= 12;
- k += 12;
- }
-
- /*-------------------------------- last block: affect all 32 bits of (c) */
- switch (length) /* all the case statements fall through */
- {
- case 12: c += ((guint32)k[11]) << 24;
- case 11: c += ((guint32)k[10]) << 16;
- case 10: c += ((guint32)k[9]) << 8;
- case 9: c += k[8];
- case 8: b += ((guint32)k[7]) << 24;
- case 7: b += ((guint32)k[6]) << 16;
- case 6: b += ((guint32)k[5]) << 8;
- case 5: b += k[4];
- case 4: a += ((guint32)k[3]) << 24;
- case 3: a += ((guint32)k[2]) << 16;
- case 2: a += ((guint32)k[1]) << 8;
- case 1: a += k[0];
- break;
- case 0: return c; /* zero length strings require no mixing */
- }
- }
-
- final (a,b,c);
- return c; /* zero length strings require no mixing */
-}
-
-gboolean
-kv_elt_compare_func (gconstpointer e1, gconstpointer e2)
-{
- struct rspamd_kv_element *elt1 = (struct rspamd_kv_element *) e1,
- *elt2 = (struct rspamd_kv_element *) e2;
-
- if (elt1->keylen == elt2->keylen) {
- return memcmp (elt1->p, elt2->p, elt1->keylen) == 0;
- }
-
- return FALSE;
-}
-
-/**
- * Create new hash kv cache
- */
-struct rspamd_kv_cache *
-rspamd_kv_hash_new (void)
-{
- struct rspamd_kv_hash_cache *new;
-
- new = g_slice_alloc (sizeof (struct rspamd_kv_hash_cache));
- new->hash = g_hash_table_new_full (kv_elt_hash_func,
- kv_elt_compare_func,
- NULL,
- NULL);
- new->init_func = NULL;
- new->insert_func = rspamd_kv_hash_insert;
- new->lookup_func = rspamd_kv_hash_lookup;
- new->replace_func = rspamd_kv_hash_replace;
- new->delete_func = rspamd_kv_hash_delete;
- new->steal_func = rspamd_kv_hash_steal;
- new->destroy_func = rspamd_kv_hash_destroy;
-
- return (struct rspamd_kv_cache *)new;
-}
-
-/*
- * Radix cache hash table
- */
-struct rspamd_kv_radix_cache {
- cache_init init_func; /*< this callback is called on kv storage initialization */
- cache_insert insert_func; /*< this callback is called when element is inserted */
- cache_replace replace_func; /*< this callback is called when element is replace */
- cache_lookup lookup_func; /*< this callback is used for lookup of element */
- cache_delete delete_func; /*< this callback is called when an element is deleted */
- cache_steal steal_func; /*< this callback is used to replace duplicates in cache */
- cache_destroy destroy_func; /*< this callback is used for destroying all elements inside cache */
- radix_tree_t *tree;
-};
-
-/**
- * Validate a key for radix
- */
-static guint32
-rspamd_kv_radix_validate (gpointer key, guint keylen)
-{
- struct in_addr addr;
-
- if (inet_aton (key, &addr) == 0) {
- return 0;
- }
-
- return addr.s_addr;
-}
-
-/**
- * Insert an element inside cache
- */
-static struct rspamd_kv_element *
-rspamd_kv_radix_insert (struct rspamd_kv_cache *c,
- gpointer key,
- guint keylen,
- gpointer value,
- gsize len)
-{
- struct rspamd_kv_element *elt;
- struct rspamd_kv_radix_cache *cache = (struct rspamd_kv_radix_cache *)c;
- guint32 rkey = rspamd_kv_radix_validate (key, keylen);
-
- if (rkey == 0) {
- return NULL;
- }
-
- elt = (struct rspamd_kv_element *)radix32tree_find (cache->tree, rkey);
- if ((uintptr_t)elt == RADIX_NO_VALUE) {
- elt = g_slice_alloc (
- sizeof (struct rspamd_kv_element) + len + keylen + 1);
- elt->age = time (NULL);
- elt->keylen = keylen;
- elt->size = len;
- elt->flags = 0;
- memcpy (ELT_KEY (elt), key, keylen + 1);
- memcpy (ELT_DATA (elt), value, len);
- elt->p = &elt->data;
- radix32tree_insert (cache->tree, rkey, 0xffffffff, (uintptr_t)elt);
- }
- else {
- radix32tree_delete (cache->tree, rkey, 0xffffffff);
- if ((elt->flags & KV_ELT_DIRTY) != 0) {
- elt->flags |= KV_ELT_NEED_FREE;
- }
- else {
- /* Free it by self */
- g_slice_free1 (ELT_SIZE (elt), elt);
- }
- elt = g_slice_alloc (
- sizeof (struct rspamd_kv_element) + len + keylen + 1);
- elt->age = time (NULL);
- elt->keylen = keylen;
- elt->size = len;
- elt->flags = 0;
- memcpy (ELT_KEY (elt), key, keylen + 1);
- memcpy (ELT_DATA (elt), value, len);
- elt->p = &elt->data;
- radix32tree_insert (cache->tree, rkey, 0xffffffff, (uintptr_t)elt);
- }
-
- return elt;
-}
-
-/**
- * Lookup an item inside radix
- */
-static struct rspamd_kv_element *
-rspamd_kv_radix_lookup (struct rspamd_kv_cache *c, gpointer key, guint keylen)
-{
- struct rspamd_kv_radix_cache *cache = (struct rspamd_kv_radix_cache *)c;
- guint32 rkey = rspamd_kv_radix_validate (key, keylen);
- struct rspamd_kv_element *elt;
-
- elt = (struct rspamd_kv_element *)radix32tree_find (cache->tree, rkey);
- if ((uintptr_t)elt == RADIX_NO_VALUE) {
- return NULL;
- }
-
- return elt;
-}
-
-/**
- * Replace an element inside cache
- */
-static gboolean
-rspamd_kv_radix_replace (struct rspamd_kv_cache *c,
- gpointer key,
- guint keylen,
- struct rspamd_kv_element *elt)
-{
- struct rspamd_kv_radix_cache *cache = (struct rspamd_kv_radix_cache *)c;
- guint32 rkey = rspamd_kv_radix_validate (key, keylen);
- struct rspamd_kv_element *oldelt;
-
- oldelt = (struct rspamd_kv_element *)radix32tree_find (cache->tree, rkey);
- if ((uintptr_t)oldelt != RADIX_NO_VALUE) {
- radix32tree_delete (cache->tree, rkey, 0xffffffff);
-
- if ((oldelt->flags & KV_ELT_DIRTY) != 0) {
- oldelt->flags |= KV_ELT_NEED_FREE;
- }
- else {
- /* Free it by self */
- g_slice_free1 (ELT_SIZE (oldelt), oldelt);
- }
- radix32tree_insert (cache->tree, rkey, 0xffffffff, (uintptr_t)elt);
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- * Delete an element from cache
- */
-static struct rspamd_kv_element *
-rspamd_kv_radix_delete (struct rspamd_kv_cache *c, gpointer key, guint keylen)
-{
- struct rspamd_kv_radix_cache *cache = (struct rspamd_kv_radix_cache *)c;
- struct rspamd_kv_element *elt;
- guint32 rkey = rspamd_kv_radix_validate (key, keylen);
-
- elt = (struct rspamd_kv_element *)radix32tree_find (cache->tree, rkey);
- if ((uintptr_t)elt != RADIX_NO_VALUE) {
- radix32tree_delete (cache->tree, rkey, 0xffffffff);
- }
- else {
- return NULL;
- }
- return elt;
-}
-
-/**
- * Delete an element from cache
- */
-static void
-rspamd_kv_radix_steal (struct rspamd_kv_cache *c, struct rspamd_kv_element *elt)
-{
- struct rspamd_kv_radix_cache *cache = (struct rspamd_kv_radix_cache *)c;
- guint32 rkey = rspamd_kv_radix_validate (ELT_KEY (elt), elt->keylen);
-
-
- radix32tree_delete (cache->tree, rkey, 0xffffffff);
-}
-
-/**
- * Destroy the whole cache
- */
-static void
-rspamd_kv_radix_destroy (struct rspamd_kv_cache *c)
-{
- struct rspamd_kv_radix_cache *cache = (struct rspamd_kv_radix_cache *)c;
-
- radix_tree_free (cache->tree);
- g_slice_free1 (sizeof (struct rspamd_kv_radix_cache), cache);
-}
-
-/**
- * Create new radix kv cache
- */
-struct rspamd_kv_cache *
-rspamd_kv_radix_new (void)
-{
- struct rspamd_kv_radix_cache *new;
-
- new = g_slice_alloc (sizeof (struct rspamd_kv_radix_cache));
- new->tree = radix_tree_create ();
- new->init_func = NULL;
- new->insert_func = rspamd_kv_radix_insert;
- new->lookup_func = rspamd_kv_radix_lookup;
- new->replace_func = rspamd_kv_radix_replace;
- new->delete_func = rspamd_kv_radix_delete;
- new->steal_func = rspamd_kv_radix_steal;
- new->destroy_func = rspamd_kv_radix_destroy;
-
- return (struct rspamd_kv_cache *)new;
-}
-
-
-#ifdef WITH_JUDY
-/*
- * KV cache hash table
- */
-struct rspamd_kv_judy_cache {
- cache_init init_func; /*< this callback is called on kv storage initialization */
- cache_insert insert_func; /*< this callback is called when element is inserted */
- cache_replace replace_func; /*< this callback is called when element is replace */
- cache_lookup lookup_func; /*< this callback is used for lookup of element */
- cache_delete delete_func; /*< this callback is called when an element is deleted */
- cache_steal steal_func; /*< this callback is used to replace duplicates in cache */
- cache_destroy destroy_func; /*< this callback is used for destroying all elements inside cache */
- Pvoid_t judy;
-};
-
-
-/**
- * Lookup an item inside judy
- */
-static struct rspamd_kv_element *
-rspamd_kv_judy_lookup (struct rspamd_kv_cache *c, gpointer key, guint keylen)
-{
- struct rspamd_kv_judy_cache *cache = (struct rspamd_kv_judy_cache *)c;
- struct rspamd_kv_element *elt = NULL, **pelt;
-
- JHSG (pelt, cache->judy, key, keylen);
- if (pelt != NULL) {
- elt = *pelt;
- }
- return elt;
-}
-
-/**
- * Delete an element from cache
- */
-static struct rspamd_kv_element *
-rspamd_kv_judy_delete (struct rspamd_kv_cache *c, gpointer key, guint keylen)
-{
- struct rspamd_kv_judy_cache *cache = (struct rspamd_kv_judy_cache *)c;
- struct rspamd_kv_element *elt;
- gint rc;
-
- elt = rspamd_kv_judy_lookup (c, key, keylen);
- if (elt) {
- JHSD (rc, cache->judy, ELT_KEY (elt), elt->keylen);
- }
- return elt;
-}
-
-/**
- * Steal an element from cache
- */
-static void
-rspamd_kv_judy_steal (struct rspamd_kv_cache *c, struct rspamd_kv_element *elt)
-{
- struct rspamd_kv_judy_cache *cache = (struct rspamd_kv_judy_cache *)c;
- gint rc;
-
- JHSD (rc, cache->judy, ELT_KEY (elt), elt->keylen);
-}
-
-/**
- * Insert an element inside cache
- */
-static struct rspamd_kv_element *
-rspamd_kv_judy_insert (struct rspamd_kv_cache *c,
- gpointer key,
- guint keylen,
- gpointer value,
- gsize len)
-{
- struct rspamd_kv_element *elt, **pelt;
- struct rspamd_kv_judy_cache *cache = (struct rspamd_kv_judy_cache *)c;
-
- if ((elt = rspamd_kv_judy_lookup (c, key, keylen)) == NULL) {
- elt = g_slice_alloc (
- sizeof (struct rspamd_kv_element) + len + keylen + 1);
- elt->age = time (NULL);
- elt->keylen = keylen;
- elt->size = len;
- elt->flags = 0;
- memcpy (ELT_KEY (elt), key, keylen);
- memcpy (ELT_DATA (elt), value, len);
- JHSI (pelt, cache->judy, ELT_KEY (elt), elt->keylen);
- elt->p = &elt->data;
- *pelt = elt;
- }
- else {
- rspamd_kv_judy_steal (c, elt);
- if ((elt->flags & KV_ELT_DIRTY) != 0) {
- elt->flags |= KV_ELT_NEED_FREE;
- }
- else {
- /* Free it by self */
- g_slice_free1 (ELT_SIZE (elt), elt);
- }
- elt = g_slice_alloc0 (
- sizeof (struct rspamd_kv_element) + len + keylen + 1);
- elt->age = time (NULL);
- elt->keylen = keylen;
- elt->size = len;
- elt->flags = 0;
- memcpy (ELT_KEY (elt), key, keylen);
- memcpy (ELT_DATA (elt), value, len);
- elt->p = &elt->data;
- JHSI (pelt, cache->judy, ELT_KEY (elt), elt->keylen);
- *pelt = elt;
- }
-
- return elt;
-}
-
-/**
- * Replace an element inside cache
- */
-static gboolean
-rspamd_kv_judy_replace (struct rspamd_kv_cache *c,
- gpointer key,
- guint keylen,
- struct rspamd_kv_element *elt)
-{
- struct rspamd_kv_judy_cache *cache = (struct rspamd_kv_judy_cache *)c;
- struct rspamd_kv_element *oldelt, **pelt;
-
- if ((oldelt = rspamd_kv_judy_lookup (c, key, keylen)) != NULL) {
- rspamd_kv_judy_steal (c, elt);
-
- if ((oldelt->flags & KV_ELT_DIRTY) != 0) {
- oldelt->flags |= KV_ELT_NEED_FREE;
- }
- else {
- /* Free it by self */
- g_slice_free1 (ELT_SIZE (oldelt), oldelt);
- }
- JHSI (pelt, cache->judy, ELT_KEY (elt), elt->keylen);
- *pelt = elt;
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- * Destroy the whole cache
- */
-static void
-rspamd_kv_judy_destroy (struct rspamd_kv_cache *c)
-{
- struct rspamd_kv_judy_cache *cache = (struct rspamd_kv_judy_cache *)c;
- glong bytes;
-
- JHSFA (bytes, cache->judy);
- g_slice_free1 (sizeof (struct rspamd_kv_judy_cache), cache);
-}
-
-/**
- * Judy tree
- */
-struct rspamd_kv_cache *
-rspamd_kv_judy_new (void)
-{
- struct rspamd_kv_judy_cache *new;
-
- new = g_slice_alloc (sizeof (struct rspamd_kv_judy_cache));
- new->judy = NULL;
- new->init_func = NULL;
- new->insert_func = rspamd_kv_judy_insert;
- new->lookup_func = rspamd_kv_judy_lookup;
- new->replace_func = rspamd_kv_judy_replace;
- new->delete_func = rspamd_kv_judy_delete;
- new->steal_func = rspamd_kv_judy_steal;
- new->destroy_func = rspamd_kv_judy_destroy;
-
- return (struct rspamd_kv_cache *)new;
-}
-#endif