1*b7579f77SDag-Erling Smørgrav /* 2*b7579f77SDag-Erling Smørgrav * util/storage/lruhash.h - hashtable, hash function, LRU keeping. 3*b7579f77SDag-Erling Smørgrav * 4*b7579f77SDag-Erling Smørgrav * Copyright (c) 2007, NLnet Labs. All rights reserved. 5*b7579f77SDag-Erling Smørgrav * 6*b7579f77SDag-Erling Smørgrav * This software is open source. 7*b7579f77SDag-Erling Smørgrav * 8*b7579f77SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 9*b7579f77SDag-Erling Smørgrav * modification, are permitted provided that the following conditions 10*b7579f77SDag-Erling Smørgrav * are met: 11*b7579f77SDag-Erling Smørgrav * 12*b7579f77SDag-Erling Smørgrav * Redistributions of source code must retain the above copyright notice, 13*b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer. 14*b7579f77SDag-Erling Smørgrav * 15*b7579f77SDag-Erling Smørgrav * Redistributions in binary form must reproduce the above copyright notice, 16*b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer in the documentation 17*b7579f77SDag-Erling Smørgrav * and/or other materials provided with the distribution. 18*b7579f77SDag-Erling Smørgrav * 19*b7579f77SDag-Erling Smørgrav * Neither the name of the NLNET LABS nor the names of its contributors may 20*b7579f77SDag-Erling Smørgrav * be used to endorse or promote products derived from this software without 21*b7579f77SDag-Erling Smørgrav * specific prior written permission. 22*b7579f77SDag-Erling Smørgrav * 23*b7579f77SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24*b7579f77SDag-Erling Smørgrav * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 25*b7579f77SDag-Erling Smørgrav * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 26*b7579f77SDag-Erling Smørgrav * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE 27*b7579f77SDag-Erling Smørgrav * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 28*b7579f77SDag-Erling Smørgrav * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 29*b7579f77SDag-Erling Smørgrav * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30*b7579f77SDag-Erling Smørgrav * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31*b7579f77SDag-Erling Smørgrav * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 32*b7579f77SDag-Erling Smørgrav * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33*b7579f77SDag-Erling Smørgrav * POSSIBILITY OF SUCH DAMAGE. 34*b7579f77SDag-Erling Smørgrav */ 35*b7579f77SDag-Erling Smørgrav 36*b7579f77SDag-Erling Smørgrav /** 37*b7579f77SDag-Erling Smørgrav * \file 38*b7579f77SDag-Erling Smørgrav * 39*b7579f77SDag-Erling Smørgrav * This file contains a hashtable with LRU keeping of entries. 40*b7579f77SDag-Erling Smørgrav * 41*b7579f77SDag-Erling Smørgrav * The hash table keeps a maximum memory size. Old entries are removed 42*b7579f77SDag-Erling Smørgrav * to make space for new entries. 43*b7579f77SDag-Erling Smørgrav * 44*b7579f77SDag-Erling Smørgrav * The locking strategy is as follows: 45*b7579f77SDag-Erling Smørgrav * o since (almost) every read also implies a LRU update, the 46*b7579f77SDag-Erling Smørgrav * hashtable lock is a spinlock, not rwlock. 47*b7579f77SDag-Erling Smørgrav * o the idea is to move every thread through the hash lock quickly, 48*b7579f77SDag-Erling Smørgrav * so that the next thread can access the lookup table. 49*b7579f77SDag-Erling Smørgrav * o User performs hash function. 50*b7579f77SDag-Erling Smørgrav * 51*b7579f77SDag-Erling Smørgrav * For read: 52*b7579f77SDag-Erling Smørgrav * o lock hashtable. 53*b7579f77SDag-Erling Smørgrav * o lookup hash bin. 54*b7579f77SDag-Erling Smørgrav * o lock hash bin. 55*b7579f77SDag-Erling Smørgrav * o find entry (if failed, unlock hash, unl bin, exit). 56*b7579f77SDag-Erling Smørgrav * o swizzle pointers for LRU update. 57*b7579f77SDag-Erling Smørgrav * o unlock hashtable. 58*b7579f77SDag-Erling Smørgrav * o lock entry (rwlock). 59*b7579f77SDag-Erling Smørgrav * o unlock hash bin. 60*b7579f77SDag-Erling Smørgrav * o work on entry. 61*b7579f77SDag-Erling Smørgrav * o unlock entry. 62*b7579f77SDag-Erling Smørgrav * 63*b7579f77SDag-Erling Smørgrav * To update an entry, gain writelock and change the entry. 64*b7579f77SDag-Erling Smørgrav * (the entry must keep the same hashvalue, so a data update.) 65*b7579f77SDag-Erling Smørgrav * (you cannot upgrade a readlock to a writelock, because the item may 66*b7579f77SDag-Erling Smørgrav * be deleted, it would cause race conditions. So instead, unlock and 67*b7579f77SDag-Erling Smørgrav * relookup it in the hashtable.) 68*b7579f77SDag-Erling Smørgrav * 69*b7579f77SDag-Erling Smørgrav * To delete an entry: 70*b7579f77SDag-Erling Smørgrav * o unlock the entry if you hold the lock already. 71*b7579f77SDag-Erling Smørgrav * o lock hashtable. 72*b7579f77SDag-Erling Smørgrav * o lookup hash bin. 73*b7579f77SDag-Erling Smørgrav * o lock hash bin. 74*b7579f77SDag-Erling Smørgrav * o find entry (if failed, unlock hash, unl bin, exit). 75*b7579f77SDag-Erling Smørgrav * o remove entry from hashtable bin overflow chain. 76*b7579f77SDag-Erling Smørgrav * o unlock hashtable. 77*b7579f77SDag-Erling Smørgrav * o lock entry (writelock). 78*b7579f77SDag-Erling Smørgrav * o unlock hash bin. 79*b7579f77SDag-Erling Smørgrav * o unlock entry (nobody else should be waiting for this lock, 80*b7579f77SDag-Erling Smørgrav * since you removed it from hashtable, and you got writelock while 81*b7579f77SDag-Erling Smørgrav * holding the hashbinlock so you are the only one.) 82*b7579f77SDag-Erling Smørgrav * Note you are only allowed to obtain a lock while holding hashbinlock. 83*b7579f77SDag-Erling Smørgrav * o delete entry. 84*b7579f77SDag-Erling Smørgrav * 85*b7579f77SDag-Erling Smørgrav * The above sequence is: 86*b7579f77SDag-Erling Smørgrav * o race free, works with read, write and delete. 87*b7579f77SDag-Erling Smørgrav * o but has a queue, imagine someone needing a writelock on an item. 88*b7579f77SDag-Erling Smørgrav * but there are still readlocks. The writelocker waits, but holds 89*b7579f77SDag-Erling Smørgrav * the hashbinlock. The next thread that comes in and needs the same 90*b7579f77SDag-Erling Smørgrav * hashbin will wait for the lock while holding the hashtable lock. 91*b7579f77SDag-Erling Smørgrav * thus halting the entire system on hashtable. 92*b7579f77SDag-Erling Smørgrav * This is because of the delete protection. 93*b7579f77SDag-Erling Smørgrav * Readlocks will be easier on the rwlock on entries. 94*b7579f77SDag-Erling Smørgrav * While the writer is holding writelock, similar problems happen with 95*b7579f77SDag-Erling Smørgrav * a reader or writer needing the same item. 96*b7579f77SDag-Erling Smørgrav * the scenario requires more than three threads. 97*b7579f77SDag-Erling Smørgrav * o so the queue length is 3 threads in a bad situation. The fourth is 98*b7579f77SDag-Erling Smørgrav * unable to use the hashtable. 99*b7579f77SDag-Erling Smørgrav * 100*b7579f77SDag-Erling Smørgrav * If you need to acquire locks on multiple items from the hashtable. 101*b7579f77SDag-Erling Smørgrav * o you MUST release all locks on items from the hashtable before 102*b7579f77SDag-Erling Smørgrav * doing the next lookup/insert/delete/whatever. 103*b7579f77SDag-Erling Smørgrav * o To acquire multiple items you should use a special routine that 104*b7579f77SDag-Erling Smørgrav * obtains the locks on those multiple items in one go. 105*b7579f77SDag-Erling Smørgrav */ 106*b7579f77SDag-Erling Smørgrav 107*b7579f77SDag-Erling Smørgrav #ifndef UTIL_STORAGE_LRUHASH_H 108*b7579f77SDag-Erling Smørgrav #define UTIL_STORAGE_LRUHASH_H 109*b7579f77SDag-Erling Smørgrav #include "util/locks.h" 110*b7579f77SDag-Erling Smørgrav struct lruhash_bin; 111*b7579f77SDag-Erling Smørgrav struct lruhash_entry; 112*b7579f77SDag-Erling Smørgrav 113*b7579f77SDag-Erling Smørgrav /** default start size for hash arrays */ 114*b7579f77SDag-Erling Smørgrav #define HASH_DEFAULT_STARTARRAY 1024 /* entries in array */ 115*b7579f77SDag-Erling Smørgrav /** default max memory for hash arrays */ 116*b7579f77SDag-Erling Smørgrav #define HASH_DEFAULT_MAXMEM 4*1024*1024 /* bytes */ 117*b7579f77SDag-Erling Smørgrav 118*b7579f77SDag-Erling Smørgrav /** the type of a hash value */ 119*b7579f77SDag-Erling Smørgrav typedef uint32_t hashvalue_t; 120*b7579f77SDag-Erling Smørgrav 121*b7579f77SDag-Erling Smørgrav /** 122*b7579f77SDag-Erling Smørgrav * Type of function that calculates the size of an entry. 123*b7579f77SDag-Erling Smørgrav * Result must include the size of struct lruhash_entry. 124*b7579f77SDag-Erling Smørgrav * Keys that are identical must also calculate to the same size. 125*b7579f77SDag-Erling Smørgrav * size = func(key, data). 126*b7579f77SDag-Erling Smørgrav */ 127*b7579f77SDag-Erling Smørgrav typedef size_t (*lruhash_sizefunc_t)(void*, void*); 128*b7579f77SDag-Erling Smørgrav 129*b7579f77SDag-Erling Smørgrav /** type of function that compares two keys. return 0 if equal. */ 130*b7579f77SDag-Erling Smørgrav typedef int (*lruhash_compfunc_t)(void*, void*); 131*b7579f77SDag-Erling Smørgrav 132*b7579f77SDag-Erling Smørgrav /** old keys are deleted. 133*b7579f77SDag-Erling Smørgrav * The RRset type has to revoke its ID number, markdel() is used first. 134*b7579f77SDag-Erling Smørgrav * This function is called: func(key, userarg) */ 135*b7579f77SDag-Erling Smørgrav typedef void (*lruhash_delkeyfunc_t)(void*, void*); 136*b7579f77SDag-Erling Smørgrav 137*b7579f77SDag-Erling Smørgrav /** old data is deleted. This function is called: func(data, userarg). */ 138*b7579f77SDag-Erling Smørgrav typedef void (*lruhash_deldatafunc_t)(void*, void*); 139*b7579f77SDag-Erling Smørgrav 140*b7579f77SDag-Erling Smørgrav /** mark a key as pending to be deleted (and not to be used by anyone). 141*b7579f77SDag-Erling Smørgrav * called: func(key) */ 142*b7579f77SDag-Erling Smørgrav typedef void (*lruhash_markdelfunc_t)(void*); 143*b7579f77SDag-Erling Smørgrav 144*b7579f77SDag-Erling Smørgrav /** 145*b7579f77SDag-Erling Smørgrav * Hash table that keeps LRU list of entries. 146*b7579f77SDag-Erling Smørgrav */ 147*b7579f77SDag-Erling Smørgrav struct lruhash { 148*b7579f77SDag-Erling Smørgrav /** lock for exclusive access, to the lookup array */ 149*b7579f77SDag-Erling Smørgrav lock_quick_t lock; 150*b7579f77SDag-Erling Smørgrav /** the size function for entries in this table */ 151*b7579f77SDag-Erling Smørgrav lruhash_sizefunc_t sizefunc; 152*b7579f77SDag-Erling Smørgrav /** the compare function for entries in this table. */ 153*b7579f77SDag-Erling Smørgrav lruhash_compfunc_t compfunc; 154*b7579f77SDag-Erling Smørgrav /** how to delete keys. */ 155*b7579f77SDag-Erling Smørgrav lruhash_delkeyfunc_t delkeyfunc; 156*b7579f77SDag-Erling Smørgrav /** how to delete data. */ 157*b7579f77SDag-Erling Smørgrav lruhash_deldatafunc_t deldatafunc; 158*b7579f77SDag-Erling Smørgrav /** how to mark a key pending deletion */ 159*b7579f77SDag-Erling Smørgrav lruhash_markdelfunc_t markdelfunc; 160*b7579f77SDag-Erling Smørgrav /** user argument for user functions */ 161*b7579f77SDag-Erling Smørgrav void* cb_arg; 162*b7579f77SDag-Erling Smørgrav 163*b7579f77SDag-Erling Smørgrav /** the size of the lookup array */ 164*b7579f77SDag-Erling Smørgrav size_t size; 165*b7579f77SDag-Erling Smørgrav /** size bitmask - since size is a power of 2 */ 166*b7579f77SDag-Erling Smørgrav int size_mask; 167*b7579f77SDag-Erling Smørgrav /** lookup array of bins */ 168*b7579f77SDag-Erling Smørgrav struct lruhash_bin* array; 169*b7579f77SDag-Erling Smørgrav 170*b7579f77SDag-Erling Smørgrav /** the lru list, start and end, noncyclical double linked list. */ 171*b7579f77SDag-Erling Smørgrav struct lruhash_entry* lru_start; 172*b7579f77SDag-Erling Smørgrav /** lru list end item (least recently used) */ 173*b7579f77SDag-Erling Smørgrav struct lruhash_entry* lru_end; 174*b7579f77SDag-Erling Smørgrav 175*b7579f77SDag-Erling Smørgrav /** the number of entries in the hash table. */ 176*b7579f77SDag-Erling Smørgrav size_t num; 177*b7579f77SDag-Erling Smørgrav /** the amount of space used, roughly the number of bytes in use. */ 178*b7579f77SDag-Erling Smørgrav size_t space_used; 179*b7579f77SDag-Erling Smørgrav /** the amount of space the hash table is maximally allowed to use. */ 180*b7579f77SDag-Erling Smørgrav size_t space_max; 181*b7579f77SDag-Erling Smørgrav }; 182*b7579f77SDag-Erling Smørgrav 183*b7579f77SDag-Erling Smørgrav /** 184*b7579f77SDag-Erling Smørgrav * A single bin with a linked list of entries in it. 185*b7579f77SDag-Erling Smørgrav */ 186*b7579f77SDag-Erling Smørgrav struct lruhash_bin { 187*b7579f77SDag-Erling Smørgrav /** 188*b7579f77SDag-Erling Smørgrav * Lock for exclusive access to the linked list 189*b7579f77SDag-Erling Smørgrav * This lock makes deletion of items safe in this overflow list. 190*b7579f77SDag-Erling Smørgrav */ 191*b7579f77SDag-Erling Smørgrav lock_quick_t lock; 192*b7579f77SDag-Erling Smørgrav /** linked list of overflow entries */ 193*b7579f77SDag-Erling Smørgrav struct lruhash_entry* overflow_list; 194*b7579f77SDag-Erling Smørgrav }; 195*b7579f77SDag-Erling Smørgrav 196*b7579f77SDag-Erling Smørgrav /** 197*b7579f77SDag-Erling Smørgrav * An entry into the hash table. 198*b7579f77SDag-Erling Smørgrav * To change overflow_next you need to hold the bin lock. 199*b7579f77SDag-Erling Smørgrav * To change the lru items you need to hold the hashtable lock. 200*b7579f77SDag-Erling Smørgrav * This structure is designed as part of key struct. And key pointer helps 201*b7579f77SDag-Erling Smørgrav * to get the surrounding structure. Data should be allocated on its own. 202*b7579f77SDag-Erling Smørgrav */ 203*b7579f77SDag-Erling Smørgrav struct lruhash_entry { 204*b7579f77SDag-Erling Smørgrav /** 205*b7579f77SDag-Erling Smørgrav * rwlock for access to the contents of the entry 206*b7579f77SDag-Erling Smørgrav * Note that it does _not_ cover the lru_ and overflow_ ptrs. 207*b7579f77SDag-Erling Smørgrav * Even with a writelock, you cannot change hash and key. 208*b7579f77SDag-Erling Smørgrav * You need to delete it to change hash or key. 209*b7579f77SDag-Erling Smørgrav */ 210*b7579f77SDag-Erling Smørgrav lock_rw_t lock; 211*b7579f77SDag-Erling Smørgrav /** next entry in overflow chain. Covered by hashlock and binlock. */ 212*b7579f77SDag-Erling Smørgrav struct lruhash_entry* overflow_next; 213*b7579f77SDag-Erling Smørgrav /** next entry in lru chain. covered by hashlock. */ 214*b7579f77SDag-Erling Smørgrav struct lruhash_entry* lru_next; 215*b7579f77SDag-Erling Smørgrav /** prev entry in lru chain. covered by hashlock. */ 216*b7579f77SDag-Erling Smørgrav struct lruhash_entry* lru_prev; 217*b7579f77SDag-Erling Smørgrav /** hash value of the key. It may not change, until entry deleted. */ 218*b7579f77SDag-Erling Smørgrav hashvalue_t hash; 219*b7579f77SDag-Erling Smørgrav /** key */ 220*b7579f77SDag-Erling Smørgrav void* key; 221*b7579f77SDag-Erling Smørgrav /** data */ 222*b7579f77SDag-Erling Smørgrav void* data; 223*b7579f77SDag-Erling Smørgrav }; 224*b7579f77SDag-Erling Smørgrav 225*b7579f77SDag-Erling Smørgrav /** 226*b7579f77SDag-Erling Smørgrav * Create new hash table. 227*b7579f77SDag-Erling Smørgrav * @param start_size: size of hashtable array at start, must be power of 2. 228*b7579f77SDag-Erling Smørgrav * @param maxmem: maximum amount of memory this table is allowed to use. 229*b7579f77SDag-Erling Smørgrav * @param sizefunc: calculates memory usage of entries. 230*b7579f77SDag-Erling Smørgrav * @param compfunc: compares entries, 0 on equality. 231*b7579f77SDag-Erling Smørgrav * @param delkeyfunc: deletes key. 232*b7579f77SDag-Erling Smørgrav * Calling both delkey and deldata will also free the struct lruhash_entry. 233*b7579f77SDag-Erling Smørgrav * Make it part of the key structure and delete it in delkeyfunc. 234*b7579f77SDag-Erling Smørgrav * @param deldatafunc: deletes data. 235*b7579f77SDag-Erling Smørgrav * @param arg: user argument that is passed to user function calls. 236*b7579f77SDag-Erling Smørgrav * @return: new hash table or NULL on malloc failure. 237*b7579f77SDag-Erling Smørgrav */ 238*b7579f77SDag-Erling Smørgrav struct lruhash* lruhash_create(size_t start_size, size_t maxmem, 239*b7579f77SDag-Erling Smørgrav lruhash_sizefunc_t sizefunc, lruhash_compfunc_t compfunc, 240*b7579f77SDag-Erling Smørgrav lruhash_delkeyfunc_t delkeyfunc, lruhash_deldatafunc_t deldatafunc, 241*b7579f77SDag-Erling Smørgrav void* arg); 242*b7579f77SDag-Erling Smørgrav 243*b7579f77SDag-Erling Smørgrav /** 244*b7579f77SDag-Erling Smørgrav * Delete hash table. Entries are all deleted. 245*b7579f77SDag-Erling Smørgrav * @param table: to delete. 246*b7579f77SDag-Erling Smørgrav */ 247*b7579f77SDag-Erling Smørgrav void lruhash_delete(struct lruhash* table); 248*b7579f77SDag-Erling Smørgrav 249*b7579f77SDag-Erling Smørgrav /** 250*b7579f77SDag-Erling Smørgrav * Clear hash table. Entries are all deleted, while locking them before 251*b7579f77SDag-Erling Smørgrav * doing so. At end the table is empty. 252*b7579f77SDag-Erling Smørgrav * @param table: to make empty. 253*b7579f77SDag-Erling Smørgrav */ 254*b7579f77SDag-Erling Smørgrav void lruhash_clear(struct lruhash* table); 255*b7579f77SDag-Erling Smørgrav 256*b7579f77SDag-Erling Smørgrav /** 257*b7579f77SDag-Erling Smørgrav * Insert a new element into the hashtable. 258*b7579f77SDag-Erling Smørgrav * If key is already present data pointer in that entry is updated. 259*b7579f77SDag-Erling Smørgrav * The space calculation function is called with the key, data. 260*b7579f77SDag-Erling Smørgrav * If necessary the least recently used entries are deleted to make space. 261*b7579f77SDag-Erling Smørgrav * If necessary the hash array is grown up. 262*b7579f77SDag-Erling Smørgrav * 263*b7579f77SDag-Erling Smørgrav * @param table: hash table. 264*b7579f77SDag-Erling Smørgrav * @param hash: hash value. User calculates the hash. 265*b7579f77SDag-Erling Smørgrav * @param entry: identifies the entry. 266*b7579f77SDag-Erling Smørgrav * If key already present, this entry->key is deleted immediately. 267*b7579f77SDag-Erling Smørgrav * But entry->data is set to NULL before deletion, and put into 268*b7579f77SDag-Erling Smørgrav * the existing entry. The data is then freed. 269*b7579f77SDag-Erling Smørgrav * @param data: the data. 270*b7579f77SDag-Erling Smørgrav * @param cb_override: if not null overrides the cb_arg for the deletefunc. 271*b7579f77SDag-Erling Smørgrav */ 272*b7579f77SDag-Erling Smørgrav void lruhash_insert(struct lruhash* table, hashvalue_t hash, 273*b7579f77SDag-Erling Smørgrav struct lruhash_entry* entry, void* data, void* cb_override); 274*b7579f77SDag-Erling Smørgrav 275*b7579f77SDag-Erling Smørgrav /** 276*b7579f77SDag-Erling Smørgrav * Lookup an entry in the hashtable. 277*b7579f77SDag-Erling Smørgrav * At the end of the function you hold a (read/write)lock on the entry. 278*b7579f77SDag-Erling Smørgrav * The LRU is updated for the entry (if found). 279*b7579f77SDag-Erling Smørgrav * @param table: hash table. 280*b7579f77SDag-Erling Smørgrav * @param hash: hash of key. 281*b7579f77SDag-Erling Smørgrav * @param key: what to look for, compared against entries in overflow chain. 282*b7579f77SDag-Erling Smørgrav * the hash value must be set, and must work with compare function. 283*b7579f77SDag-Erling Smørgrav * @param wr: set to true if you desire a writelock on the entry. 284*b7579f77SDag-Erling Smørgrav * with a writelock you can update the data part. 285*b7579f77SDag-Erling Smørgrav * @return: pointer to the entry or NULL. The entry is locked. 286*b7579f77SDag-Erling Smørgrav * The user must unlock the entry when done. 287*b7579f77SDag-Erling Smørgrav */ 288*b7579f77SDag-Erling Smørgrav struct lruhash_entry* lruhash_lookup(struct lruhash* table, hashvalue_t hash, 289*b7579f77SDag-Erling Smørgrav void* key, int wr); 290*b7579f77SDag-Erling Smørgrav 291*b7579f77SDag-Erling Smørgrav /** 292*b7579f77SDag-Erling Smørgrav * Touch entry, so it becomes the most recently used in the LRU list. 293*b7579f77SDag-Erling Smørgrav * Caller must hold hash table lock. The entry must be inserted already. 294*b7579f77SDag-Erling Smørgrav * @param table: hash table. 295*b7579f77SDag-Erling Smørgrav * @param entry: entry to make first in LRU. 296*b7579f77SDag-Erling Smørgrav */ 297*b7579f77SDag-Erling Smørgrav void lru_touch(struct lruhash* table, struct lruhash_entry* entry); 298*b7579f77SDag-Erling Smørgrav 299*b7579f77SDag-Erling Smørgrav /** 300*b7579f77SDag-Erling Smørgrav * Set the markdelfunction (or NULL) 301*b7579f77SDag-Erling Smørgrav */ 302*b7579f77SDag-Erling Smørgrav void lruhash_setmarkdel(struct lruhash* table, lruhash_markdelfunc_t md); 303*b7579f77SDag-Erling Smørgrav 304*b7579f77SDag-Erling Smørgrav /************************* Internal functions ************************/ 305*b7579f77SDag-Erling Smørgrav /*** these are only exposed for unit tests. ***/ 306*b7579f77SDag-Erling Smørgrav 307*b7579f77SDag-Erling Smørgrav /** 308*b7579f77SDag-Erling Smørgrav * Remove entry from hashtable. Does nothing if not found in hashtable. 309*b7579f77SDag-Erling Smørgrav * Delfunc is called for the entry. 310*b7579f77SDag-Erling Smørgrav * @param table: hash table. 311*b7579f77SDag-Erling Smørgrav * @param hash: hash of key. 312*b7579f77SDag-Erling Smørgrav * @param key: what to look for. 313*b7579f77SDag-Erling Smørgrav */ 314*b7579f77SDag-Erling Smørgrav void lruhash_remove(struct lruhash* table, hashvalue_t hash, void* key); 315*b7579f77SDag-Erling Smørgrav 316*b7579f77SDag-Erling Smørgrav /** init the hash bins for the table */ 317*b7579f77SDag-Erling Smørgrav void bin_init(struct lruhash_bin* array, size_t size); 318*b7579f77SDag-Erling Smørgrav 319*b7579f77SDag-Erling Smørgrav /** delete the hash bin and entries inside it */ 320*b7579f77SDag-Erling Smørgrav void bin_delete(struct lruhash* table, struct lruhash_bin* bin); 321*b7579f77SDag-Erling Smørgrav 322*b7579f77SDag-Erling Smørgrav /** 323*b7579f77SDag-Erling Smørgrav * Find entry in hash bin. You must have locked the bin. 324*b7579f77SDag-Erling Smørgrav * @param table: hash table with function pointers. 325*b7579f77SDag-Erling Smørgrav * @param bin: hash bin to look into. 326*b7579f77SDag-Erling Smørgrav * @param hash: hash value to look for. 327*b7579f77SDag-Erling Smørgrav * @param key: key to look for. 328*b7579f77SDag-Erling Smørgrav * @return: the entry or NULL if not found. 329*b7579f77SDag-Erling Smørgrav */ 330*b7579f77SDag-Erling Smørgrav struct lruhash_entry* bin_find_entry(struct lruhash* table, 331*b7579f77SDag-Erling Smørgrav struct lruhash_bin* bin, hashvalue_t hash, void* key); 332*b7579f77SDag-Erling Smørgrav 333*b7579f77SDag-Erling Smørgrav /** 334*b7579f77SDag-Erling Smørgrav * Remove entry from bin overflow chain. 335*b7579f77SDag-Erling Smørgrav * You must have locked the bin. 336*b7579f77SDag-Erling Smørgrav * @param bin: hash bin to look into. 337*b7579f77SDag-Erling Smørgrav * @param entry: entry ptr that needs removal. 338*b7579f77SDag-Erling Smørgrav */ 339*b7579f77SDag-Erling Smørgrav void bin_overflow_remove(struct lruhash_bin* bin, 340*b7579f77SDag-Erling Smørgrav struct lruhash_entry* entry); 341*b7579f77SDag-Erling Smørgrav 342*b7579f77SDag-Erling Smørgrav /** 343*b7579f77SDag-Erling Smørgrav * Split hash bin into two new ones. Based on increased size_mask. 344*b7579f77SDag-Erling Smørgrav * Caller must hold hash table lock. 345*b7579f77SDag-Erling Smørgrav * At the end the routine acquires all hashbin locks (in the old array). 346*b7579f77SDag-Erling Smørgrav * This makes it wait for other threads to finish with the bins. 347*b7579f77SDag-Erling Smørgrav * So the bins are ready to be deleted after this function. 348*b7579f77SDag-Erling Smørgrav * @param table: hash table with function pointers. 349*b7579f77SDag-Erling Smørgrav * @param newa: new increased array. 350*b7579f77SDag-Erling Smørgrav * @param newmask: new lookup mask. 351*b7579f77SDag-Erling Smørgrav */ 352*b7579f77SDag-Erling Smørgrav void bin_split(struct lruhash* table, struct lruhash_bin* newa, 353*b7579f77SDag-Erling Smørgrav int newmask); 354*b7579f77SDag-Erling Smørgrav 355*b7579f77SDag-Erling Smørgrav /** 356*b7579f77SDag-Erling Smørgrav * Try to make space available by deleting old entries. 357*b7579f77SDag-Erling Smørgrav * Assumes that the lock on the hashtable is being held by caller. 358*b7579f77SDag-Erling Smørgrav * Caller must not hold bin locks. 359*b7579f77SDag-Erling Smørgrav * @param table: hash table. 360*b7579f77SDag-Erling Smørgrav * @param list: list of entries that are to be deleted later. 361*b7579f77SDag-Erling Smørgrav * Entries have been removed from the hash table and writelock is held. 362*b7579f77SDag-Erling Smørgrav */ 363*b7579f77SDag-Erling Smørgrav void reclaim_space(struct lruhash* table, struct lruhash_entry** list); 364*b7579f77SDag-Erling Smørgrav 365*b7579f77SDag-Erling Smørgrav /** 366*b7579f77SDag-Erling Smørgrav * Grow the table lookup array. Becomes twice as large. 367*b7579f77SDag-Erling Smørgrav * Caller must hold the hash table lock. Must not hold any bin locks. 368*b7579f77SDag-Erling Smørgrav * Tries to grow, on malloc failure, nothing happened. 369*b7579f77SDag-Erling Smørgrav * @param table: hash table. 370*b7579f77SDag-Erling Smørgrav */ 371*b7579f77SDag-Erling Smørgrav void table_grow(struct lruhash* table); 372*b7579f77SDag-Erling Smørgrav 373*b7579f77SDag-Erling Smørgrav /** 374*b7579f77SDag-Erling Smørgrav * Put entry at front of lru. entry must be unlinked from lru. 375*b7579f77SDag-Erling Smørgrav * Caller must hold hash table lock. 376*b7579f77SDag-Erling Smørgrav * @param table: hash table with lru head and tail. 377*b7579f77SDag-Erling Smørgrav * @param entry: entry to make most recently used. 378*b7579f77SDag-Erling Smørgrav */ 379*b7579f77SDag-Erling Smørgrav void lru_front(struct lruhash* table, struct lruhash_entry* entry); 380*b7579f77SDag-Erling Smørgrav 381*b7579f77SDag-Erling Smørgrav /** 382*b7579f77SDag-Erling Smørgrav * Remove entry from lru list. 383*b7579f77SDag-Erling Smørgrav * Caller must hold hash table lock. 384*b7579f77SDag-Erling Smørgrav * @param table: hash table with lru head and tail. 385*b7579f77SDag-Erling Smørgrav * @param entry: entry to remove from lru. 386*b7579f77SDag-Erling Smørgrav */ 387*b7579f77SDag-Erling Smørgrav void lru_remove(struct lruhash* table, struct lruhash_entry* entry); 388*b7579f77SDag-Erling Smørgrav 389*b7579f77SDag-Erling Smørgrav /** 390*b7579f77SDag-Erling Smørgrav * Output debug info to the log as to state of the hash table. 391*b7579f77SDag-Erling Smørgrav * @param table: hash table. 392*b7579f77SDag-Erling Smørgrav * @param id: string printed with table to identify the hash table. 393*b7579f77SDag-Erling Smørgrav * @param extended: set to true to print statistics on overflow bin lengths. 394*b7579f77SDag-Erling Smørgrav */ 395*b7579f77SDag-Erling Smørgrav void lruhash_status(struct lruhash* table, const char* id, int extended); 396*b7579f77SDag-Erling Smørgrav 397*b7579f77SDag-Erling Smørgrav /** 398*b7579f77SDag-Erling Smørgrav * Get memory in use now by the lruhash table. 399*b7579f77SDag-Erling Smørgrav * @param table: hash table. Will be locked before use. And unlocked after. 400*b7579f77SDag-Erling Smørgrav * @return size in bytes. 401*b7579f77SDag-Erling Smørgrav */ 402*b7579f77SDag-Erling Smørgrav size_t lruhash_get_mem(struct lruhash* table); 403*b7579f77SDag-Erling Smørgrav 404*b7579f77SDag-Erling Smørgrav /** 405*b7579f77SDag-Erling Smørgrav * Traverse a lruhash. Call back for every element in the table. 406*b7579f77SDag-Erling Smørgrav * @param h: hash table. Locked before use. 407*b7579f77SDag-Erling Smørgrav * @param wr: if true writelock is obtained on element, otherwise readlock. 408*b7579f77SDag-Erling Smørgrav * @param func: function for every element. Do not lock or unlock elements. 409*b7579f77SDag-Erling Smørgrav * @param arg: user argument to func. 410*b7579f77SDag-Erling Smørgrav */ 411*b7579f77SDag-Erling Smørgrav void lruhash_traverse(struct lruhash* h, int wr, 412*b7579f77SDag-Erling Smørgrav void (*func)(struct lruhash_entry*, void*), void* arg); 413*b7579f77SDag-Erling Smørgrav 414*b7579f77SDag-Erling Smørgrav #endif /* UTIL_STORAGE_LRUHASH_H */ 415