static void bucket_erase_existed( bucket_t *bucket, const hashmap_key_t key, unsigned int * const existed ) { entry_t *prev; entry_t *iter; assert( NULL != bucket ); assert( NULL != key ); assert( NULL != existed ); iter = bucket_find_entry( bucket, key, &prev ); if( NULL != iter ) { if( NULL == prev ) { bucket->entries = iter->next; } else { prev->next = iter->next; } entry_destroy( iter ); --bucket->stats.num_entries; *existed = 1; } else { *existed = 0; } }
void lruhash_remove(struct lruhash *table, hashvalue_t hash, void *key) { struct lruhash_entry *entry; struct lruhash_bucket *bucket; void *d; lock_basic_lock(&table->lock); bucket = &table->array[hash & table->size_mask]; if((entry=bucket_find_entry(table, bucket, hash, key))) { bucket_overflow_remove(bucket, entry); lru_remove(table, entry); } else { lock_basic_unlock(&table->lock); return; } table->num--; lock_basic_lock(&entry->lock); table->space_used -= (*table->sizefunc)(entry->key, entry->data); lock_basic_unlock(&entry->lock); lock_basic_unlock(&table->lock); //del key data d = entry->data; (*table->delkeyfunc)(entry->key); (*table->deldatafunc)(d); }
struct lruhash_entry *lruhash_lookup(struct lruhash *table, hashvalue_t hash, void *key) { struct lruhash_entry *entry; struct lruhash_bucket *bucket; lock_basic_lock(&table->lock); bucket = &table->array[hash & table->size_mask]; if((entry=bucket_find_entry(table, bucket, hash, key))) { lru_touch(table, entry); lock_basic_lock(&entry->lock); } lock_basic_unlock(&table->lock); return entry; }
void lruhash_insert(struct lruhash *table, hashvalue_t hash, struct lruhash_entry *entry, void *data) { struct lruhash_bucket *bucket; struct lruhash_entry *found, *reclaimlist=NULL; size_t need_size; need_size = table->sizefunc(entry->key, data); //find bucket lock_basic_lock(&table->lock); bucket = &table->array[hash & table->size_mask]; //see if entry exists if(!(found=bucket_find_entry(table, bucket, hash, entry->key))) { //if not found: add to bucket entry->overflow_next = bucket->overflow_list; bucket->overflow_list = entry; lru_front(table, entry); table->num++; table->space_used += need_size; } else { //if found: update data table->space_used += need_size - (*table->sizefunc)(found->key, found->data); (*table->delkeyfunc)(entry->key); lru_touch(table, found); lock_basic_lock(&found->lock); (*table->deldatafunc)(found->data); found->data = data; lock_basic_unlock(&found->lock); } if(table->space_used > table->space_max) reclaim_space(table, &reclaimlist); if(table->num >= table->size) table_grow(table); lock_basic_unlock(&table->lock); //del reclaim without lock while(reclaimlist) { struct lruhash_entry *n = reclaimlist->overflow_next; void *d = reclaimlist->data; (*table->delkeyfunc)(reclaimlist->key); (*table->deldatafunc)(d); reclaimlist = n; } }
static unsigned int bucket_find( bucket_t *bucket, hashmap_key_t key, hashmap_value_t * const value ) { unsigned int found = 0; entry_t *entry = bucket_find_entry( bucket, key, NULL ); if( NULL != entry ) { found = 1; if( NULL != value ) { *value = entry->value; } } return found; }
static int bucket_insert_existed( bucket_t *bucket, const hashmap_key_t key, const hashmap_value_t value, unsigned int * const existed ) { entry_t *entry; int err = 0; assert( NULL != bucket ); assert( NULL != key ); assert( NULL != existed ); entry = bucket_find_entry( bucket, key, NULL ); if( NULL != entry ) { /* Key exists in this bucket, update the value. */ entry->value = value; *existed = 1; } else { /* Key doesn't exist in this bucket, add it. */ entry_t *new_entry = entry_create( key, value ); if( NULL != new_entry ) { new_entry->next = bucket->entries; bucket->entries = new_entry; ++bucket->stats.num_entries; *existed = 0; } else { err = -1; } } return err; }
//test bucket_find_entry and bucket_overflow_remove static void test_bucket_find_entry(struct lruhash *table) { testkey *k1 = newkey(12); testkey *k2 = newkey(12 + 1024); testkey *k3 = newkey(14); testkey *k4 = newkey(12 + 1024*2); hashvalue_t h = simplehash(12); struct lruhash_bucket bucket; memset(&bucket, 0, sizeof(bucket)); //remove from empty list bucket_overflow_remove(&bucket, &k1->entry); //find in empty list unit_assert(bucket_find_entry(table, &bucket, h, k1) == NULL); //insert bucket.overflow_list = &k1->entry; unit_assert(bucket_find_entry(table, &bucket, simplehash(13), k1) == NULL); unit_assert(k1->entry.hash == k2->entry.hash); unit_assert(bucket_find_entry(table, &bucket, h, k2) == NULL); unit_assert(bucket_find_entry(table, &bucket, h, k1) == &k1->entry); //remove bucket_overflow_remove(&bucket, &k1->entry); unit_assert(bucket_find_entry(table, &bucket, h, k1) == NULL); //insert multi unit_assert(k1->entry.hash == k4->entry.hash); k4->entry.overflow_next = &k1->entry; k3->entry.overflow_next = &k4->entry; bucket.overflow_list = &k3->entry; unit_assert(bucket_find_entry(table, &bucket, simplehash(13), k1) == NULL); unit_assert(k1->entry.hash == k2->entry.hash); unit_assert(bucket_find_entry(table, &bucket, h, k2) == NULL); unit_assert(bucket_find_entry(table, &bucket, h, k1) == &k1->entry); //remove mid unit_assert(bucket_find_entry(table, &bucket, k4->entry.hash, k4) == &k4->entry); bucket_overflow_remove(&bucket, &k4->entry); unit_assert(bucket_find_entry(table, &bucket, k4->entry.hash, k4) == NULL); //remove last bucket_overflow_remove(&bucket, &k1->entry); unit_assert(bucket_find_entry(table, &bucket, h, k1) == NULL); delkey(k1); delkey(k2); delkey(k3); delkey(k4); }