From: Vsevolod Stakhov Date: Mon, 10 Dec 2018 12:20:05 +0000 (+0000) Subject: [Rework] Core: Improve structure of lru hash, get rid of GHashTable X-Git-Tag: 1.9.0~464 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=13252a6d575615170031f56797f328da55f77b71;p=rspamd.git [Rework] Core: Improve structure of lru hash, get rid of GHashTable --- diff --git a/src/fuzzy_storage.c b/src/fuzzy_storage.c index 2d53d969b..36b41113d 100644 --- a/src/fuzzy_storage.c +++ b/src/fuzzy_storage.c @@ -2201,11 +2201,9 @@ rspamd_fuzzy_storage_stat_key (struct fuzzy_key_stat *key_stat) static ucl_object_t * rspamd_fuzzy_stat_to_ucl (struct rspamd_fuzzy_storage_ctx *ctx, gboolean ip_stat) { - GHashTableIter it, ip_it; - GHashTable *ip_hash; struct fuzzy_key_stat *key_stat; + GHashTableIter it; struct fuzzy_key *key; - rspamd_lru_element_t *lru_elt; ucl_object_t *obj, *keys_obj, *elt, *ip_elt, *ip_cur; gpointer k, v; gint i; @@ -2226,22 +2224,18 @@ rspamd_fuzzy_stat_to_ucl (struct rspamd_fuzzy_storage_ctx *ctx, gboolean ip_stat elt = rspamd_fuzzy_storage_stat_key (key_stat); if (key_stat->last_ips && ip_stat) { - ip_hash = rspamd_lru_hash_get_htable (key_stat->last_ips); - - if (ip_hash) { - g_hash_table_iter_init (&ip_it, ip_hash); - ip_elt = ucl_object_typed_new (UCL_OBJECT); - - while (g_hash_table_iter_next (&ip_it, &k, &v)) { - lru_elt = v; - ip_cur = rspamd_fuzzy_storage_stat_key ( - rspamd_lru_hash_element_data (lru_elt)); - ucl_object_insert_key (ip_elt, ip_cur, - rspamd_inet_address_to_string (k), 0, true); - } + i = 0; + + ip_elt = ucl_object_typed_new (UCL_OBJECT); - ucl_object_insert_key (elt, ip_elt, "ips", 0, false); + while ((i = rspamd_lru_hash_foreach (key_stat->last_ips, + i, &k, &v)) != -1) { + ip_cur = rspamd_fuzzy_storage_stat_key (v); + ucl_object_insert_key (ip_elt, ip_cur, + rspamd_inet_address_to_string (k), 0, true); } + + ucl_object_insert_key (elt, ip_elt, "ips", 0, false); } ucl_object_insert_key (keys_obj, elt, keyname, 0, true); @@ -2268,27 +2262,21 @@ rspamd_fuzzy_stat_to_ucl (struct rspamd_fuzzy_storage_ctx *ctx, gboolean ip_stat false); if (ctx->errors_ips && ip_stat) { - ip_hash = rspamd_lru_hash_get_htable (ctx->errors_ips); - - if (ip_hash) { - g_hash_table_iter_init (&ip_it, ip_hash); - ip_elt = ucl_object_typed_new (UCL_OBJECT); + i = 0; - while (g_hash_table_iter_next (&ip_it, &k, &v)) { - lru_elt = v; + ip_elt = ucl_object_typed_new (UCL_OBJECT); - ucl_object_insert_key (ip_elt, - ucl_object_fromint (*(guint64 *) - rspamd_lru_hash_element_data (lru_elt)), - rspamd_inet_address_to_string (k), 0, true); - } - - ucl_object_insert_key (obj, - ip_elt, - "errors_ips", - 0, - false); + while ((i = rspamd_lru_hash_foreach (ctx->errors_ips, i, &k, &v)) != -1) { + ucl_object_insert_key (ip_elt, + ucl_object_fromint (*(guint64 *)v), + rspamd_inet_address_to_string (k), 0, true); } + + ucl_object_insert_key (obj, + ip_elt, + "errors_ips", + 0, + false); } /* Checked by epoch */ diff --git a/src/libutil/hash.c b/src/libutil/hash.c index bc438830f..086eba8d1 100644 --- a/src/libutil/hash.c +++ b/src/libutil/hash.c @@ -16,6 +16,7 @@ #include "config.h" #include "hash.h" #include "util.h" +#include "khash.h" /** * LRU hashing @@ -25,14 +26,23 @@ static const guint log_base = 10; static const guint eviction_candidates = 16; static const gdouble lfu_base_value = 5.0; +struct rspamd_lru_volatile_element_s; + struct rspamd_lru_hash_s { guint maxsize; guint eviction_min_prio; guint eviction_used; + struct rspamd_lru_element_s **eviction_pool; + GDestroyNotify value_destroy; GDestroyNotify key_destroy; - struct rspamd_lru_element_s **eviction_pool; - GHashTable *tbl; + GHashFunc hfunc; + GEqualFunc eqfunc; + + khint_t n_buckets, size, n_occupied, upper_bound; + khint32_t *flags; + gpointer *keys; + struct rspamd_lru_volatile_element_s *vals; }; enum rspamd_lru_element_flags { @@ -46,8 +56,6 @@ struct rspamd_lru_element_s { guint8 eviction_pos; guint8 flags; gpointer data; - gpointer key; - rspamd_lru_hash_t *hash; }; struct rspamd_lru_volatile_element_s { @@ -59,20 +67,240 @@ typedef struct rspamd_lru_volatile_element_s rspamd_lru_vol_element_t; #define TIME_TO_TS(t) ((guint16)(((t) / 60) & 0xFFFFU)) -static void -rspamd_lru_destroy_node (gpointer value) +static rspamd_lru_vol_element_t * +rspamd_lru_hash_get (const rspamd_lru_hash_t *h, gconstpointer key) +{ + if (h->n_buckets) { + khint_t k, i, last, mask, step = 0; + mask = h->n_buckets - 1; + k = h->hfunc (key); + i = k & mask; + last = i; + + while (!__ac_isempty(h->flags, i) && + (__ac_isdel(h->flags, i) || !h->eqfunc(h->keys[i], key))) { + i = (i + (++step)) & mask; + if (i == last) { + return NULL; + } + } + + return __ac_iseither(h->flags, i) ? NULL : &h->vals[i]; + } + + return NULL; +} + +static int +rspamd_lru_hash_resize (rspamd_lru_hash_t *h, + khint_t new_n_buckets) { - rspamd_lru_element_t *elt = (rspamd_lru_element_t *)value; + /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ + khint32_t *new_flags = 0; + khint_t j = 1; + + kroundup32(new_n_buckets); + if (new_n_buckets < 4) { + new_n_buckets = 4; + } + + if (h->size >= (khint_t) (new_n_buckets * __ac_HASH_UPPER + 0.5)) { + j = 0; + /* requested size is too small */ + } + else { + /* hash table size to be changed (shrink or expand); rehash */ + new_flags = (khint32_t *) g_malloc(__ac_fsize (new_n_buckets) * sizeof (khint32_t)); + + if (!new_flags) { + return -1; + } + + memset(new_flags, 0xaa, __ac_fsize (new_n_buckets) * sizeof (khint32_t)); + if (h->n_buckets < new_n_buckets) { + /* expand */ + gpointer *new_keys = (gpointer *) g_realloc((void *) h->keys, + new_n_buckets * sizeof (gpointer)); + + if (!new_keys) { + g_free(new_flags); + return -1; + } + + h->keys = new_keys; + rspamd_lru_vol_element_t *new_vals = + (rspamd_lru_vol_element_t *) g_realloc((void *) h->vals, + new_n_buckets * sizeof (rspamd_lru_vol_element_t)); + if (!new_vals) { + g_free(new_flags); + return -1; + } + + h->vals = new_vals; + } + /* Shrink */ + } + + if (j) { + /* rehashing is needed */ + h->eviction_used = 0; + + for (j = 0; j != h->n_buckets; ++j) { + if (__ac_iseither(h->flags, j) == 0) { + gpointer key = h->keys[j]; + rspamd_lru_vol_element_t val; + khint_t new_mask; + new_mask = new_n_buckets - 1; + val = h->vals[j]; + val.e.eviction_pos = (guint8)-1; + __ac_set_isdel_true(h->flags, j); + + while (1) { /* kick-out process; sort of like in Cuckoo hashing */ + khint_t k, i, step = 0; + k = h->hfunc(key); + i = k & new_mask; + + while (!__ac_isempty(new_flags, i)) { + i = (i + (++step)) & new_mask; + } - if (elt) { - if (elt->hash && elt->hash->key_destroy) { - elt->hash->key_destroy (elt->key); + __ac_set_isempty_false(new_flags, i); + + if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { + /* kick out the existing element */ + { + gpointer tmp = h->keys[i]; + h->keys[i] = key; + key = tmp; + } + { + rspamd_lru_vol_element_t tmp = h->vals[i]; + h->vals[i] = val; + val = tmp; + val.e.eviction_pos = (guint8)-1; + } + __ac_set_isdel_true(h->flags, i); + /* mark it as deleted in the old hash table */ + } else { /* write the element and jump out of the loop */ + h->keys[i] = key; + h->vals[i] = val; + break; + } + } + } } - if (elt->hash && elt->hash->value_destroy) { - elt->hash->value_destroy (elt->data); + + if (h->n_buckets > new_n_buckets) { + /* shrink the hash table */ + h->keys = (gpointer *) g_realloc((void *) h->keys, + new_n_buckets * sizeof (gpointer)); + h->vals = (rspamd_lru_vol_element_t *) g_realloc((void *) h->vals, + new_n_buckets * sizeof (rspamd_lru_vol_element_t)); } - g_free (elt); + g_free(h->flags); /* free the working space */ + h->flags = new_flags; + h->n_buckets = new_n_buckets; + h->n_occupied = h->size; + h->upper_bound = (khint_t) (h->n_buckets * __ac_HASH_UPPER + 0.5); + } + + return 0; +} + +static rspamd_lru_vol_element_t * +rspamd_lru_hash_put (rspamd_lru_hash_t *h, gpointer key, int *ret) +{ + khint_t x; + + if (h->n_occupied >= h->upper_bound) { + /* update the hash table */ + if (h->n_buckets > (h->size << 1)) { + if (rspamd_lru_hash_resize (h, h->n_buckets - 1) < 0) { + /* clear "deleted" elements */ + *ret = -1; + return NULL; + } + } + else if (rspamd_lru_hash_resize (h, h->n_buckets + 1) < 0) { + /* expand the hash table */ + *ret = -1; + return NULL; + } + } + + khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; + x = site = h->n_buckets; + k = h->hfunc(key); + i = k & mask; + + if (__ac_isempty(h->flags, i)) { + x = i; /* for speed up */ + } + else { + last = i; + while (!__ac_isempty(h->flags, i) && + (__ac_isdel(h->flags, i) || + !h->eqfunc (h->keys[i], key))) { + if (__ac_isdel(h->flags, i)) { + site = i; + } + + i = (i + (++step)) & mask; + + if (i == last) { + x = site; + break; + } + } + + if (x == h->n_buckets) { + if (__ac_isempty(h->flags, i) && site != h->n_buckets) { + x = site; + } + else { + x = i; + } + } + } + + if (__ac_isempty(h->flags, x)) { /* not present at all */ + h->keys[x] = key; + __ac_set_isboth_false(h->flags, x); + ++h->size; + ++h->n_occupied; + *ret = 1; + } + else if (__ac_isdel(h->flags, x)) { /* deleted */ + h->keys[x] = key; + __ac_set_isboth_false(h->flags, x); + ++h->size; + *ret = 2; + } + else { + /* Don't touch h->keys[x] if present and not deleted */ + *ret = 0; + } + + return &h->vals[x]; +} + +static void +rspamd_lru_hash_del (rspamd_lru_hash_t *h, rspamd_lru_vol_element_t *elt) +{ + khint_t x = elt - h->vals; + + if (x != h->n_buckets && !__ac_iseither(h->flags, x)) { + __ac_set_isdel_true(h->flags, x); + --h->size; + + if (h->key_destroy) { + h->key_destroy (h->keys[x]); + } + + if (h->value_destroy) { + h->value_destroy (elt->e.data); + } } } @@ -193,38 +421,6 @@ rspamd_lru_hash_maybe_evict (rspamd_lru_hash_t *hash, return FALSE; } -static rspamd_lru_element_t * -rspamd_lru_create_node (rspamd_lru_hash_t *hash, - gpointer key, - gpointer value, - time_t now, - guint ttl) -{ - rspamd_lru_element_t *node; - rspamd_lru_vol_element_t *vnode; - - if (ttl == 0) { - node = g_malloc (sizeof (rspamd_lru_element_t)); - node->flags = RSPAMD_LRU_ELEMENT_NORMAL; - } - else { - vnode = g_malloc (sizeof (rspamd_lru_vol_element_t)); - vnode->creation_time = now; - vnode->ttl = ttl; - node = &vnode->e; - node->flags = RSPAMD_LRU_ELEMENT_VOLATILE; - } - - node->data = value; - node->key = key; - node->hash = hash; - node->lg_usages = (guint8)lfu_base_value; - node->last = TIME_TO_TS (now); - node->eviction_pos = -1; - - return node; -} - static void rspamd_lru_hash_remove_node (rspamd_lru_hash_t *hash, rspamd_lru_element_t *elt) { @@ -232,36 +428,7 @@ rspamd_lru_hash_remove_node (rspamd_lru_hash_t *hash, rspamd_lru_element_t *elt) rspamd_lru_hash_remove_evicted (hash, elt); } - g_hash_table_remove (hash->tbl, elt->key); -} - -static rspamd_lru_element_t * -rspamd_lru_eviction_full_update (rspamd_lru_hash_t *hash, time_t now) -{ - GHashTableIter it; - gpointer k, v; - rspamd_lru_element_t *cur, *selected = NULL; - - g_hash_table_iter_init (&it, hash->tbl); - now = TIME_TO_TS (now); - - while (g_hash_table_iter_next (&it, &k, &v)) { - cur = v; - - rspamd_lru_hash_decrease_counter (cur, now); - - if (rspamd_lru_hash_maybe_evict (hash, cur)) { - - if (selected && cur->lg_usages < selected->lg_usages) { - selected = cur; - } - else if (selected == NULL) { - selected = cur; - } - } - } - - return selected; + rspamd_lru_hash_del (hash, (rspamd_lru_vol_element_t *)elt); } static void @@ -270,6 +437,7 @@ rspamd_lru_hash_evict (rspamd_lru_hash_t *hash, time_t now) double r; guint i; rspamd_lru_element_t *elt = NULL; + guint nexpired = 0; /* * We either evict one node from the eviction list @@ -280,9 +448,38 @@ rspamd_lru_hash_evict (rspamd_lru_hash_t *hash, time_t now) r = rspamd_random_double_fast (); if (r < ((double)eviction_candidates) / hash->maxsize) { - elt = rspamd_lru_eviction_full_update (hash, now); + /* Full hash scan */ + rspamd_lru_vol_element_t *cur; + rspamd_lru_element_t *selected = NULL; + + kh_foreach_value_ptr (hash, cur, { + rspamd_lru_element_t *node = &cur->e; + + if (node->flags & RSPAMD_LRU_ELEMENT_VOLATILE) { + /* If element is expired, just remove it */ + if (now - cur->creation_time > cur->ttl) { + rspamd_lru_hash_remove_node (hash, node); + + nexpired ++; + continue; + } + } + else { + rspamd_lru_hash_decrease_counter (node, now); + + if (rspamd_lru_hash_maybe_evict (hash, node)) { + if (selected && node->lg_usages < selected->lg_usages) { + selected = node; + } + else if (selected == NULL) { + selected = node; + } + } + } + }); } else { + /* Fast random eviction */ for (i = 0; i < hash->eviction_used; i ++) { elt = hash->eviction_pool[i]; @@ -292,41 +489,44 @@ rspamd_lru_hash_evict (rspamd_lru_hash_t *hash, time_t now) } } - g_assert (elt != NULL); - rspamd_lru_hash_remove_node (hash, elt); + if (elt && nexpired == 0) { + rspamd_lru_hash_remove_node (hash, elt); + } } rspamd_lru_hash_t * -rspamd_lru_hash_new_full ( - gint maxsize, - GDestroyNotify key_destroy, - GDestroyNotify value_destroy, - GHashFunc hf, - GEqualFunc cmpf) +rspamd_lru_hash_new_full (gint maxsize, + GDestroyNotify key_destroy, + GDestroyNotify value_destroy, + GHashFunc hf, + GEqualFunc cmpf) { - rspamd_lru_hash_t *new; + rspamd_lru_hash_t *h; if (maxsize < eviction_candidates * 2) { maxsize = eviction_candidates * 2; } - new = g_malloc0 (sizeof (rspamd_lru_hash_t)); - new->tbl = g_hash_table_new_full (hf, cmpf, NULL, rspamd_lru_destroy_node); - new->eviction_pool = g_malloc0 (sizeof (rspamd_lru_element_t *) * + h = g_malloc0 (sizeof (rspamd_lru_hash_t)); + h->hfunc = hf; + h->eqfunc = cmpf; + h->eviction_pool = g_malloc0 (sizeof (rspamd_lru_element_t *) * eviction_candidates); - new->maxsize = maxsize; - new->value_destroy = value_destroy; - new->key_destroy = key_destroy; - new->eviction_min_prio = G_MAXUINT; + h->maxsize = maxsize; + h->value_destroy = value_destroy; + h->key_destroy = key_destroy; + h->eviction_min_prio = G_MAXUINT; - return new; + /* Preallocate some elements */ + rspamd_lru_hash_resize (h, MIN (h->maxsize, 128)); + + return h; } rspamd_lru_hash_t * -rspamd_lru_hash_new ( - gint maxsize, - GDestroyNotify key_destroy, - GDestroyNotify value_destroy) +rspamd_lru_hash_new (gint maxsize, + GDestroyNotify key_destroy, + GDestroyNotify value_destroy) { return rspamd_lru_hash_new_full (maxsize, key_destroy, value_destroy, @@ -339,12 +539,12 @@ rspamd_lru_hash_lookup (rspamd_lru_hash_t *hash, gconstpointer key, time_t now) rspamd_lru_element_t *res; rspamd_lru_vol_element_t *vnode; - res = g_hash_table_lookup (hash->tbl, key); - if (res != NULL) { + vnode = rspamd_lru_hash_get (hash, (gpointer)key); + if (vnode != NULL) { + res = &vnode->e; if (res->flags & RSPAMD_LRU_ELEMENT_VOLATILE) { /* Check ttl */ - vnode = (rspamd_lru_vol_element_t *)res; if (now - vnode->creation_time > vnode->ttl) { rspamd_lru_hash_remove_node (hash, res); @@ -368,12 +568,12 @@ gboolean rspamd_lru_hash_remove (rspamd_lru_hash_t *hash, gconstpointer key) { - rspamd_lru_element_t *res; + rspamd_lru_vol_element_t *res; - res = g_hash_table_lookup (hash->tbl, key); + res = rspamd_lru_hash_get (hash, key); if (res != NULL) { - rspamd_lru_hash_remove_node (hash, res); + rspamd_lru_hash_remove_node (hash, &res->e); return TRUE; } @@ -382,44 +582,113 @@ rspamd_lru_hash_remove (rspamd_lru_hash_t *hash, } void -rspamd_lru_hash_insert (rspamd_lru_hash_t *hash, gpointer key, gpointer value, - time_t now, guint ttl) +rspamd_lru_hash_insert (rspamd_lru_hash_t *hash, + gpointer key, + gpointer value, + time_t now, + guint ttl) { - rspamd_lru_element_t *res; + rspamd_lru_element_t *node; + rspamd_lru_vol_element_t *vnode; + gint ret; - res = g_hash_table_lookup (hash->tbl, key); + vnode = rspamd_lru_hash_put (hash, key, &ret); + node = &vnode->e; - if (res != NULL) { - rspamd_lru_hash_remove_node (hash, res); + if (ret == 0) { + /* Existing element, be carefull about destructors */ + if (hash->value_destroy) { + /* Remove old data */ + hash->value_destroy (vnode->e.data); + } + + if (hash->key_destroy) { + /* Here are dragons! */ + goffset off = vnode - hash->vals; + + hash->key_destroy (hash->keys[off]); + hash->keys[off] = key; + } + } + + + if (ttl == 0) { + node->flags = RSPAMD_LRU_ELEMENT_NORMAL; } else { - if (g_hash_table_size (hash->tbl) >= hash->maxsize) { + vnode->creation_time = now; + vnode->ttl = ttl; + node->flags = RSPAMD_LRU_ELEMENT_VOLATILE; + } + + node->data = value; + node->lg_usages = (guint8)lfu_base_value; + node->last = TIME_TO_TS (now); + node->eviction_pos = -1; + + if (ret != 0) { + /* Also need to check maxsize */ + if (kh_size (hash) >= hash->maxsize) { rspamd_lru_hash_evict (hash, now); } } - res = rspamd_lru_create_node (hash, key, value, now, ttl); - g_hash_table_insert (hash->tbl, key, res); - rspamd_lru_hash_maybe_evict (hash, res); + rspamd_lru_hash_maybe_evict (hash, node); } void rspamd_lru_hash_destroy (rspamd_lru_hash_t *hash) { - g_hash_table_unref (hash->tbl); - g_free (hash->eviction_pool); - g_free (hash); -} - + if (hash) { + if (hash->key_destroy || hash->value_destroy) { + gpointer k; + rspamd_lru_vol_element_t cur; + + kh_foreach (hash, k, cur, { + if (hash->key_destroy) { + hash->key_destroy (k); + } + if (hash->value_destroy) { + hash->value_destroy (cur.e.data); + } + }); + } -GHashTable * -rspamd_lru_hash_get_htable (rspamd_lru_hash_t *hash) -{ - return hash->tbl; + g_free (hash->keys); + g_free (hash->vals); + g_free (hash->flags); + g_free (hash->eviction_pool); + g_free (hash); + } } gpointer rspamd_lru_hash_element_data (rspamd_lru_element_t *elt) { return elt->data; +} + +int +rspamd_lru_hash_foreach (rspamd_lru_hash_t *h, int it, gpointer *k, + gpointer *v) +{ + gint i; + g_assert (it >= 0); + + for (i = it; i != kh_end (h); ++i) { + if (!kh_exist (h, i)) { + continue; + } + + *k = h->keys[i]; + *v = h->vals[i].e.data; + + break; + } + + if (i == kh_end (h)) { + return -1; + } + + return i; } \ No newline at end of file diff --git a/src/libutil/hash.h b/src/libutil/hash.h index 7638d6397..f983a0be8 100644 --- a/src/libutil/hash.h +++ b/src/libutil/hash.h @@ -23,10 +23,9 @@ typedef struct rspamd_lru_element_s rspamd_lru_element_t; * @param key_equal_func pointer to function for comparing keys * @return new rspamd_hash object */ -rspamd_lru_hash_t * rspamd_lru_hash_new ( - gint maxsize, - GDestroyNotify key_destroy, - GDestroyNotify value_destroy); +rspamd_lru_hash_t * rspamd_lru_hash_new (gint maxsize, + GDestroyNotify key_destroy, + GDestroyNotify value_destroy); /** @@ -37,12 +36,11 @@ rspamd_lru_hash_t * rspamd_lru_hash_new ( * @param key_equal_func pointer to function for comparing keys * @return new rspamd_hash object */ -rspamd_lru_hash_t * rspamd_lru_hash_new_full ( - gint maxsize, - GDestroyNotify key_destroy, - GDestroyNotify value_destroy, - GHashFunc hfunc, - GEqualFunc eqfunc); +rspamd_lru_hash_t * rspamd_lru_hash_new_full (gint maxsize, + GDestroyNotify key_destroy, + GDestroyNotify value_destroy, + GHashFunc hfunc, + GEqualFunc eqfunc); /** * Lookup item from hash @@ -51,8 +49,8 @@ rspamd_lru_hash_t * rspamd_lru_hash_new_full ( * @return value of key or NULL if key is not found */ gpointer rspamd_lru_hash_lookup (rspamd_lru_hash_t *hash, - gconstpointer key, - time_t now); + gconstpointer key, + time_t now); /** * Removes key from LRU cache @@ -61,7 +59,7 @@ gpointer rspamd_lru_hash_lookup (rspamd_lru_hash_t *hash, * @return TRUE if key has been found and removed */ gboolean rspamd_lru_hash_remove (rspamd_lru_hash_t *hash, - gconstpointer key); + gconstpointer key); /** * Insert item in hash * @param hash hash object @@ -69,10 +67,10 @@ gboolean rspamd_lru_hash_remove (rspamd_lru_hash_t *hash, * @param value value of key */ void rspamd_lru_hash_insert (rspamd_lru_hash_t *hash, - gpointer key, - gpointer value, - time_t now, - guint ttl); + gpointer key, + gpointer value, + time_t now, + guint ttl); /** * Remove lru hash @@ -82,18 +80,13 @@ void rspamd_lru_hash_insert (rspamd_lru_hash_t *hash, void rspamd_lru_hash_destroy (rspamd_lru_hash_t *hash); /** - * Get hash table for this lru hash (use rspamd_lru_element_t as data) - */ -GHashTable *rspamd_lru_hash_get_htable (rspamd_lru_hash_t *hash); - -/** - * Get element's data - * @param elt - * @return + * Iterate over lru hash. Iterations must start from it=0 and are done when it==-1 + * @param hash + * @param it + * @param k + * @param v + * @return new it or -1 if iteration has been reached over */ -gpointer rspamd_lru_hash_element_data (rspamd_lru_element_t *elt); +int rspamd_lru_hash_foreach (rspamd_lru_hash_t *hash, int it, gpointer *k, + gpointer *v); #endif - -/* - * vi:ts=4 - */