xref: /freebsd/contrib/unbound/util/storage/lruhash.c (revision 65b390aa03158608c95d842609dcc4c7129d6476)
1b7579f77SDag-Erling Smørgrav /*
2b7579f77SDag-Erling Smørgrav  * util/storage/lruhash.c - hashtable, hash function, LRU keeping.
3b7579f77SDag-Erling Smørgrav  *
4b7579f77SDag-Erling Smørgrav  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5b7579f77SDag-Erling Smørgrav  *
6b7579f77SDag-Erling Smørgrav  * This software is open source.
7b7579f77SDag-Erling Smørgrav  *
8b7579f77SDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
9b7579f77SDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
10b7579f77SDag-Erling Smørgrav  * are met:
11b7579f77SDag-Erling Smørgrav  *
12b7579f77SDag-Erling Smørgrav  * Redistributions of source code must retain the above copyright notice,
13b7579f77SDag-Erling Smørgrav  * this list of conditions and the following disclaimer.
14b7579f77SDag-Erling Smørgrav  *
15b7579f77SDag-Erling Smørgrav  * Redistributions in binary form must reproduce the above copyright notice,
16b7579f77SDag-Erling Smørgrav  * this list of conditions and the following disclaimer in the documentation
17b7579f77SDag-Erling Smørgrav  * and/or other materials provided with the distribution.
18b7579f77SDag-Erling Smørgrav  *
19b7579f77SDag-Erling Smørgrav  * Neither the name of the NLNET LABS nor the names of its contributors may
20b7579f77SDag-Erling Smørgrav  * be used to endorse or promote products derived from this software without
21b7579f77SDag-Erling Smørgrav  * specific prior written permission.
22b7579f77SDag-Erling Smørgrav  *
23b7579f77SDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2417d15b25SDag-Erling Smørgrav  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2517d15b25SDag-Erling Smørgrav  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2617d15b25SDag-Erling Smørgrav  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2717d15b25SDag-Erling Smørgrav  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2817d15b25SDag-Erling Smørgrav  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
2917d15b25SDag-Erling Smørgrav  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
3017d15b25SDag-Erling Smørgrav  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
3117d15b25SDag-Erling Smørgrav  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3217d15b25SDag-Erling Smørgrav  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3317d15b25SDag-Erling Smørgrav  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34b7579f77SDag-Erling Smørgrav  */
35b7579f77SDag-Erling Smørgrav 
36b7579f77SDag-Erling Smørgrav /**
37b7579f77SDag-Erling Smørgrav  * \file
38b7579f77SDag-Erling Smørgrav  *
39b7579f77SDag-Erling Smørgrav  * This file contains a hashtable with LRU keeping of entries.
40b7579f77SDag-Erling Smørgrav  *
41b7579f77SDag-Erling Smørgrav  */
42b7579f77SDag-Erling Smørgrav 
43b7579f77SDag-Erling Smørgrav #include "config.h"
44b7579f77SDag-Erling Smørgrav #include "util/storage/lruhash.h"
45b7579f77SDag-Erling Smørgrav #include "util/fptr_wlist.h"
46b7579f77SDag-Erling Smørgrav 
47b7579f77SDag-Erling Smørgrav void
48b7579f77SDag-Erling Smørgrav bin_init(struct lruhash_bin* array, size_t size)
49b7579f77SDag-Erling Smørgrav {
50b7579f77SDag-Erling Smørgrav 	size_t i;
51b7579f77SDag-Erling Smørgrav #ifdef THREADS_DISABLED
52b7579f77SDag-Erling Smørgrav 	(void)array;
53b7579f77SDag-Erling Smørgrav #endif
54b7579f77SDag-Erling Smørgrav 	for(i=0; i<size; i++) {
55b7579f77SDag-Erling Smørgrav 		lock_quick_init(&array[i].lock);
56b7579f77SDag-Erling Smørgrav 		lock_protect(&array[i].lock, &array[i],
57b7579f77SDag-Erling Smørgrav 			sizeof(struct lruhash_bin));
58b7579f77SDag-Erling Smørgrav 	}
59b7579f77SDag-Erling Smørgrav }
60b7579f77SDag-Erling Smørgrav 
61b7579f77SDag-Erling Smørgrav struct lruhash*
623005e0a3SDag-Erling Smørgrav lruhash_create(size_t start_size, size_t maxmem,
633005e0a3SDag-Erling Smørgrav 	lruhash_sizefunc_type sizefunc, lruhash_compfunc_type compfunc,
643005e0a3SDag-Erling Smørgrav 	lruhash_delkeyfunc_type delkeyfunc,
653005e0a3SDag-Erling Smørgrav 	lruhash_deldatafunc_type deldatafunc, void* arg)
66b7579f77SDag-Erling Smørgrav {
67b7579f77SDag-Erling Smørgrav 	struct lruhash* table = (struct lruhash*)calloc(1,
68b7579f77SDag-Erling Smørgrav 		sizeof(struct lruhash));
69b7579f77SDag-Erling Smørgrav 	if(!table)
70b7579f77SDag-Erling Smørgrav 		return NULL;
71b7579f77SDag-Erling Smørgrav 	lock_quick_init(&table->lock);
72b7579f77SDag-Erling Smørgrav 	table->sizefunc = sizefunc;
73b7579f77SDag-Erling Smørgrav 	table->compfunc = compfunc;
74b7579f77SDag-Erling Smørgrav 	table->delkeyfunc = delkeyfunc;
75b7579f77SDag-Erling Smørgrav 	table->deldatafunc = deldatafunc;
76b7579f77SDag-Erling Smørgrav 	table->cb_arg = arg;
77b7579f77SDag-Erling Smørgrav 	table->size = start_size;
78b7579f77SDag-Erling Smørgrav 	table->size_mask = (int)(start_size-1);
79b7579f77SDag-Erling Smørgrav 	table->lru_start = NULL;
80b7579f77SDag-Erling Smørgrav 	table->lru_end = NULL;
81b7579f77SDag-Erling Smørgrav 	table->num = 0;
82b7579f77SDag-Erling Smørgrav 	table->space_used = 0;
83b7579f77SDag-Erling Smørgrav 	table->space_max = maxmem;
84b7579f77SDag-Erling Smørgrav 	table->array = calloc(table->size, sizeof(struct lruhash_bin));
85b7579f77SDag-Erling Smørgrav 	if(!table->array) {
86b7579f77SDag-Erling Smørgrav 		lock_quick_destroy(&table->lock);
87b7579f77SDag-Erling Smørgrav 		free(table);
88b7579f77SDag-Erling Smørgrav 		return NULL;
89b7579f77SDag-Erling Smørgrav 	}
90b7579f77SDag-Erling Smørgrav 	bin_init(table->array, table->size);
91b7579f77SDag-Erling Smørgrav 	lock_protect(&table->lock, table, sizeof(*table));
92b7579f77SDag-Erling Smørgrav 	lock_protect(&table->lock, table->array,
93b7579f77SDag-Erling Smørgrav 		table->size*sizeof(struct lruhash_bin));
94b7579f77SDag-Erling Smørgrav 	return table;
95b7579f77SDag-Erling Smørgrav }
96b7579f77SDag-Erling Smørgrav 
97b7579f77SDag-Erling Smørgrav void
98b7579f77SDag-Erling Smørgrav bin_delete(struct lruhash* table, struct lruhash_bin* bin)
99b7579f77SDag-Erling Smørgrav {
100b7579f77SDag-Erling Smørgrav 	struct lruhash_entry* p, *np;
101b7579f77SDag-Erling Smørgrav 	void *d;
102b7579f77SDag-Erling Smørgrav 	if(!bin)
103b7579f77SDag-Erling Smørgrav 		return;
104b7579f77SDag-Erling Smørgrav 	lock_quick_destroy(&bin->lock);
105b7579f77SDag-Erling Smørgrav 	p = bin->overflow_list;
106b7579f77SDag-Erling Smørgrav 	bin->overflow_list = NULL;
107b7579f77SDag-Erling Smørgrav 	while(p) {
108b7579f77SDag-Erling Smørgrav 		np = p->overflow_next;
109b7579f77SDag-Erling Smørgrav 		d = p->data;
110b7579f77SDag-Erling Smørgrav 		(*table->delkeyfunc)(p->key, table->cb_arg);
111b7579f77SDag-Erling Smørgrav 		(*table->deldatafunc)(d, table->cb_arg);
112b7579f77SDag-Erling Smørgrav 		p = np;
113b7579f77SDag-Erling Smørgrav 	}
114b7579f77SDag-Erling Smørgrav }
115b7579f77SDag-Erling Smørgrav 
116b7579f77SDag-Erling Smørgrav void
117b7579f77SDag-Erling Smørgrav bin_split(struct lruhash* table, struct lruhash_bin* newa,
118b7579f77SDag-Erling Smørgrav 	int newmask)
119b7579f77SDag-Erling Smørgrav {
120b7579f77SDag-Erling Smørgrav 	size_t i;
121b7579f77SDag-Erling Smørgrav 	struct lruhash_entry *p, *np;
122b7579f77SDag-Erling Smørgrav 	struct lruhash_bin* newbin;
123b7579f77SDag-Erling Smørgrav 	/* move entries to new table. Notice that since hash x is mapped to
124b7579f77SDag-Erling Smørgrav 	 * bin x & mask, and new mask uses one more bit, so all entries in
125b7579f77SDag-Erling Smørgrav 	 * one bin will go into the old bin or bin | newbit */
126b7579f77SDag-Erling Smørgrav #ifndef THREADS_DISABLED
127b7579f77SDag-Erling Smørgrav 	int newbit = newmask - table->size_mask;
128b7579f77SDag-Erling Smørgrav #endif
129b7579f77SDag-Erling Smørgrav 	/* so, really, this task could also be threaded, per bin. */
130b7579f77SDag-Erling Smørgrav 	/* LRU list is not changed */
131b7579f77SDag-Erling Smørgrav 	for(i=0; i<table->size; i++)
132b7579f77SDag-Erling Smørgrav 	{
133b7579f77SDag-Erling Smørgrav 		lock_quick_lock(&table->array[i].lock);
134b7579f77SDag-Erling Smørgrav 		p = table->array[i].overflow_list;
135b7579f77SDag-Erling Smørgrav 		/* lock both destination bins */
136b7579f77SDag-Erling Smørgrav 		lock_quick_lock(&newa[i].lock);
137b7579f77SDag-Erling Smørgrav 		lock_quick_lock(&newa[newbit|i].lock);
138b7579f77SDag-Erling Smørgrav 		while(p) {
139b7579f77SDag-Erling Smørgrav 			np = p->overflow_next;
140b7579f77SDag-Erling Smørgrav 			/* link into correct new bin */
141b7579f77SDag-Erling Smørgrav 			newbin = &newa[p->hash & newmask];
142b7579f77SDag-Erling Smørgrav 			p->overflow_next = newbin->overflow_list;
143b7579f77SDag-Erling Smørgrav 			newbin->overflow_list = p;
144b7579f77SDag-Erling Smørgrav 			p=np;
145b7579f77SDag-Erling Smørgrav 		}
146b7579f77SDag-Erling Smørgrav 		lock_quick_unlock(&newa[i].lock);
147b7579f77SDag-Erling Smørgrav 		lock_quick_unlock(&newa[newbit|i].lock);
148b7579f77SDag-Erling Smørgrav 		lock_quick_unlock(&table->array[i].lock);
149b7579f77SDag-Erling Smørgrav 	}
150b7579f77SDag-Erling Smørgrav }
151b7579f77SDag-Erling Smørgrav 
152b7579f77SDag-Erling Smørgrav void
153b7579f77SDag-Erling Smørgrav lruhash_delete(struct lruhash* table)
154b7579f77SDag-Erling Smørgrav {
155b7579f77SDag-Erling Smørgrav 	size_t i;
156b7579f77SDag-Erling Smørgrav 	if(!table)
157b7579f77SDag-Erling Smørgrav 		return;
158b7579f77SDag-Erling Smørgrav 	/* delete lock on hashtable to force check its OK */
159b7579f77SDag-Erling Smørgrav 	lock_quick_destroy(&table->lock);
160b7579f77SDag-Erling Smørgrav 	for(i=0; i<table->size; i++)
161b7579f77SDag-Erling Smørgrav 		bin_delete(table, &table->array[i]);
162b7579f77SDag-Erling Smørgrav 	free(table->array);
163b7579f77SDag-Erling Smørgrav 	free(table);
164b7579f77SDag-Erling Smørgrav }
165b7579f77SDag-Erling Smørgrav 
166b7579f77SDag-Erling Smørgrav void
167b7579f77SDag-Erling Smørgrav bin_overflow_remove(struct lruhash_bin* bin, struct lruhash_entry* entry)
168b7579f77SDag-Erling Smørgrav {
169b7579f77SDag-Erling Smørgrav 	struct lruhash_entry* p = bin->overflow_list;
170b7579f77SDag-Erling Smørgrav 	struct lruhash_entry** prevp = &bin->overflow_list;
171b7579f77SDag-Erling Smørgrav 	while(p) {
172b7579f77SDag-Erling Smørgrav 		if(p == entry) {
173b7579f77SDag-Erling Smørgrav 			*prevp = p->overflow_next;
174b7579f77SDag-Erling Smørgrav 			return;
175b7579f77SDag-Erling Smørgrav 		}
176b7579f77SDag-Erling Smørgrav 		prevp = &p->overflow_next;
177b7579f77SDag-Erling Smørgrav 		p = p->overflow_next;
178b7579f77SDag-Erling Smørgrav 	}
179b7579f77SDag-Erling Smørgrav }
180b7579f77SDag-Erling Smørgrav 
181b7579f77SDag-Erling Smørgrav void
182b7579f77SDag-Erling Smørgrav reclaim_space(struct lruhash* table, struct lruhash_entry** list)
183b7579f77SDag-Erling Smørgrav {
184b7579f77SDag-Erling Smørgrav 	struct lruhash_entry* d;
185b7579f77SDag-Erling Smørgrav 	struct lruhash_bin* bin;
186b7579f77SDag-Erling Smørgrav 	log_assert(table);
187b7579f77SDag-Erling Smørgrav 	/* does not delete MRU entry, so table will not be empty. */
188b7579f77SDag-Erling Smørgrav 	while(table->num > 1 && table->space_used > table->space_max) {
189b7579f77SDag-Erling Smørgrav 		/* notice that since we hold the hashtable lock, nobody
190b7579f77SDag-Erling Smørgrav 		   can change the lru chain. So it cannot be deleted underneath
191b7579f77SDag-Erling Smørgrav 		   us. We still need the hashbin and entry write lock to make
192b7579f77SDag-Erling Smørgrav 		   sure we flush all users away from the entry.
193b7579f77SDag-Erling Smørgrav 		   which is unlikely, since it is LRU, if someone got a rdlock
194b7579f77SDag-Erling Smørgrav 		   it would be moved to front, but to be sure. */
195b7579f77SDag-Erling Smørgrav 		d = table->lru_end;
196b7579f77SDag-Erling Smørgrav 		/* specialised, delete from end of double linked list,
197b7579f77SDag-Erling Smørgrav 		   and we know num>1, so there is a previous lru entry. */
198b7579f77SDag-Erling Smørgrav 		log_assert(d && d->lru_prev);
199b7579f77SDag-Erling Smørgrav 		table->lru_end = d->lru_prev;
200b7579f77SDag-Erling Smørgrav 		d->lru_prev->lru_next = NULL;
201b7579f77SDag-Erling Smørgrav 		/* schedule entry for deletion */
202b7579f77SDag-Erling Smørgrav 		bin = &table->array[d->hash & table->size_mask];
203b7579f77SDag-Erling Smørgrav 		table->num --;
204b7579f77SDag-Erling Smørgrav 		lock_quick_lock(&bin->lock);
205b7579f77SDag-Erling Smørgrav 		bin_overflow_remove(bin, d);
206b7579f77SDag-Erling Smørgrav 		d->overflow_next = *list;
207b7579f77SDag-Erling Smørgrav 		*list = d;
208b7579f77SDag-Erling Smørgrav 		lock_rw_wrlock(&d->lock);
209b7579f77SDag-Erling Smørgrav 		table->space_used -= table->sizefunc(d->key, d->data);
210b7579f77SDag-Erling Smørgrav 		if(table->markdelfunc)
211b7579f77SDag-Erling Smørgrav 			(*table->markdelfunc)(d->key);
212b7579f77SDag-Erling Smørgrav 		lock_rw_unlock(&d->lock);
213b7579f77SDag-Erling Smørgrav 		lock_quick_unlock(&bin->lock);
214b7579f77SDag-Erling Smørgrav 	}
215b7579f77SDag-Erling Smørgrav }
216b7579f77SDag-Erling Smørgrav 
217b7579f77SDag-Erling Smørgrav struct lruhash_entry*
218b7579f77SDag-Erling Smørgrav bin_find_entry(struct lruhash* table,
2193005e0a3SDag-Erling Smørgrav 	struct lruhash_bin* bin, hashvalue_type hash, void* key)
220b7579f77SDag-Erling Smørgrav {
221b7579f77SDag-Erling Smørgrav 	struct lruhash_entry* p = bin->overflow_list;
222b7579f77SDag-Erling Smørgrav 	while(p) {
223b7579f77SDag-Erling Smørgrav 		if(p->hash == hash && table->compfunc(p->key, key) == 0)
224b7579f77SDag-Erling Smørgrav 			return p;
225b7579f77SDag-Erling Smørgrav 		p = p->overflow_next;
226b7579f77SDag-Erling Smørgrav 	}
227b7579f77SDag-Erling Smørgrav 	return NULL;
228b7579f77SDag-Erling Smørgrav }
229b7579f77SDag-Erling Smørgrav 
230b7579f77SDag-Erling Smørgrav void
231b7579f77SDag-Erling Smørgrav table_grow(struct lruhash* table)
232b7579f77SDag-Erling Smørgrav {
233b7579f77SDag-Erling Smørgrav 	struct lruhash_bin* newa;
234b7579f77SDag-Erling Smørgrav 	int newmask;
235b7579f77SDag-Erling Smørgrav 	size_t i;
236b7579f77SDag-Erling Smørgrav 	if(table->size_mask == (int)(((size_t)-1)>>1)) {
237b7579f77SDag-Erling Smørgrav 		log_err("hash array malloc: size_t too small");
238b7579f77SDag-Erling Smørgrav 		return;
239b7579f77SDag-Erling Smørgrav 	}
240b7579f77SDag-Erling Smørgrav 	/* try to allocate new array, if not fail */
241b7579f77SDag-Erling Smørgrav 	newa = calloc(table->size*2, sizeof(struct lruhash_bin));
242b7579f77SDag-Erling Smørgrav 	if(!newa) {
243b7579f77SDag-Erling Smørgrav 		log_err("hash grow: malloc failed");
244b7579f77SDag-Erling Smørgrav 		/* continue with smaller array. Though its slower. */
245b7579f77SDag-Erling Smørgrav 		return;
246b7579f77SDag-Erling Smørgrav 	}
247b7579f77SDag-Erling Smørgrav 	bin_init(newa, table->size*2);
248b7579f77SDag-Erling Smørgrav 	newmask = (table->size_mask << 1) | 1;
249b7579f77SDag-Erling Smørgrav 	bin_split(table, newa, newmask);
250b7579f77SDag-Erling Smørgrav 	/* delete the old bins */
251b7579f77SDag-Erling Smørgrav 	lock_unprotect(&table->lock, table->array);
252b7579f77SDag-Erling Smørgrav 	for(i=0; i<table->size; i++) {
253b7579f77SDag-Erling Smørgrav 		lock_quick_destroy(&table->array[i].lock);
254b7579f77SDag-Erling Smørgrav 	}
255b7579f77SDag-Erling Smørgrav 	free(table->array);
256b7579f77SDag-Erling Smørgrav 
257b7579f77SDag-Erling Smørgrav 	table->size *= 2;
258b7579f77SDag-Erling Smørgrav 	table->size_mask = newmask;
259b7579f77SDag-Erling Smørgrav 	table->array = newa;
260b7579f77SDag-Erling Smørgrav 	lock_protect(&table->lock, table->array,
261b7579f77SDag-Erling Smørgrav 		table->size*sizeof(struct lruhash_bin));
262b7579f77SDag-Erling Smørgrav 	return;
263b7579f77SDag-Erling Smørgrav }
264b7579f77SDag-Erling Smørgrav 
265b7579f77SDag-Erling Smørgrav void
266b7579f77SDag-Erling Smørgrav lru_front(struct lruhash* table, struct lruhash_entry* entry)
267b7579f77SDag-Erling Smørgrav {
268b7579f77SDag-Erling Smørgrav 	entry->lru_prev = NULL;
269b7579f77SDag-Erling Smørgrav 	entry->lru_next = table->lru_start;
270b7579f77SDag-Erling Smørgrav 	if(!table->lru_start)
271b7579f77SDag-Erling Smørgrav 		table->lru_end = entry;
272b7579f77SDag-Erling Smørgrav 	else	table->lru_start->lru_prev = entry;
273b7579f77SDag-Erling Smørgrav 	table->lru_start = entry;
274b7579f77SDag-Erling Smørgrav }
275b7579f77SDag-Erling Smørgrav 
276b7579f77SDag-Erling Smørgrav void
277b7579f77SDag-Erling Smørgrav lru_remove(struct lruhash* table, struct lruhash_entry* entry)
278b7579f77SDag-Erling Smørgrav {
279b7579f77SDag-Erling Smørgrav 	if(entry->lru_prev)
280b7579f77SDag-Erling Smørgrav 		entry->lru_prev->lru_next = entry->lru_next;
281b7579f77SDag-Erling Smørgrav 	else	table->lru_start = entry->lru_next;
282b7579f77SDag-Erling Smørgrav 	if(entry->lru_next)
283b7579f77SDag-Erling Smørgrav 		entry->lru_next->lru_prev = entry->lru_prev;
284b7579f77SDag-Erling Smørgrav 	else	table->lru_end = entry->lru_prev;
285b7579f77SDag-Erling Smørgrav }
286b7579f77SDag-Erling Smørgrav 
287b7579f77SDag-Erling Smørgrav void
288b7579f77SDag-Erling Smørgrav lru_touch(struct lruhash* table, struct lruhash_entry* entry)
289b7579f77SDag-Erling Smørgrav {
290b7579f77SDag-Erling Smørgrav 	log_assert(table && entry);
291b7579f77SDag-Erling Smørgrav 	if(entry == table->lru_start)
292b7579f77SDag-Erling Smørgrav 		return; /* nothing to do */
293b7579f77SDag-Erling Smørgrav 	/* remove from current lru position */
294b7579f77SDag-Erling Smørgrav 	lru_remove(table, entry);
295b7579f77SDag-Erling Smørgrav 	/* add at front */
296b7579f77SDag-Erling Smørgrav 	lru_front(table, entry);
297b7579f77SDag-Erling Smørgrav }
298b7579f77SDag-Erling Smørgrav 
299b7579f77SDag-Erling Smørgrav void
3003005e0a3SDag-Erling Smørgrav lruhash_insert(struct lruhash* table, hashvalue_type hash,
301b7579f77SDag-Erling Smørgrav         struct lruhash_entry* entry, void* data, void* cb_arg)
302b7579f77SDag-Erling Smørgrav {
303b7579f77SDag-Erling Smørgrav 	struct lruhash_bin* bin;
304b7579f77SDag-Erling Smørgrav 	struct lruhash_entry* found, *reclaimlist=NULL;
305b7579f77SDag-Erling Smørgrav 	size_t need_size;
306b7579f77SDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_hash_sizefunc(table->sizefunc));
307b7579f77SDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_hash_delkeyfunc(table->delkeyfunc));
308b7579f77SDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_hash_deldatafunc(table->deldatafunc));
309b7579f77SDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_hash_compfunc(table->compfunc));
310b7579f77SDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_hash_markdelfunc(table->markdelfunc));
311b7579f77SDag-Erling Smørgrav 	need_size = table->sizefunc(entry->key, data);
312b7579f77SDag-Erling Smørgrav 	if(cb_arg == NULL) cb_arg = table->cb_arg;
313b7579f77SDag-Erling Smørgrav 
314b7579f77SDag-Erling Smørgrav 	/* find bin */
315b7579f77SDag-Erling Smørgrav 	lock_quick_lock(&table->lock);
316b7579f77SDag-Erling Smørgrav 	bin = &table->array[hash & table->size_mask];
317b7579f77SDag-Erling Smørgrav 	lock_quick_lock(&bin->lock);
318b7579f77SDag-Erling Smørgrav 
319b7579f77SDag-Erling Smørgrav 	/* see if entry exists already */
320b7579f77SDag-Erling Smørgrav 	if(!(found=bin_find_entry(table, bin, hash, entry->key))) {
321b7579f77SDag-Erling Smørgrav 		/* if not: add to bin */
322b7579f77SDag-Erling Smørgrav 		entry->overflow_next = bin->overflow_list;
323b7579f77SDag-Erling Smørgrav 		bin->overflow_list = entry;
324b7579f77SDag-Erling Smørgrav 		lru_front(table, entry);
325b7579f77SDag-Erling Smørgrav 		table->num++;
326b7579f77SDag-Erling Smørgrav 		table->space_used += need_size;
327b7579f77SDag-Erling Smørgrav 	} else {
328b7579f77SDag-Erling Smørgrav 		/* if so: update data - needs a writelock */
329b7579f77SDag-Erling Smørgrav 		table->space_used += need_size -
330b7579f77SDag-Erling Smørgrav 			(*table->sizefunc)(found->key, found->data);
331b7579f77SDag-Erling Smørgrav 		(*table->delkeyfunc)(entry->key, cb_arg);
332b7579f77SDag-Erling Smørgrav 		lru_touch(table, found);
333b7579f77SDag-Erling Smørgrav 		lock_rw_wrlock(&found->lock);
334b7579f77SDag-Erling Smørgrav 		(*table->deldatafunc)(found->data, cb_arg);
335b7579f77SDag-Erling Smørgrav 		found->data = data;
336b7579f77SDag-Erling Smørgrav 		lock_rw_unlock(&found->lock);
337b7579f77SDag-Erling Smørgrav 	}
338b7579f77SDag-Erling Smørgrav 	lock_quick_unlock(&bin->lock);
339b7579f77SDag-Erling Smørgrav 	if(table->space_used > table->space_max)
340b7579f77SDag-Erling Smørgrav 		reclaim_space(table, &reclaimlist);
341b7579f77SDag-Erling Smørgrav 	if(table->num >= table->size)
342b7579f77SDag-Erling Smørgrav 		table_grow(table);
343b7579f77SDag-Erling Smørgrav 	lock_quick_unlock(&table->lock);
344b7579f77SDag-Erling Smørgrav 
345b7579f77SDag-Erling Smørgrav 	/* finish reclaim if any (outside of critical region) */
346b7579f77SDag-Erling Smørgrav 	while(reclaimlist) {
347b7579f77SDag-Erling Smørgrav 		struct lruhash_entry* n = reclaimlist->overflow_next;
348b7579f77SDag-Erling Smørgrav 		void* d = reclaimlist->data;
349b7579f77SDag-Erling Smørgrav 		(*table->delkeyfunc)(reclaimlist->key, cb_arg);
350b7579f77SDag-Erling Smørgrav 		(*table->deldatafunc)(d, cb_arg);
351b7579f77SDag-Erling Smørgrav 		reclaimlist = n;
352b7579f77SDag-Erling Smørgrav 	}
353b7579f77SDag-Erling Smørgrav }
354b7579f77SDag-Erling Smørgrav 
355b7579f77SDag-Erling Smørgrav struct lruhash_entry*
3563005e0a3SDag-Erling Smørgrav lruhash_lookup(struct lruhash* table, hashvalue_type hash, void* key, int wr)
357b7579f77SDag-Erling Smørgrav {
358b7579f77SDag-Erling Smørgrav 	struct lruhash_entry* entry;
359b7579f77SDag-Erling Smørgrav 	struct lruhash_bin* bin;
360b7579f77SDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_hash_compfunc(table->compfunc));
361b7579f77SDag-Erling Smørgrav 
362b7579f77SDag-Erling Smørgrav 	lock_quick_lock(&table->lock);
363b7579f77SDag-Erling Smørgrav 	bin = &table->array[hash & table->size_mask];
364b7579f77SDag-Erling Smørgrav 	lock_quick_lock(&bin->lock);
365b7579f77SDag-Erling Smørgrav 	if((entry=bin_find_entry(table, bin, hash, key)))
366b7579f77SDag-Erling Smørgrav 		lru_touch(table, entry);
367b7579f77SDag-Erling Smørgrav 	lock_quick_unlock(&table->lock);
368b7579f77SDag-Erling Smørgrav 
369b7579f77SDag-Erling Smørgrav 	if(entry) {
370b7579f77SDag-Erling Smørgrav 		if(wr)	{ lock_rw_wrlock(&entry->lock); }
371b7579f77SDag-Erling Smørgrav 		else	{ lock_rw_rdlock(&entry->lock); }
372b7579f77SDag-Erling Smørgrav 	}
373b7579f77SDag-Erling Smørgrav 	lock_quick_unlock(&bin->lock);
374b7579f77SDag-Erling Smørgrav 	return entry;
375b7579f77SDag-Erling Smørgrav }
376b7579f77SDag-Erling Smørgrav 
377b7579f77SDag-Erling Smørgrav void
3783005e0a3SDag-Erling Smørgrav lruhash_remove(struct lruhash* table, hashvalue_type hash, void* key)
379b7579f77SDag-Erling Smørgrav {
380b7579f77SDag-Erling Smørgrav 	struct lruhash_entry* entry;
381b7579f77SDag-Erling Smørgrav 	struct lruhash_bin* bin;
382b7579f77SDag-Erling Smørgrav 	void *d;
383b7579f77SDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_hash_sizefunc(table->sizefunc));
384b7579f77SDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_hash_delkeyfunc(table->delkeyfunc));
385b7579f77SDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_hash_deldatafunc(table->deldatafunc));
386b7579f77SDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_hash_compfunc(table->compfunc));
387b7579f77SDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_hash_markdelfunc(table->markdelfunc));
388b7579f77SDag-Erling Smørgrav 
389b7579f77SDag-Erling Smørgrav 	lock_quick_lock(&table->lock);
390b7579f77SDag-Erling Smørgrav 	bin = &table->array[hash & table->size_mask];
391b7579f77SDag-Erling Smørgrav 	lock_quick_lock(&bin->lock);
392b7579f77SDag-Erling Smørgrav 	if((entry=bin_find_entry(table, bin, hash, key))) {
393b7579f77SDag-Erling Smørgrav 		bin_overflow_remove(bin, entry);
394b7579f77SDag-Erling Smørgrav 		lru_remove(table, entry);
395b7579f77SDag-Erling Smørgrav 	} else {
396b7579f77SDag-Erling Smørgrav 		lock_quick_unlock(&table->lock);
397b7579f77SDag-Erling Smørgrav 		lock_quick_unlock(&bin->lock);
398b7579f77SDag-Erling Smørgrav 		return;
399b7579f77SDag-Erling Smørgrav 	}
400b7579f77SDag-Erling Smørgrav 	table->num--;
401b7579f77SDag-Erling Smørgrav 	table->space_used -= (*table->sizefunc)(entry->key, entry->data);
402b7579f77SDag-Erling Smørgrav 	lock_quick_unlock(&table->lock);
403b7579f77SDag-Erling Smørgrav 	lock_rw_wrlock(&entry->lock);
404b7579f77SDag-Erling Smørgrav 	if(table->markdelfunc)
405b7579f77SDag-Erling Smørgrav 		(*table->markdelfunc)(entry->key);
406b7579f77SDag-Erling Smørgrav 	lock_rw_unlock(&entry->lock);
407b7579f77SDag-Erling Smørgrav 	lock_quick_unlock(&bin->lock);
408b7579f77SDag-Erling Smørgrav 	/* finish removal */
409b7579f77SDag-Erling Smørgrav 	d = entry->data;
410b7579f77SDag-Erling Smørgrav 	(*table->delkeyfunc)(entry->key, table->cb_arg);
411b7579f77SDag-Erling Smørgrav 	(*table->deldatafunc)(d, table->cb_arg);
412b7579f77SDag-Erling Smørgrav }
413b7579f77SDag-Erling Smørgrav 
414b7579f77SDag-Erling Smørgrav /** clear bin, respecting locks, does not do space, LRU */
415b7579f77SDag-Erling Smørgrav static void
416b7579f77SDag-Erling Smørgrav bin_clear(struct lruhash* table, struct lruhash_bin* bin)
417b7579f77SDag-Erling Smørgrav {
418b7579f77SDag-Erling Smørgrav 	struct lruhash_entry* p, *np;
419b7579f77SDag-Erling Smørgrav 	void *d;
420b7579f77SDag-Erling Smørgrav 	lock_quick_lock(&bin->lock);
421b7579f77SDag-Erling Smørgrav 	p = bin->overflow_list;
422b7579f77SDag-Erling Smørgrav 	while(p) {
423b7579f77SDag-Erling Smørgrav 		lock_rw_wrlock(&p->lock);
424b7579f77SDag-Erling Smørgrav 		np = p->overflow_next;
425b7579f77SDag-Erling Smørgrav 		d = p->data;
426b7579f77SDag-Erling Smørgrav 		if(table->markdelfunc)
427b7579f77SDag-Erling Smørgrav 			(*table->markdelfunc)(p->key);
428b7579f77SDag-Erling Smørgrav 		lock_rw_unlock(&p->lock);
429b7579f77SDag-Erling Smørgrav 		(*table->delkeyfunc)(p->key, table->cb_arg);
430b7579f77SDag-Erling Smørgrav 		(*table->deldatafunc)(d, table->cb_arg);
431b7579f77SDag-Erling Smørgrav 		p = np;
432b7579f77SDag-Erling Smørgrav 	}
433b7579f77SDag-Erling Smørgrav 	bin->overflow_list = NULL;
434b7579f77SDag-Erling Smørgrav 	lock_quick_unlock(&bin->lock);
435b7579f77SDag-Erling Smørgrav }
436b7579f77SDag-Erling Smørgrav 
437b7579f77SDag-Erling Smørgrav void
438b7579f77SDag-Erling Smørgrav lruhash_clear(struct lruhash* table)
439b7579f77SDag-Erling Smørgrav {
440b7579f77SDag-Erling Smørgrav 	size_t i;
441b7579f77SDag-Erling Smørgrav 	if(!table)
442b7579f77SDag-Erling Smørgrav 		return;
443b7579f77SDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_hash_delkeyfunc(table->delkeyfunc));
444b7579f77SDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_hash_deldatafunc(table->deldatafunc));
445b7579f77SDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_hash_markdelfunc(table->markdelfunc));
446b7579f77SDag-Erling Smørgrav 
447b7579f77SDag-Erling Smørgrav 	lock_quick_lock(&table->lock);
448b7579f77SDag-Erling Smørgrav 	for(i=0; i<table->size; i++) {
449b7579f77SDag-Erling Smørgrav 		bin_clear(table, &table->array[i]);
450b7579f77SDag-Erling Smørgrav 	}
451b7579f77SDag-Erling Smørgrav 	table->lru_start = NULL;
452b7579f77SDag-Erling Smørgrav 	table->lru_end = NULL;
453b7579f77SDag-Erling Smørgrav 	table->num = 0;
454b7579f77SDag-Erling Smørgrav 	table->space_used = 0;
455b7579f77SDag-Erling Smørgrav 	lock_quick_unlock(&table->lock);
456b7579f77SDag-Erling Smørgrav }
457b7579f77SDag-Erling Smørgrav 
458b7579f77SDag-Erling Smørgrav void
459b7579f77SDag-Erling Smørgrav lruhash_status(struct lruhash* table, const char* id, int extended)
460b7579f77SDag-Erling Smørgrav {
461b7579f77SDag-Erling Smørgrav 	lock_quick_lock(&table->lock);
462b7579f77SDag-Erling Smørgrav 	log_info("%s: %u entries, memory %u / %u",
463b7579f77SDag-Erling Smørgrav 		id, (unsigned)table->num, (unsigned)table->space_used,
464b7579f77SDag-Erling Smørgrav 		(unsigned)table->space_max);
465b7579f77SDag-Erling Smørgrav 	log_info("  itemsize %u, array %u, mask %d",
466b7579f77SDag-Erling Smørgrav 		(unsigned)(table->num? table->space_used/table->num : 0),
467b7579f77SDag-Erling Smørgrav 		(unsigned)table->size, table->size_mask);
468b7579f77SDag-Erling Smørgrav 	if(extended) {
469b7579f77SDag-Erling Smørgrav 		size_t i;
470b7579f77SDag-Erling Smørgrav 		int min=(int)table->size*2, max=-2;
471b7579f77SDag-Erling Smørgrav 		for(i=0; i<table->size; i++) {
472b7579f77SDag-Erling Smørgrav 			int here = 0;
473b7579f77SDag-Erling Smørgrav 			struct lruhash_entry *en;
474b7579f77SDag-Erling Smørgrav 			lock_quick_lock(&table->array[i].lock);
475b7579f77SDag-Erling Smørgrav 			en = table->array[i].overflow_list;
476b7579f77SDag-Erling Smørgrav 			while(en) {
477b7579f77SDag-Erling Smørgrav 				here ++;
478b7579f77SDag-Erling Smørgrav 				en = en->overflow_next;
479b7579f77SDag-Erling Smørgrav 			}
480b7579f77SDag-Erling Smørgrav 			lock_quick_unlock(&table->array[i].lock);
481b7579f77SDag-Erling Smørgrav 			if(extended >= 2)
482b7579f77SDag-Erling Smørgrav 				log_info("bin[%d] %d", (int)i, here);
483b7579f77SDag-Erling Smørgrav 			if(here > max) max = here;
484b7579f77SDag-Erling Smørgrav 			if(here < min) min = here;
485b7579f77SDag-Erling Smørgrav 		}
486b7579f77SDag-Erling Smørgrav 		log_info("  bin min %d, avg %.2lf, max %d", min,
487b7579f77SDag-Erling Smørgrav 			(double)table->num/(double)table->size, max);
488b7579f77SDag-Erling Smørgrav 	}
489b7579f77SDag-Erling Smørgrav 	lock_quick_unlock(&table->lock);
490b7579f77SDag-Erling Smørgrav }
491b7579f77SDag-Erling Smørgrav 
492b7579f77SDag-Erling Smørgrav size_t
493b7579f77SDag-Erling Smørgrav lruhash_get_mem(struct lruhash* table)
494b7579f77SDag-Erling Smørgrav {
495b7579f77SDag-Erling Smørgrav 	size_t s;
496b7579f77SDag-Erling Smørgrav 	lock_quick_lock(&table->lock);
497b7579f77SDag-Erling Smørgrav 	s = sizeof(struct lruhash) + table->space_used;
498b7579f77SDag-Erling Smørgrav #ifdef USE_THREAD_DEBUG
499b7579f77SDag-Erling Smørgrav 	if(table->size != 0) {
500b7579f77SDag-Erling Smørgrav 		size_t i;
501b7579f77SDag-Erling Smørgrav 		for(i=0; i<table->size; i++)
502b7579f77SDag-Erling Smørgrav 			s += sizeof(struct lruhash_bin) +
503b7579f77SDag-Erling Smørgrav 				lock_get_mem(&table->array[i].lock);
504b7579f77SDag-Erling Smørgrav 	}
505b7579f77SDag-Erling Smørgrav #else /* no THREAD_DEBUG */
506b7579f77SDag-Erling Smørgrav 	if(table->size != 0)
507b7579f77SDag-Erling Smørgrav 		s += (table->size)*(sizeof(struct lruhash_bin) +
508b7579f77SDag-Erling Smørgrav 			lock_get_mem(&table->array[0].lock));
509b7579f77SDag-Erling Smørgrav #endif
510b7579f77SDag-Erling Smørgrav 	lock_quick_unlock(&table->lock);
511b7579f77SDag-Erling Smørgrav 	s += lock_get_mem(&table->lock);
512b7579f77SDag-Erling Smørgrav 	return s;
513b7579f77SDag-Erling Smørgrav }
514b7579f77SDag-Erling Smørgrav 
515b7579f77SDag-Erling Smørgrav void
5163005e0a3SDag-Erling Smørgrav lruhash_setmarkdel(struct lruhash* table, lruhash_markdelfunc_type md)
517b7579f77SDag-Erling Smørgrav {
518b7579f77SDag-Erling Smørgrav 	lock_quick_lock(&table->lock);
519b7579f77SDag-Erling Smørgrav 	table->markdelfunc = md;
520b7579f77SDag-Erling Smørgrav 	lock_quick_unlock(&table->lock);
521b7579f77SDag-Erling Smørgrav }
522b7579f77SDag-Erling Smørgrav 
523b7579f77SDag-Erling Smørgrav void
524b7579f77SDag-Erling Smørgrav lruhash_traverse(struct lruhash* h, int wr,
525b7579f77SDag-Erling Smørgrav 	void (*func)(struct lruhash_entry*, void*), void* arg)
526b7579f77SDag-Erling Smørgrav {
527b7579f77SDag-Erling Smørgrav 	size_t i;
528b7579f77SDag-Erling Smørgrav 	struct lruhash_entry* e;
529b7579f77SDag-Erling Smørgrav 
530b7579f77SDag-Erling Smørgrav 	lock_quick_lock(&h->lock);
531b7579f77SDag-Erling Smørgrav 	for(i=0; i<h->size; i++) {
532b7579f77SDag-Erling Smørgrav 		lock_quick_lock(&h->array[i].lock);
533b7579f77SDag-Erling Smørgrav 		for(e = h->array[i].overflow_list; e; e = e->overflow_next) {
534b7579f77SDag-Erling Smørgrav 			if(wr) {
535b7579f77SDag-Erling Smørgrav 				lock_rw_wrlock(&e->lock);
536b7579f77SDag-Erling Smørgrav 			} else {
537b7579f77SDag-Erling Smørgrav 				lock_rw_rdlock(&e->lock);
538b7579f77SDag-Erling Smørgrav 			}
539b7579f77SDag-Erling Smørgrav 			(*func)(e, arg);
540b7579f77SDag-Erling Smørgrav 			lock_rw_unlock(&e->lock);
541b7579f77SDag-Erling Smørgrav 		}
542b7579f77SDag-Erling Smørgrav 		lock_quick_unlock(&h->array[i].lock);
543b7579f77SDag-Erling Smørgrav 	}
544b7579f77SDag-Erling Smørgrav 	lock_quick_unlock(&h->lock);
545b7579f77SDag-Erling Smørgrav }
546*65b390aaSDag-Erling Smørgrav 
547*65b390aaSDag-Erling Smørgrav /*
548*65b390aaSDag-Erling Smørgrav  * Demote: the opposite of touch, move an entry to the bottom
549*65b390aaSDag-Erling Smørgrav  * of the LRU pile.
550*65b390aaSDag-Erling Smørgrav  */
551*65b390aaSDag-Erling Smørgrav 
552*65b390aaSDag-Erling Smørgrav void
553*65b390aaSDag-Erling Smørgrav lru_demote(struct lruhash* table, struct lruhash_entry* entry)
554*65b390aaSDag-Erling Smørgrav {
555*65b390aaSDag-Erling Smørgrav 	log_assert(table && entry);
556*65b390aaSDag-Erling Smørgrav 	if (entry == table->lru_end)
557*65b390aaSDag-Erling Smørgrav 		return; /* nothing to do */
558*65b390aaSDag-Erling Smørgrav 	/* remove from current lru position */
559*65b390aaSDag-Erling Smørgrav 	lru_remove(table, entry);
560*65b390aaSDag-Erling Smørgrav 	/* add at end */
561*65b390aaSDag-Erling Smørgrav 	entry->lru_next = NULL;
562*65b390aaSDag-Erling Smørgrav 	entry->lru_prev = table->lru_end;
563*65b390aaSDag-Erling Smørgrav 
564*65b390aaSDag-Erling Smørgrav 	if (table->lru_end == NULL)
565*65b390aaSDag-Erling Smørgrav 	{
566*65b390aaSDag-Erling Smørgrav 		table->lru_start = entry;
567*65b390aaSDag-Erling Smørgrav 	}
568*65b390aaSDag-Erling Smørgrav 	else
569*65b390aaSDag-Erling Smørgrav 	{
570*65b390aaSDag-Erling Smørgrav 		table->lru_end->lru_next = entry;
571*65b390aaSDag-Erling Smørgrav 	}
572*65b390aaSDag-Erling Smørgrav 	table->lru_end = entry;
573*65b390aaSDag-Erling Smørgrav }
574*65b390aaSDag-Erling Smørgrav 
575*65b390aaSDag-Erling Smørgrav struct lruhash_entry*
576*65b390aaSDag-Erling Smørgrav lruhash_insert_or_retrieve(struct lruhash* table, hashvalue_type hash,
577*65b390aaSDag-Erling Smørgrav 	struct lruhash_entry* entry, void* data, void* cb_arg)
578*65b390aaSDag-Erling Smørgrav {
579*65b390aaSDag-Erling Smørgrav 	struct lruhash_bin* bin;
580*65b390aaSDag-Erling Smørgrav 	struct lruhash_entry* found, *reclaimlist = NULL;
581*65b390aaSDag-Erling Smørgrav 	size_t need_size;
582*65b390aaSDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_hash_sizefunc(table->sizefunc));
583*65b390aaSDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_hash_delkeyfunc(table->delkeyfunc));
584*65b390aaSDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_hash_deldatafunc(table->deldatafunc));
585*65b390aaSDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_hash_compfunc(table->compfunc));
586*65b390aaSDag-Erling Smørgrav 	fptr_ok(fptr_whitelist_hash_markdelfunc(table->markdelfunc));
587*65b390aaSDag-Erling Smørgrav 	need_size = table->sizefunc(entry->key, data);
588*65b390aaSDag-Erling Smørgrav 	if (cb_arg == NULL) cb_arg = table->cb_arg;
589*65b390aaSDag-Erling Smørgrav 
590*65b390aaSDag-Erling Smørgrav 	/* find bin */
591*65b390aaSDag-Erling Smørgrav 	lock_quick_lock(&table->lock);
592*65b390aaSDag-Erling Smørgrav 	bin = &table->array[hash & table->size_mask];
593*65b390aaSDag-Erling Smørgrav 	lock_quick_lock(&bin->lock);
594*65b390aaSDag-Erling Smørgrav 
595*65b390aaSDag-Erling Smørgrav 	/* see if entry exists already */
596*65b390aaSDag-Erling Smørgrav 	if ((found = bin_find_entry(table, bin, hash, entry->key)) != NULL) {
597*65b390aaSDag-Erling Smørgrav 		/* if so: keep the existing data - acquire a writelock */
598*65b390aaSDag-Erling Smørgrav 		lock_rw_wrlock(&found->lock);
599*65b390aaSDag-Erling Smørgrav 	}
600*65b390aaSDag-Erling Smørgrav 	else
601*65b390aaSDag-Erling Smørgrav 	{
602*65b390aaSDag-Erling Smørgrav 		/* if not: add to bin */
603*65b390aaSDag-Erling Smørgrav 		entry->overflow_next = bin->overflow_list;
604*65b390aaSDag-Erling Smørgrav 		bin->overflow_list = entry;
605*65b390aaSDag-Erling Smørgrav 		lru_front(table, entry);
606*65b390aaSDag-Erling Smørgrav 		table->num++;
607*65b390aaSDag-Erling Smørgrav 		table->space_used += need_size;
608*65b390aaSDag-Erling Smørgrav 		/* return the entry that was presented, and lock it */
609*65b390aaSDag-Erling Smørgrav 		found = entry;
610*65b390aaSDag-Erling Smørgrav 		lock_rw_wrlock(&found->lock);
611*65b390aaSDag-Erling Smørgrav 	}
612*65b390aaSDag-Erling Smørgrav 	lock_quick_unlock(&bin->lock);
613*65b390aaSDag-Erling Smørgrav 	if (table->space_used > table->space_max)
614*65b390aaSDag-Erling Smørgrav 		reclaim_space(table, &reclaimlist);
615*65b390aaSDag-Erling Smørgrav 	if (table->num >= table->size)
616*65b390aaSDag-Erling Smørgrav 		table_grow(table);
617*65b390aaSDag-Erling Smørgrav 	lock_quick_unlock(&table->lock);
618*65b390aaSDag-Erling Smørgrav 
619*65b390aaSDag-Erling Smørgrav 	/* finish reclaim if any (outside of critical region) */
620*65b390aaSDag-Erling Smørgrav 	while (reclaimlist) {
621*65b390aaSDag-Erling Smørgrav 		struct lruhash_entry* n = reclaimlist->overflow_next;
622*65b390aaSDag-Erling Smørgrav 		void* d = reclaimlist->data;
623*65b390aaSDag-Erling Smørgrav 		(*table->delkeyfunc)(reclaimlist->key, cb_arg);
624*65b390aaSDag-Erling Smørgrav 		(*table->deldatafunc)(d, cb_arg);
625*65b390aaSDag-Erling Smørgrav 		reclaimlist = n;
626*65b390aaSDag-Erling Smørgrav 	}
627*65b390aaSDag-Erling Smørgrav 
628*65b390aaSDag-Erling Smørgrav 	/* return the entry that was selected */
629*65b390aaSDag-Erling Smørgrav 	return found;
630*65b390aaSDag-Erling Smørgrav }
631*65b390aaSDag-Erling Smørgrav 
632