1b7579f77SDag-Erling Smørgrav /* 2b7579f77SDag-Erling Smørgrav * util/storage/lruhash.h - 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 * The hash table keeps a maximum memory size. Old entries are removed 42b7579f77SDag-Erling Smørgrav * to make space for new entries. 43b7579f77SDag-Erling Smørgrav * 44b7579f77SDag-Erling Smørgrav * The locking strategy is as follows: 45b7579f77SDag-Erling Smørgrav * o since (almost) every read also implies a LRU update, the 46b7579f77SDag-Erling Smørgrav * hashtable lock is a spinlock, not rwlock. 47b7579f77SDag-Erling Smørgrav * o the idea is to move every thread through the hash lock quickly, 48b7579f77SDag-Erling Smørgrav * so that the next thread can access the lookup table. 49b7579f77SDag-Erling Smørgrav * o User performs hash function. 50b7579f77SDag-Erling Smørgrav * 51b7579f77SDag-Erling Smørgrav * For read: 52b7579f77SDag-Erling Smørgrav * o lock hashtable. 53b7579f77SDag-Erling Smørgrav * o lookup hash bin. 54b7579f77SDag-Erling Smørgrav * o lock hash bin. 55b7579f77SDag-Erling Smørgrav * o find entry (if failed, unlock hash, unl bin, exit). 56b7579f77SDag-Erling Smørgrav * o swizzle pointers for LRU update. 57b7579f77SDag-Erling Smørgrav * o unlock hashtable. 58b7579f77SDag-Erling Smørgrav * o lock entry (rwlock). 59b7579f77SDag-Erling Smørgrav * o unlock hash bin. 60b7579f77SDag-Erling Smørgrav * o work on entry. 61b7579f77SDag-Erling Smørgrav * o unlock entry. 62b7579f77SDag-Erling Smørgrav * 63b7579f77SDag-Erling Smørgrav * To update an entry, gain writelock and change the entry. 64b7579f77SDag-Erling Smørgrav * (the entry must keep the same hashvalue, so a data update.) 65b7579f77SDag-Erling Smørgrav * (you cannot upgrade a readlock to a writelock, because the item may 66b7579f77SDag-Erling Smørgrav * be deleted, it would cause race conditions. So instead, unlock and 67b7579f77SDag-Erling Smørgrav * relookup it in the hashtable.) 68b7579f77SDag-Erling Smørgrav * 69b7579f77SDag-Erling Smørgrav * To delete an entry: 70b7579f77SDag-Erling Smørgrav * o unlock the entry if you hold the lock already. 71b7579f77SDag-Erling Smørgrav * o lock hashtable. 72b7579f77SDag-Erling Smørgrav * o lookup hash bin. 73b7579f77SDag-Erling Smørgrav * o lock hash bin. 74b7579f77SDag-Erling Smørgrav * o find entry (if failed, unlock hash, unl bin, exit). 75b7579f77SDag-Erling Smørgrav * o remove entry from hashtable bin overflow chain. 76b7579f77SDag-Erling Smørgrav * o unlock hashtable. 77b7579f77SDag-Erling Smørgrav * o lock entry (writelock). 78b7579f77SDag-Erling Smørgrav * o unlock hash bin. 79b7579f77SDag-Erling Smørgrav * o unlock entry (nobody else should be waiting for this lock, 80b7579f77SDag-Erling Smørgrav * since you removed it from hashtable, and you got writelock while 81b7579f77SDag-Erling Smørgrav * holding the hashbinlock so you are the only one.) 82b7579f77SDag-Erling Smørgrav * Note you are only allowed to obtain a lock while holding hashbinlock. 83b7579f77SDag-Erling Smørgrav * o delete entry. 84b7579f77SDag-Erling Smørgrav * 85b7579f77SDag-Erling Smørgrav * The above sequence is: 86b7579f77SDag-Erling Smørgrav * o race free, works with read, write and delete. 87b7579f77SDag-Erling Smørgrav * o but has a queue, imagine someone needing a writelock on an item. 88b7579f77SDag-Erling Smørgrav * but there are still readlocks. The writelocker waits, but holds 89b7579f77SDag-Erling Smørgrav * the hashbinlock. The next thread that comes in and needs the same 90b7579f77SDag-Erling Smørgrav * hashbin will wait for the lock while holding the hashtable lock. 91b7579f77SDag-Erling Smørgrav * thus halting the entire system on hashtable. 92b7579f77SDag-Erling Smørgrav * This is because of the delete protection. 93b7579f77SDag-Erling Smørgrav * Readlocks will be easier on the rwlock on entries. 94b7579f77SDag-Erling Smørgrav * While the writer is holding writelock, similar problems happen with 95b7579f77SDag-Erling Smørgrav * a reader or writer needing the same item. 96b7579f77SDag-Erling Smørgrav * the scenario requires more than three threads. 97b7579f77SDag-Erling Smørgrav * o so the queue length is 3 threads in a bad situation. The fourth is 98b7579f77SDag-Erling Smørgrav * unable to use the hashtable. 99b7579f77SDag-Erling Smørgrav * 100b7579f77SDag-Erling Smørgrav * If you need to acquire locks on multiple items from the hashtable. 101b7579f77SDag-Erling Smørgrav * o you MUST release all locks on items from the hashtable before 102b7579f77SDag-Erling Smørgrav * doing the next lookup/insert/delete/whatever. 103b7579f77SDag-Erling Smørgrav * o To acquire multiple items you should use a special routine that 104b7579f77SDag-Erling Smørgrav * obtains the locks on those multiple items in one go. 105b7579f77SDag-Erling Smørgrav */ 106b7579f77SDag-Erling Smørgrav 107b7579f77SDag-Erling Smørgrav #ifndef UTIL_STORAGE_LRUHASH_H 108b7579f77SDag-Erling Smørgrav #define UTIL_STORAGE_LRUHASH_H 109b7579f77SDag-Erling Smørgrav #include "util/locks.h" 110b7579f77SDag-Erling Smørgrav struct lruhash_bin; 111b7579f77SDag-Erling Smørgrav struct lruhash_entry; 112b7579f77SDag-Erling Smørgrav 113b7579f77SDag-Erling Smørgrav /** default start size for hash arrays */ 114b7579f77SDag-Erling Smørgrav #define HASH_DEFAULT_STARTARRAY 1024 /* entries in array */ 115b7579f77SDag-Erling Smørgrav /** default max memory for hash arrays */ 116b7579f77SDag-Erling Smørgrav #define HASH_DEFAULT_MAXMEM 4*1024*1024 /* bytes */ 117b7579f77SDag-Erling Smørgrav 118b7579f77SDag-Erling Smørgrav /** the type of a hash value */ 1193005e0a3SDag-Erling Smørgrav typedef uint32_t hashvalue_type; 120b7579f77SDag-Erling Smørgrav 121b7579f77SDag-Erling Smørgrav /** 122b7579f77SDag-Erling Smørgrav * Type of function that calculates the size of an entry. 123b7579f77SDag-Erling Smørgrav * Result must include the size of struct lruhash_entry. 124b7579f77SDag-Erling Smørgrav * Keys that are identical must also calculate to the same size. 125b7579f77SDag-Erling Smørgrav * size = func(key, data). 126b7579f77SDag-Erling Smørgrav */ 1273005e0a3SDag-Erling Smørgrav typedef size_t (*lruhash_sizefunc_type)(void*, void*); 128b7579f77SDag-Erling Smørgrav 129b7579f77SDag-Erling Smørgrav /** type of function that compares two keys. return 0 if equal. */ 1303005e0a3SDag-Erling Smørgrav typedef int (*lruhash_compfunc_type)(void*, void*); 131b7579f77SDag-Erling Smørgrav 132b7579f77SDag-Erling Smørgrav /** old keys are deleted. 133b7579f77SDag-Erling Smørgrav * The RRset type has to revoke its ID number, markdel() is used first. 134b7579f77SDag-Erling Smørgrav * This function is called: func(key, userarg) */ 1353005e0a3SDag-Erling Smørgrav typedef void (*lruhash_delkeyfunc_type)(void*, void*); 136b7579f77SDag-Erling Smørgrav 137b7579f77SDag-Erling Smørgrav /** old data is deleted. This function is called: func(data, userarg). */ 1383005e0a3SDag-Erling Smørgrav typedef void (*lruhash_deldatafunc_type)(void*, void*); 139b7579f77SDag-Erling Smørgrav 140b7579f77SDag-Erling Smørgrav /** mark a key as pending to be deleted (and not to be used by anyone). 141b7579f77SDag-Erling Smørgrav * called: func(key) */ 1423005e0a3SDag-Erling Smørgrav typedef void (*lruhash_markdelfunc_type)(void*); 143b7579f77SDag-Erling Smørgrav 144b7579f77SDag-Erling Smørgrav /** 145b7579f77SDag-Erling Smørgrav * Hash table that keeps LRU list of entries. 146b7579f77SDag-Erling Smørgrav */ 147b7579f77SDag-Erling Smørgrav struct lruhash { 148b7579f77SDag-Erling Smørgrav /** lock for exclusive access, to the lookup array */ 1493005e0a3SDag-Erling Smørgrav lock_quick_type lock; 150b7579f77SDag-Erling Smørgrav /** the size function for entries in this table */ 1513005e0a3SDag-Erling Smørgrav lruhash_sizefunc_type sizefunc; 152b7579f77SDag-Erling Smørgrav /** the compare function for entries in this table. */ 1533005e0a3SDag-Erling Smørgrav lruhash_compfunc_type compfunc; 154b7579f77SDag-Erling Smørgrav /** how to delete keys. */ 1553005e0a3SDag-Erling Smørgrav lruhash_delkeyfunc_type delkeyfunc; 156b7579f77SDag-Erling Smørgrav /** how to delete data. */ 1573005e0a3SDag-Erling Smørgrav lruhash_deldatafunc_type deldatafunc; 158b7579f77SDag-Erling Smørgrav /** how to mark a key pending deletion */ 1593005e0a3SDag-Erling Smørgrav lruhash_markdelfunc_type markdelfunc; 160b7579f77SDag-Erling Smørgrav /** user argument for user functions */ 161b7579f77SDag-Erling Smørgrav void* cb_arg; 162b7579f77SDag-Erling Smørgrav 163b7579f77SDag-Erling Smørgrav /** the size of the lookup array */ 164b7579f77SDag-Erling Smørgrav size_t size; 165b7579f77SDag-Erling Smørgrav /** size bitmask - since size is a power of 2 */ 166b7579f77SDag-Erling Smørgrav int size_mask; 167b7579f77SDag-Erling Smørgrav /** lookup array of bins */ 168b7579f77SDag-Erling Smørgrav struct lruhash_bin* array; 169b7579f77SDag-Erling Smørgrav 170b7579f77SDag-Erling Smørgrav /** the lru list, start and end, noncyclical double linked list. */ 171b7579f77SDag-Erling Smørgrav struct lruhash_entry* lru_start; 172b7579f77SDag-Erling Smørgrav /** lru list end item (least recently used) */ 173b7579f77SDag-Erling Smørgrav struct lruhash_entry* lru_end; 174b7579f77SDag-Erling Smørgrav 175b7579f77SDag-Erling Smørgrav /** the number of entries in the hash table. */ 176b7579f77SDag-Erling Smørgrav size_t num; 177b7579f77SDag-Erling Smørgrav /** the amount of space used, roughly the number of bytes in use. */ 178b7579f77SDag-Erling Smørgrav size_t space_used; 179b7579f77SDag-Erling Smørgrav /** the amount of space the hash table is maximally allowed to use. */ 180b7579f77SDag-Erling Smørgrav size_t space_max; 1818f76bb7dSCy Schubert /** the maximum collisions were detected during the lruhash_insert operations. */ 1828f76bb7dSCy Schubert size_t max_collisions; 183b7579f77SDag-Erling Smørgrav }; 184b7579f77SDag-Erling Smørgrav 185b7579f77SDag-Erling Smørgrav /** 186b7579f77SDag-Erling Smørgrav * A single bin with a linked list of entries in it. 187b7579f77SDag-Erling Smørgrav */ 188b7579f77SDag-Erling Smørgrav struct lruhash_bin { 189b7579f77SDag-Erling Smørgrav /** 190b7579f77SDag-Erling Smørgrav * Lock for exclusive access to the linked list 191b7579f77SDag-Erling Smørgrav * This lock makes deletion of items safe in this overflow list. 192b7579f77SDag-Erling Smørgrav */ 1933005e0a3SDag-Erling Smørgrav lock_quick_type lock; 194b7579f77SDag-Erling Smørgrav /** linked list of overflow entries */ 195b7579f77SDag-Erling Smørgrav struct lruhash_entry* overflow_list; 196b7579f77SDag-Erling Smørgrav }; 197b7579f77SDag-Erling Smørgrav 198b7579f77SDag-Erling Smørgrav /** 199b7579f77SDag-Erling Smørgrav * An entry into the hash table. 200b7579f77SDag-Erling Smørgrav * To change overflow_next you need to hold the bin lock. 201b7579f77SDag-Erling Smørgrav * To change the lru items you need to hold the hashtable lock. 202b7579f77SDag-Erling Smørgrav * This structure is designed as part of key struct. And key pointer helps 203b7579f77SDag-Erling Smørgrav * to get the surrounding structure. Data should be allocated on its own. 204b7579f77SDag-Erling Smørgrav */ 205b7579f77SDag-Erling Smørgrav struct lruhash_entry { 206b7579f77SDag-Erling Smørgrav /** 207b7579f77SDag-Erling Smørgrav * rwlock for access to the contents of the entry 208b7579f77SDag-Erling Smørgrav * Note that it does _not_ cover the lru_ and overflow_ ptrs. 209b7579f77SDag-Erling Smørgrav * Even with a writelock, you cannot change hash and key. 210b7579f77SDag-Erling Smørgrav * You need to delete it to change hash or key. 211b7579f77SDag-Erling Smørgrav */ 2123005e0a3SDag-Erling Smørgrav lock_rw_type lock; 213b7579f77SDag-Erling Smørgrav /** next entry in overflow chain. Covered by hashlock and binlock. */ 214b7579f77SDag-Erling Smørgrav struct lruhash_entry* overflow_next; 215b7579f77SDag-Erling Smørgrav /** next entry in lru chain. covered by hashlock. */ 216b7579f77SDag-Erling Smørgrav struct lruhash_entry* lru_next; 217b7579f77SDag-Erling Smørgrav /** prev entry in lru chain. covered by hashlock. */ 218b7579f77SDag-Erling Smørgrav struct lruhash_entry* lru_prev; 219b7579f77SDag-Erling Smørgrav /** hash value of the key. It may not change, until entry deleted. */ 2203005e0a3SDag-Erling Smørgrav hashvalue_type hash; 221b7579f77SDag-Erling Smørgrav /** key */ 222b7579f77SDag-Erling Smørgrav void* key; 223b7579f77SDag-Erling Smørgrav /** data */ 224b7579f77SDag-Erling Smørgrav void* data; 225b7579f77SDag-Erling Smørgrav }; 226b7579f77SDag-Erling Smørgrav 227b7579f77SDag-Erling Smørgrav /** 228b7579f77SDag-Erling Smørgrav * Create new hash table. 229b7579f77SDag-Erling Smørgrav * @param start_size: size of hashtable array at start, must be power of 2. 230b7579f77SDag-Erling Smørgrav * @param maxmem: maximum amount of memory this table is allowed to use. 231b7579f77SDag-Erling Smørgrav * @param sizefunc: calculates memory usage of entries. 232b7579f77SDag-Erling Smørgrav * @param compfunc: compares entries, 0 on equality. 233b7579f77SDag-Erling Smørgrav * @param delkeyfunc: deletes key. 234b7579f77SDag-Erling Smørgrav * Calling both delkey and deldata will also free the struct lruhash_entry. 235b7579f77SDag-Erling Smørgrav * Make it part of the key structure and delete it in delkeyfunc. 236b7579f77SDag-Erling Smørgrav * @param deldatafunc: deletes data. 237b7579f77SDag-Erling Smørgrav * @param arg: user argument that is passed to user function calls. 238b7579f77SDag-Erling Smørgrav * @return: new hash table or NULL on malloc failure. 239b7579f77SDag-Erling Smørgrav */ 240b7579f77SDag-Erling Smørgrav struct lruhash* lruhash_create(size_t start_size, size_t maxmem, 2413005e0a3SDag-Erling Smørgrav lruhash_sizefunc_type sizefunc, lruhash_compfunc_type compfunc, 2423005e0a3SDag-Erling Smørgrav lruhash_delkeyfunc_type delkeyfunc, 2433005e0a3SDag-Erling Smørgrav lruhash_deldatafunc_type deldatafunc, void* arg); 244b7579f77SDag-Erling Smørgrav 245b7579f77SDag-Erling Smørgrav /** 246b7579f77SDag-Erling Smørgrav * Delete hash table. Entries are all deleted. 247b7579f77SDag-Erling Smørgrav * @param table: to delete. 248b7579f77SDag-Erling Smørgrav */ 249b7579f77SDag-Erling Smørgrav void lruhash_delete(struct lruhash* table); 250b7579f77SDag-Erling Smørgrav 251b7579f77SDag-Erling Smørgrav /** 252b7579f77SDag-Erling Smørgrav * Clear hash table. Entries are all deleted, while locking them before 253b7579f77SDag-Erling Smørgrav * doing so. At end the table is empty. 254b7579f77SDag-Erling Smørgrav * @param table: to make empty. 255b7579f77SDag-Erling Smørgrav */ 256b7579f77SDag-Erling Smørgrav void lruhash_clear(struct lruhash* table); 257b7579f77SDag-Erling Smørgrav 258b7579f77SDag-Erling Smørgrav /** 259b7579f77SDag-Erling Smørgrav * Insert a new element into the hashtable. 260b7579f77SDag-Erling Smørgrav * If key is already present data pointer in that entry is updated. 261b7579f77SDag-Erling Smørgrav * The space calculation function is called with the key, data. 262b7579f77SDag-Erling Smørgrav * If necessary the least recently used entries are deleted to make space. 263b7579f77SDag-Erling Smørgrav * If necessary the hash array is grown up. 264b7579f77SDag-Erling Smørgrav * 265b7579f77SDag-Erling Smørgrav * @param table: hash table. 266b7579f77SDag-Erling Smørgrav * @param hash: hash value. User calculates the hash. 267b7579f77SDag-Erling Smørgrav * @param entry: identifies the entry. 268b7579f77SDag-Erling Smørgrav * If key already present, this entry->key is deleted immediately. 269b7579f77SDag-Erling Smørgrav * But entry->data is set to NULL before deletion, and put into 270b7579f77SDag-Erling Smørgrav * the existing entry. The data is then freed. 271b7579f77SDag-Erling Smørgrav * @param data: the data. 272b7579f77SDag-Erling Smørgrav * @param cb_override: if not null overrides the cb_arg for the deletefunc. 273b7579f77SDag-Erling Smørgrav */ 2743005e0a3SDag-Erling Smørgrav void lruhash_insert(struct lruhash* table, hashvalue_type hash, 275b7579f77SDag-Erling Smørgrav struct lruhash_entry* entry, void* data, void* cb_override); 276b7579f77SDag-Erling Smørgrav 277b7579f77SDag-Erling Smørgrav /** 278b7579f77SDag-Erling Smørgrav * Lookup an entry in the hashtable. 279b7579f77SDag-Erling Smørgrav * At the end of the function you hold a (read/write)lock on the entry. 280b7579f77SDag-Erling Smørgrav * The LRU is updated for the entry (if found). 281b7579f77SDag-Erling Smørgrav * @param table: hash table. 282b7579f77SDag-Erling Smørgrav * @param hash: hash of key. 283b7579f77SDag-Erling Smørgrav * @param key: what to look for, compared against entries in overflow chain. 284b7579f77SDag-Erling Smørgrav * the hash value must be set, and must work with compare function. 285b7579f77SDag-Erling Smørgrav * @param wr: set to true if you desire a writelock on the entry. 286b7579f77SDag-Erling Smørgrav * with a writelock you can update the data part. 287b7579f77SDag-Erling Smørgrav * @return: pointer to the entry or NULL. The entry is locked. 288b7579f77SDag-Erling Smørgrav * The user must unlock the entry when done. 289b7579f77SDag-Erling Smørgrav */ 2903005e0a3SDag-Erling Smørgrav struct lruhash_entry* lruhash_lookup(struct lruhash* table, 2913005e0a3SDag-Erling Smørgrav hashvalue_type hash, void* key, int wr); 292b7579f77SDag-Erling Smørgrav 293b7579f77SDag-Erling Smørgrav /** 294b7579f77SDag-Erling Smørgrav * Touch entry, so it becomes the most recently used in the LRU list. 295b7579f77SDag-Erling Smørgrav * Caller must hold hash table lock. The entry must be inserted already. 296b7579f77SDag-Erling Smørgrav * @param table: hash table. 297b7579f77SDag-Erling Smørgrav * @param entry: entry to make first in LRU. 298b7579f77SDag-Erling Smørgrav */ 299b7579f77SDag-Erling Smørgrav void lru_touch(struct lruhash* table, struct lruhash_entry* entry); 300b7579f77SDag-Erling Smørgrav 301b7579f77SDag-Erling Smørgrav /** 302b7579f77SDag-Erling Smørgrav * Set the markdelfunction (or NULL) 303b7579f77SDag-Erling Smørgrav */ 3043005e0a3SDag-Erling Smørgrav void lruhash_setmarkdel(struct lruhash* table, lruhash_markdelfunc_type md); 305b7579f77SDag-Erling Smørgrav 306335c7cdaSCy Schubert /** 307335c7cdaSCy Schubert * Update the size of an element in the hashtable. 308335c7cdaSCy Schubert * 309335c7cdaSCy Schubert * @param table: hash table. 310335c7cdaSCy Schubert * @param cb_override: if not NULL overrides the cb_arg for deletefunc. 311335c7cdaSCy Schubert * @param diff_size: difference in size to the hash table storage. 312335c7cdaSCy Schubert * This is newsize - oldsize, a positive number uses more space. 313335c7cdaSCy Schubert */ 314335c7cdaSCy Schubert void lruhash_update_space_used(struct lruhash* table, void* cb_override, 315335c7cdaSCy Schubert int diff_size); 316335c7cdaSCy Schubert 317*be771a7bSCy Schubert /** 318*be771a7bSCy Schubert * Update the max space for the hashtable. 319*be771a7bSCy Schubert * 320*be771a7bSCy Schubert * @param table: hash table. 321*be771a7bSCy Schubert * @param cb_override: if not NULL overrides the cb_arg for deletefunc. 322*be771a7bSCy Schubert * @param max: the new max. 323*be771a7bSCy Schubert */ 324*be771a7bSCy Schubert void lruhash_update_space_max(struct lruhash* table, void* cb_override, 325*be771a7bSCy Schubert size_t max); 326*be771a7bSCy Schubert 32765b390aaSDag-Erling Smørgrav /************************* getdns functions ************************/ 32865b390aaSDag-Erling Smørgrav /*** these are used by getdns only and not by unbound. ***/ 32965b390aaSDag-Erling Smørgrav 33065b390aaSDag-Erling Smørgrav /** 33165b390aaSDag-Erling Smørgrav * Demote entry, so it becomes the least recently used in the LRU list. 33265b390aaSDag-Erling Smørgrav * Caller must hold hash table lock. The entry must be inserted already. 33365b390aaSDag-Erling Smørgrav * @param table: hash table. 33465b390aaSDag-Erling Smørgrav * @param entry: entry to make last in LRU. 33565b390aaSDag-Erling Smørgrav */ 33665b390aaSDag-Erling Smørgrav void lru_demote(struct lruhash* table, struct lruhash_entry* entry); 33765b390aaSDag-Erling Smørgrav 33865b390aaSDag-Erling Smørgrav /** 33965b390aaSDag-Erling Smørgrav * Insert a new element into the hashtable, or retrieve the corresponding 34065b390aaSDag-Erling Smørgrav * element of it exits. 34165b390aaSDag-Erling Smørgrav * 34265b390aaSDag-Erling Smørgrav * If key is already present data pointer in that entry is kept. 34365b390aaSDag-Erling Smørgrav * If it is not present, a new entry is created. In that case, 34465b390aaSDag-Erling Smørgrav * the space calculation function is called with the key, data. 34565b390aaSDag-Erling Smørgrav * If necessary the least recently used entries are deleted to make space. 34665b390aaSDag-Erling Smørgrav * If necessary the hash array is grown up. 34765b390aaSDag-Erling Smørgrav * 34865b390aaSDag-Erling Smørgrav * @param table: hash table. 34965b390aaSDag-Erling Smørgrav * @param hash: hash value. User calculates the hash. 35065b390aaSDag-Erling Smørgrav * @param entry: identifies the entry. 35165b390aaSDag-Erling Smørgrav * @param data: the data. 35265b390aaSDag-Erling Smørgrav * @param cb_arg: if not null overrides the cb_arg for the deletefunc. 35365b390aaSDag-Erling Smørgrav * @return: pointer to the existing entry if the key was already present, 35465b390aaSDag-Erling Smørgrav * or to the entry argument if it was not. 35565b390aaSDag-Erling Smørgrav */ 35665b390aaSDag-Erling Smørgrav struct lruhash_entry* lruhash_insert_or_retrieve(struct lruhash* table, hashvalue_type hash, 35765b390aaSDag-Erling Smørgrav struct lruhash_entry* entry, void* data, void* cb_arg); 35865b390aaSDag-Erling Smørgrav 359b7579f77SDag-Erling Smørgrav /************************* Internal functions ************************/ 360b7579f77SDag-Erling Smørgrav /*** these are only exposed for unit tests. ***/ 361b7579f77SDag-Erling Smørgrav 362b7579f77SDag-Erling Smørgrav /** 363b7579f77SDag-Erling Smørgrav * Remove entry from hashtable. Does nothing if not found in hashtable. 364b7579f77SDag-Erling Smørgrav * Delfunc is called for the entry. 365b7579f77SDag-Erling Smørgrav * @param table: hash table. 366b7579f77SDag-Erling Smørgrav * @param hash: hash of key. 367b7579f77SDag-Erling Smørgrav * @param key: what to look for. 368b7579f77SDag-Erling Smørgrav */ 3693005e0a3SDag-Erling Smørgrav void lruhash_remove(struct lruhash* table, hashvalue_type hash, void* key); 370b7579f77SDag-Erling Smørgrav 371b7579f77SDag-Erling Smørgrav /** init the hash bins for the table */ 372b7579f77SDag-Erling Smørgrav void bin_init(struct lruhash_bin* array, size_t size); 373b7579f77SDag-Erling Smørgrav 374b7579f77SDag-Erling Smørgrav /** delete the hash bin and entries inside it */ 375b7579f77SDag-Erling Smørgrav void bin_delete(struct lruhash* table, struct lruhash_bin* bin); 376b7579f77SDag-Erling Smørgrav 377b7579f77SDag-Erling Smørgrav /** 378b7579f77SDag-Erling Smørgrav * Find entry in hash bin. You must have locked the bin. 379b7579f77SDag-Erling Smørgrav * @param table: hash table with function pointers. 380b7579f77SDag-Erling Smørgrav * @param bin: hash bin to look into. 381b7579f77SDag-Erling Smørgrav * @param hash: hash value to look for. 382b7579f77SDag-Erling Smørgrav * @param key: key to look for. 3838f76bb7dSCy Schubert * @param collisions: how many collisions were found during the search. 384b7579f77SDag-Erling Smørgrav * @return: the entry or NULL if not found. 385b7579f77SDag-Erling Smørgrav */ 386b7579f77SDag-Erling Smørgrav struct lruhash_entry* bin_find_entry(struct lruhash* table, 3878f76bb7dSCy Schubert struct lruhash_bin* bin, hashvalue_type hash, void* key, size_t* collisions); 388b7579f77SDag-Erling Smørgrav 389b7579f77SDag-Erling Smørgrav /** 390b7579f77SDag-Erling Smørgrav * Remove entry from bin overflow chain. 391b7579f77SDag-Erling Smørgrav * You must have locked the bin. 392b7579f77SDag-Erling Smørgrav * @param bin: hash bin to look into. 393b7579f77SDag-Erling Smørgrav * @param entry: entry ptr that needs removal. 394b7579f77SDag-Erling Smørgrav */ 395b7579f77SDag-Erling Smørgrav void bin_overflow_remove(struct lruhash_bin* bin, 396b7579f77SDag-Erling Smørgrav struct lruhash_entry* entry); 397b7579f77SDag-Erling Smørgrav 398b7579f77SDag-Erling Smørgrav /** 399b7579f77SDag-Erling Smørgrav * Split hash bin into two new ones. Based on increased size_mask. 400b7579f77SDag-Erling Smørgrav * Caller must hold hash table lock. 401b7579f77SDag-Erling Smørgrav * At the end the routine acquires all hashbin locks (in the old array). 402b7579f77SDag-Erling Smørgrav * This makes it wait for other threads to finish with the bins. 403b7579f77SDag-Erling Smørgrav * So the bins are ready to be deleted after this function. 404b7579f77SDag-Erling Smørgrav * @param table: hash table with function pointers. 405b7579f77SDag-Erling Smørgrav * @param newa: new increased array. 406b7579f77SDag-Erling Smørgrav * @param newmask: new lookup mask. 407b7579f77SDag-Erling Smørgrav */ 408b7579f77SDag-Erling Smørgrav void bin_split(struct lruhash* table, struct lruhash_bin* newa, 409b7579f77SDag-Erling Smørgrav int newmask); 410b7579f77SDag-Erling Smørgrav 411b7579f77SDag-Erling Smørgrav /** 412b7579f77SDag-Erling Smørgrav * Try to make space available by deleting old entries. 413b7579f77SDag-Erling Smørgrav * Assumes that the lock on the hashtable is being held by caller. 414b7579f77SDag-Erling Smørgrav * Caller must not hold bin locks. 415b7579f77SDag-Erling Smørgrav * @param table: hash table. 416b7579f77SDag-Erling Smørgrav * @param list: list of entries that are to be deleted later. 417b7579f77SDag-Erling Smørgrav * Entries have been removed from the hash table and writelock is held. 418b7579f77SDag-Erling Smørgrav */ 419b7579f77SDag-Erling Smørgrav void reclaim_space(struct lruhash* table, struct lruhash_entry** list); 420b7579f77SDag-Erling Smørgrav 421b7579f77SDag-Erling Smørgrav /** 422b7579f77SDag-Erling Smørgrav * Grow the table lookup array. Becomes twice as large. 423b7579f77SDag-Erling Smørgrav * Caller must hold the hash table lock. Must not hold any bin locks. 424b7579f77SDag-Erling Smørgrav * Tries to grow, on malloc failure, nothing happened. 425b7579f77SDag-Erling Smørgrav * @param table: hash table. 426b7579f77SDag-Erling Smørgrav */ 427b7579f77SDag-Erling Smørgrav void table_grow(struct lruhash* table); 428b7579f77SDag-Erling Smørgrav 429b7579f77SDag-Erling Smørgrav /** 430b7579f77SDag-Erling Smørgrav * Put entry at front of lru. entry must be unlinked from lru. 431b7579f77SDag-Erling Smørgrav * Caller must hold hash table lock. 432b7579f77SDag-Erling Smørgrav * @param table: hash table with lru head and tail. 433b7579f77SDag-Erling Smørgrav * @param entry: entry to make most recently used. 434b7579f77SDag-Erling Smørgrav */ 435b7579f77SDag-Erling Smørgrav void lru_front(struct lruhash* table, struct lruhash_entry* entry); 436b7579f77SDag-Erling Smørgrav 437b7579f77SDag-Erling Smørgrav /** 438b7579f77SDag-Erling Smørgrav * Remove entry from lru list. 439b7579f77SDag-Erling Smørgrav * Caller must hold hash table lock. 440b7579f77SDag-Erling Smørgrav * @param table: hash table with lru head and tail. 441b7579f77SDag-Erling Smørgrav * @param entry: entry to remove from lru. 442b7579f77SDag-Erling Smørgrav */ 443b7579f77SDag-Erling Smørgrav void lru_remove(struct lruhash* table, struct lruhash_entry* entry); 444b7579f77SDag-Erling Smørgrav 445b7579f77SDag-Erling Smørgrav /** 446b7579f77SDag-Erling Smørgrav * Output debug info to the log as to state of the hash table. 447b7579f77SDag-Erling Smørgrav * @param table: hash table. 448b7579f77SDag-Erling Smørgrav * @param id: string printed with table to identify the hash table. 449b7579f77SDag-Erling Smørgrav * @param extended: set to true to print statistics on overflow bin lengths. 450b7579f77SDag-Erling Smørgrav */ 451b7579f77SDag-Erling Smørgrav void lruhash_status(struct lruhash* table, const char* id, int extended); 452b7579f77SDag-Erling Smørgrav 453b7579f77SDag-Erling Smørgrav /** 454b7579f77SDag-Erling Smørgrav * Get memory in use now by the lruhash table. 455b7579f77SDag-Erling Smørgrav * @param table: hash table. Will be locked before use. And unlocked after. 456b7579f77SDag-Erling Smørgrav * @return size in bytes. 457b7579f77SDag-Erling Smørgrav */ 458b7579f77SDag-Erling Smørgrav size_t lruhash_get_mem(struct lruhash* table); 459b7579f77SDag-Erling Smørgrav 460b7579f77SDag-Erling Smørgrav /** 461b7579f77SDag-Erling Smørgrav * Traverse a lruhash. Call back for every element in the table. 462b7579f77SDag-Erling Smørgrav * @param h: hash table. Locked before use. 463b7579f77SDag-Erling Smørgrav * @param wr: if true writelock is obtained on element, otherwise readlock. 464b7579f77SDag-Erling Smørgrav * @param func: function for every element. Do not lock or unlock elements. 465b7579f77SDag-Erling Smørgrav * @param arg: user argument to func. 466b7579f77SDag-Erling Smørgrav */ 467b7579f77SDag-Erling Smørgrav void lruhash_traverse(struct lruhash* h, int wr, 468b7579f77SDag-Erling Smørgrav void (*func)(struct lruhash_entry*, void*), void* arg); 469b7579f77SDag-Erling Smørgrav 470b7579f77SDag-Erling Smørgrav #endif /* UTIL_STORAGE_LRUHASH_H */ 471