aboutsummaryrefslogtreecommitdiff
path: root/external/unbound/util/storage/lruhash.c
diff options
context:
space:
mode:
Diffstat (limited to 'external/unbound/util/storage/lruhash.c')
-rw-r--r--external/unbound/util/storage/lruhash.c631
1 files changed, 0 insertions, 631 deletions
diff --git a/external/unbound/util/storage/lruhash.c b/external/unbound/util/storage/lruhash.c
deleted file mode 100644
index 0003ff491..000000000
--- a/external/unbound/util/storage/lruhash.c
+++ /dev/null
@@ -1,631 +0,0 @@
-/*
- * util/storage/lruhash.c - hashtable, hash function, LRU keeping.
- *
- * Copyright (c) 2007, NLnet Labs. All rights reserved.
- *
- * This software is open source.
- *
- * 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.
- *
- * Neither the name of the NLNET LABS nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "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 THE COPYRIGHT
- * HOLDER OR CONTRIBUTORS 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.
- */
-
-/**
- * \file
- *
- * This file contains a hashtable with LRU keeping of entries.
- *
- */
-
-#include "config.h"
-#include "util/storage/lruhash.h"
-#include "util/fptr_wlist.h"
-
-void
-bin_init(struct lruhash_bin* array, size_t size)
-{
- size_t i;
-#ifdef THREADS_DISABLED
- (void)array;
-#endif
- for(i=0; i<size; i++) {
- lock_quick_init(&array[i].lock);
- lock_protect(&array[i].lock, &array[i],
- sizeof(struct lruhash_bin));
- }
-}
-
-struct lruhash*
-lruhash_create(size_t start_size, size_t maxmem,
- lruhash_sizefunc_type sizefunc, lruhash_compfunc_type compfunc,
- lruhash_delkeyfunc_type delkeyfunc,
- lruhash_deldatafunc_type deldatafunc, void* arg)
-{
- struct lruhash* table = (struct lruhash*)calloc(1,
- sizeof(struct lruhash));
- if(!table)
- return NULL;
- lock_quick_init(&table->lock);
- table->sizefunc = sizefunc;
- table->compfunc = compfunc;
- table->delkeyfunc = delkeyfunc;
- table->deldatafunc = deldatafunc;
- table->cb_arg = arg;
- table->size = start_size;
- table->size_mask = (int)(start_size-1);
- table->lru_start = NULL;
- table->lru_end = NULL;
- table->num = 0;
- table->space_used = 0;
- table->space_max = maxmem;
- table->array = calloc(table->size, sizeof(struct lruhash_bin));
- if(!table->array) {
- lock_quick_destroy(&table->lock);
- free(table);
- return NULL;
- }
- bin_init(table->array, table->size);
- lock_protect(&table->lock, table, sizeof(*table));
- lock_protect(&table->lock, table->array,
- table->size*sizeof(struct lruhash_bin));
- return table;
-}
-
-void
-bin_delete(struct lruhash* table, struct lruhash_bin* bin)
-{
- struct lruhash_entry* p, *np;
- void *d;
- if(!bin)
- return;
- lock_quick_destroy(&bin->lock);
- p = bin->overflow_list;
- bin->overflow_list = NULL;
- while(p) {
- np = p->overflow_next;
- d = p->data;
- (*table->delkeyfunc)(p->key, table->cb_arg);
- (*table->deldatafunc)(d, table->cb_arg);
- p = np;
- }
-}
-
-void
-bin_split(struct lruhash* table, struct lruhash_bin* newa,
- int newmask)
-{
- size_t i;
- struct lruhash_entry *p, *np;
- struct lruhash_bin* newbin;
- /* move entries to new table. Notice that since hash x is mapped to
- * bin x & mask, and new mask uses one more bit, so all entries in
- * one bin will go into the old bin or bin | newbit */
-#ifndef THREADS_DISABLED
- int newbit = newmask - table->size_mask;
-#endif
- /* so, really, this task could also be threaded, per bin. */
- /* LRU list is not changed */
- for(i=0; i<table->size; i++)
- {
- lock_quick_lock(&table->array[i].lock);
- p = table->array[i].overflow_list;
- /* lock both destination bins */
- lock_quick_lock(&newa[i].lock);
- lock_quick_lock(&newa[newbit|i].lock);
- while(p) {
- np = p->overflow_next;
- /* link into correct new bin */
- newbin = &newa[p->hash & newmask];
- p->overflow_next = newbin->overflow_list;
- newbin->overflow_list = p;
- p=np;
- }
- lock_quick_unlock(&newa[i].lock);
- lock_quick_unlock(&newa[newbit|i].lock);
- lock_quick_unlock(&table->array[i].lock);
- }
-}
-
-void
-lruhash_delete(struct lruhash* table)
-{
- size_t i;
- if(!table)
- return;
- /* delete lock on hashtable to force check its OK */
- lock_quick_destroy(&table->lock);
- for(i=0; i<table->size; i++)
- bin_delete(table, &table->array[i]);
- free(table->array);
- free(table);
-}
-
-void
-bin_overflow_remove(struct lruhash_bin* bin, struct lruhash_entry* entry)
-{
- struct lruhash_entry* p = bin->overflow_list;
- struct lruhash_entry** prevp = &bin->overflow_list;
- while(p) {
- if(p == entry) {
- *prevp = p->overflow_next;
- return;
- }
- prevp = &p->overflow_next;
- p = p->overflow_next;
- }
-}
-
-void
-reclaim_space(struct lruhash* table, struct lruhash_entry** list)
-{
- struct lruhash_entry* d;
- struct lruhash_bin* bin;
- log_assert(table);
- /* does not delete MRU entry, so table will not be empty. */
- while(table->num > 1 && table->space_used > table->space_max) {
- /* notice that since we hold the hashtable lock, nobody
- can change the lru chain. So it cannot be deleted underneath
- us. We still need the hashbin and entry write lock to make
- sure we flush all users away from the entry.
- which is unlikely, since it is LRU, if someone got a rdlock
- it would be moved to front, but to be sure. */
- d = table->lru_end;
- /* specialised, delete from end of double linked list,
- and we know num>1, so there is a previous lru entry. */
- log_assert(d && d->lru_prev);
- table->lru_end = d->lru_prev;
- d->lru_prev->lru_next = NULL;
- /* schedule entry for deletion */
- bin = &table->array[d->hash & table->size_mask];
- table->num --;
- lock_quick_lock(&bin->lock);
- bin_overflow_remove(bin, d);
- d->overflow_next = *list;
- *list = d;
- lock_rw_wrlock(&d->lock);
- table->space_used -= table->sizefunc(d->key, d->data);
- if(table->markdelfunc)
- (*table->markdelfunc)(d->key);
- lock_rw_unlock(&d->lock);
- lock_quick_unlock(&bin->lock);
- }
-}
-
-struct lruhash_entry*
-bin_find_entry(struct lruhash* table,
- struct lruhash_bin* bin, hashvalue_type hash, void* key)
-{
- struct lruhash_entry* p = bin->overflow_list;
- while(p) {
- if(p->hash == hash && table->compfunc(p->key, key) == 0)
- return p;
- p = p->overflow_next;
- }
- return NULL;
-}
-
-void
-table_grow(struct lruhash* table)
-{
- struct lruhash_bin* newa;
- int newmask;
- size_t i;
- if(table->size_mask == (int)(((size_t)-1)>>1)) {
- log_err("hash array malloc: size_t too small");
- return;
- }
- /* try to allocate new array, if not fail */
- newa = calloc(table->size*2, sizeof(struct lruhash_bin));
- if(!newa) {
- log_err("hash grow: malloc failed");
- /* continue with smaller array. Though its slower. */
- return;
- }
- bin_init(newa, table->size*2);
- newmask = (table->size_mask << 1) | 1;
- bin_split(table, newa, newmask);
- /* delete the old bins */
- lock_unprotect(&table->lock, table->array);
- for(i=0; i<table->size; i++) {
- lock_quick_destroy(&table->array[i].lock);
- }
- free(table->array);
-
- table->size *= 2;
- table->size_mask = newmask;
- table->array = newa;
- lock_protect(&table->lock, table->array,
- table->size*sizeof(struct lruhash_bin));
- return;
-}
-
-void
-lru_front(struct lruhash* table, struct lruhash_entry* entry)
-{
- entry->lru_prev = NULL;
- entry->lru_next = table->lru_start;
- if(!table->lru_start)
- table->lru_end = entry;
- else table->lru_start->lru_prev = entry;
- table->lru_start = entry;
-}
-
-void
-lru_remove(struct lruhash* table, struct lruhash_entry* entry)
-{
- if(entry->lru_prev)
- entry->lru_prev->lru_next = entry->lru_next;
- else table->lru_start = entry->lru_next;
- if(entry->lru_next)
- entry->lru_next->lru_prev = entry->lru_prev;
- else table->lru_end = entry->lru_prev;
-}
-
-void
-lru_touch(struct lruhash* table, struct lruhash_entry* entry)
-{
- log_assert(table && entry);
- if(entry == table->lru_start)
- return; /* nothing to do */
- /* remove from current lru position */
- lru_remove(table, entry);
- /* add at front */
- lru_front(table, entry);
-}
-
-void
-lruhash_insert(struct lruhash* table, hashvalue_type hash,
- struct lruhash_entry* entry, void* data, void* cb_arg)
-{
- struct lruhash_bin* bin;
- struct lruhash_entry* found, *reclaimlist=NULL;
- size_t need_size;
- fptr_ok(fptr_whitelist_hash_sizefunc(table->sizefunc));
- fptr_ok(fptr_whitelist_hash_delkeyfunc(table->delkeyfunc));
- fptr_ok(fptr_whitelist_hash_deldatafunc(table->deldatafunc));
- fptr_ok(fptr_whitelist_hash_compfunc(table->compfunc));
- fptr_ok(fptr_whitelist_hash_markdelfunc(table->markdelfunc));
- need_size = table->sizefunc(entry->key, data);
- if(cb_arg == NULL) cb_arg = table->cb_arg;
-
- /* find bin */
- lock_quick_lock(&table->lock);
- bin = &table->array[hash & table->size_mask];
- lock_quick_lock(&bin->lock);
-
- /* see if entry exists already */
- if(!(found=bin_find_entry(table, bin, hash, entry->key))) {
- /* if not: add to bin */
- entry->overflow_next = bin->overflow_list;
- bin->overflow_list = entry;
- lru_front(table, entry);
- table->num++;
- table->space_used += need_size;
- } else {
- /* if so: update data - needs a writelock */
- table->space_used += need_size -
- (*table->sizefunc)(found->key, found->data);
- (*table->delkeyfunc)(entry->key, cb_arg);
- lru_touch(table, found);
- lock_rw_wrlock(&found->lock);
- (*table->deldatafunc)(found->data, cb_arg);
- found->data = data;
- lock_rw_unlock(&found->lock);
- }
- lock_quick_unlock(&bin->lock);
- if(table->space_used > table->space_max)
- reclaim_space(table, &reclaimlist);
- if(table->num >= table->size)
- table_grow(table);
- lock_quick_unlock(&table->lock);
-
- /* finish reclaim if any (outside of critical region) */
- while(reclaimlist) {
- struct lruhash_entry* n = reclaimlist->overflow_next;
- void* d = reclaimlist->data;
- (*table->delkeyfunc)(reclaimlist->key, cb_arg);
- (*table->deldatafunc)(d, cb_arg);
- reclaimlist = n;
- }
-}
-
-struct lruhash_entry*
-lruhash_lookup(struct lruhash* table, hashvalue_type hash, void* key, int wr)
-{
- struct lruhash_entry* entry;
- struct lruhash_bin* bin;
- fptr_ok(fptr_whitelist_hash_compfunc(table->compfunc));
-
- lock_quick_lock(&table->lock);
- bin = &table->array[hash & table->size_mask];
- lock_quick_lock(&bin->lock);
- if((entry=bin_find_entry(table, bin, hash, key)))
- lru_touch(table, entry);
- lock_quick_unlock(&table->lock);
-
- if(entry) {
- if(wr) { lock_rw_wrlock(&entry->lock); }
- else { lock_rw_rdlock(&entry->lock); }
- }
- lock_quick_unlock(&bin->lock);
- return entry;
-}
-
-void
-lruhash_remove(struct lruhash* table, hashvalue_type hash, void* key)
-{
- struct lruhash_entry* entry;
- struct lruhash_bin* bin;
- void *d;
- fptr_ok(fptr_whitelist_hash_sizefunc(table->sizefunc));
- fptr_ok(fptr_whitelist_hash_delkeyfunc(table->delkeyfunc));
- fptr_ok(fptr_whitelist_hash_deldatafunc(table->deldatafunc));
- fptr_ok(fptr_whitelist_hash_compfunc(table->compfunc));
- fptr_ok(fptr_whitelist_hash_markdelfunc(table->markdelfunc));
-
- lock_quick_lock(&table->lock);
- bin = &table->array[hash & table->size_mask];
- lock_quick_lock(&bin->lock);
- if((entry=bin_find_entry(table, bin, hash, key))) {
- bin_overflow_remove(bin, entry);
- lru_remove(table, entry);
- } else {
- lock_quick_unlock(&table->lock);
- lock_quick_unlock(&bin->lock);
- return;
- }
- table->num--;
- table->space_used -= (*table->sizefunc)(entry->key, entry->data);
- lock_quick_unlock(&table->lock);
- lock_rw_wrlock(&entry->lock);
- if(table->markdelfunc)
- (*table->markdelfunc)(entry->key);
- lock_rw_unlock(&entry->lock);
- lock_quick_unlock(&bin->lock);
- /* finish removal */
- d = entry->data;
- (*table->delkeyfunc)(entry->key, table->cb_arg);
- (*table->deldatafunc)(d, table->cb_arg);
-}
-
-/** clear bin, respecting locks, does not do space, LRU */
-static void
-bin_clear(struct lruhash* table, struct lruhash_bin* bin)
-{
- struct lruhash_entry* p, *np;
- void *d;
- lock_quick_lock(&bin->lock);
- p = bin->overflow_list;
- while(p) {
- lock_rw_wrlock(&p->lock);
- np = p->overflow_next;
- d = p->data;
- if(table->markdelfunc)
- (*table->markdelfunc)(p->key);
- lock_rw_unlock(&p->lock);
- (*table->delkeyfunc)(p->key, table->cb_arg);
- (*table->deldatafunc)(d, table->cb_arg);
- p = np;
- }
- bin->overflow_list = NULL;
- lock_quick_unlock(&bin->lock);
-}
-
-void
-lruhash_clear(struct lruhash* table)
-{
- size_t i;
- if(!table)
- return;
- fptr_ok(fptr_whitelist_hash_delkeyfunc(table->delkeyfunc));
- fptr_ok(fptr_whitelist_hash_deldatafunc(table->deldatafunc));
- fptr_ok(fptr_whitelist_hash_markdelfunc(table->markdelfunc));
-
- lock_quick_lock(&table->lock);
- for(i=0; i<table->size; i++) {
- bin_clear(table, &table->array[i]);
- }
- table->lru_start = NULL;
- table->lru_end = NULL;
- table->num = 0;
- table->space_used = 0;
- lock_quick_unlock(&table->lock);
-}
-
-void
-lruhash_status(struct lruhash* table, const char* id, int extended)
-{
- lock_quick_lock(&table->lock);
- log_info("%s: %u entries, memory %u / %u",
- id, (unsigned)table->num, (unsigned)table->space_used,
- (unsigned)table->space_max);
- log_info(" itemsize %u, array %u, mask %d",
- (unsigned)(table->num? table->space_used/table->num : 0),
- (unsigned)table->size, table->size_mask);
- if(extended) {
- size_t i;
- int min=(int)table->size*2, max=-2;
- for(i=0; i<table->size; i++) {
- int here = 0;
- struct lruhash_entry *en;
- lock_quick_lock(&table->array[i].lock);
- en = table->array[i].overflow_list;
- while(en) {
- here ++;
- en = en->overflow_next;
- }
- lock_quick_unlock(&table->array[i].lock);
- if(extended >= 2)
- log_info("bin[%d] %d", (int)i, here);
- if(here > max) max = here;
- if(here < min) min = here;
- }
- log_info(" bin min %d, avg %.2lf, max %d", min,
- (double)table->num/(double)table->size, max);
- }
- lock_quick_unlock(&table->lock);
-}
-
-size_t
-lruhash_get_mem(struct lruhash* table)
-{
- size_t s;
- lock_quick_lock(&table->lock);
- s = sizeof(struct lruhash) + table->space_used;
-#ifdef USE_THREAD_DEBUG
- if(table->size != 0) {
- size_t i;
- for(i=0; i<table->size; i++)
- s += sizeof(struct lruhash_bin) +
- lock_get_mem(&table->array[i].lock);
- }
-#else /* no THREAD_DEBUG */
- if(table->size != 0)
- s += (table->size)*(sizeof(struct lruhash_bin) +
- lock_get_mem(&table->array[0].lock));
-#endif
- lock_quick_unlock(&table->lock);
- s += lock_get_mem(&table->lock);
- return s;
-}
-
-void
-lruhash_setmarkdel(struct lruhash* table, lruhash_markdelfunc_type md)
-{
- lock_quick_lock(&table->lock);
- table->markdelfunc = md;
- lock_quick_unlock(&table->lock);
-}
-
-void
-lruhash_traverse(struct lruhash* h, int wr,
- void (*func)(struct lruhash_entry*, void*), void* arg)
-{
- size_t i;
- struct lruhash_entry* e;
-
- lock_quick_lock(&h->lock);
- for(i=0; i<h->size; i++) {
- lock_quick_lock(&h->array[i].lock);
- for(e = h->array[i].overflow_list; e; e = e->overflow_next) {
- if(wr) {
- lock_rw_wrlock(&e->lock);
- } else {
- lock_rw_rdlock(&e->lock);
- }
- (*func)(e, arg);
- lock_rw_unlock(&e->lock);
- }
- lock_quick_unlock(&h->array[i].lock);
- }
- lock_quick_unlock(&h->lock);
-}
-
-/*
- * Demote: the opposite of touch, move an entry to the bottom
- * of the LRU pile.
- */
-
-void
-lru_demote(struct lruhash* table, struct lruhash_entry* entry)
-{
- log_assert(table && entry);
- if (entry == table->lru_end)
- return; /* nothing to do */
- /* remove from current lru position */
- lru_remove(table, entry);
- /* add at end */
- entry->lru_next = NULL;
- entry->lru_prev = table->lru_end;
-
- if (table->lru_end == NULL)
- {
- table->lru_start = entry;
- }
- else
- {
- table->lru_end->lru_next = entry;
- }
- table->lru_end = entry;
-}
-
-struct lruhash_entry*
-lruhash_insert_or_retrieve(struct lruhash* table, hashvalue_type hash,
- struct lruhash_entry* entry, void* data, void* cb_arg)
-{
- struct lruhash_bin* bin;
- struct lruhash_entry* found, *reclaimlist = NULL;
- size_t need_size;
- fptr_ok(fptr_whitelist_hash_sizefunc(table->sizefunc));
- fptr_ok(fptr_whitelist_hash_delkeyfunc(table->delkeyfunc));
- fptr_ok(fptr_whitelist_hash_deldatafunc(table->deldatafunc));
- fptr_ok(fptr_whitelist_hash_compfunc(table->compfunc));
- fptr_ok(fptr_whitelist_hash_markdelfunc(table->markdelfunc));
- need_size = table->sizefunc(entry->key, data);
- if (cb_arg == NULL) cb_arg = table->cb_arg;
-
- /* find bin */
- lock_quick_lock(&table->lock);
- bin = &table->array[hash & table->size_mask];
- lock_quick_lock(&bin->lock);
-
- /* see if entry exists already */
- if ((found = bin_find_entry(table, bin, hash, entry->key)) != NULL) {
- /* if so: keep the existing data - acquire a writelock */
- lock_rw_wrlock(&found->lock);
- }
- else
- {
- /* if not: add to bin */
- entry->overflow_next = bin->overflow_list;
- bin->overflow_list = entry;
- lru_front(table, entry);
- table->num++;
- table->space_used += need_size;
- /* return the entry that was presented, and lock it */
- found = entry;
- lock_rw_wrlock(&found->lock);
- }
- lock_quick_unlock(&bin->lock);
- if (table->space_used > table->space_max)
- reclaim_space(table, &reclaimlist);
- if (table->num >= table->size)
- table_grow(table);
- lock_quick_unlock(&table->lock);
-
- /* finish reclaim if any (outside of critical region) */
- while (reclaimlist) {
- struct lruhash_entry* n = reclaimlist->overflow_next;
- void* d = reclaimlist->data;
- (*table->delkeyfunc)(reclaimlist->key, cb_arg);
- (*table->deldatafunc)(d, cb_arg);
- reclaimlist = n;
- }
-
- /* return the entry that was selected */
- return found;
-}
-