//test lru_front and lru_remove static void test_lru(struct lruhash *table) { testkey *k1 = newkey(12); testkey *k2 = newkey(14); lock_basic_lock(&table->lock); unit_assert(table->lru_head == NULL && table->lru_tail == NULL); lru_remove(table, &k1->entry); unit_assert(table->lru_head == NULL && table->lru_tail == NULL); //add one lru_front(table, &k1->entry); unit_assert( table->lru_head == &k1->entry && table->lru_tail == &k1->entry); //remove lru_remove(table, &k1->entry); unit_assert(table->lru_head == NULL && table->lru_tail == NULL); //add two lru_front(table, &k1->entry); unit_assert(table->lru_head == &k1->entry && table->lru_tail == &k1->entry); lru_front(table, &k2->entry); unit_assert(table->lru_head == &k2->entry && table->lru_tail == &k1->entry); //remove first lru_remove(table, &k2->entry); unit_assert(table->lru_head == &k1->entry && table->lru_tail == &k1->entry); lru_front(table, &k2->entry); unit_assert(table->lru_head == &k2->entry && table->lru_tail == &k1->entry); //remove last lru_remove(table, &k1->entry); unit_assert(table->lru_head == &k2->entry && table->lru_tail == &k2->entry); //empty lru_remove(table, &k2->entry); unit_assert(table->lru_head == NULL && table->lru_tail == NULL); lock_basic_unlock(&table->lock); delkey(k1); delkey(k2); }
static void lru_touch(struct lruhash *table, struct lruhash_entry *entry) { if(entry == table->lru_head) return; //move to front lru_remove(table, entry); lru_front(table, entry); }
/** test lru_front lru_remove */ static void test_lru(struct lruhash* table) { testkey_t* k = newkey(12); testkey_t* k2 = newkey(14); lock_quick_lock(&table->lock); unit_assert( table->lru_start == NULL && table->lru_end == NULL); lru_remove(table, &k->entry); unit_assert( table->lru_start == NULL && table->lru_end == NULL); /* add one */ lru_front(table, &k->entry); unit_assert( table->lru_start == &k->entry && table->lru_end == &k->entry); /* remove it */ lru_remove(table, &k->entry); unit_assert( table->lru_start == NULL && table->lru_end == NULL); /* add two */ lru_front(table, &k->entry); unit_assert( table->lru_start == &k->entry && table->lru_end == &k->entry); lru_front(table, &k2->entry); unit_assert( table->lru_start == &k2->entry && table->lru_end == &k->entry); /* remove first in list */ lru_remove(table, &k2->entry); unit_assert( table->lru_start == &k->entry && table->lru_end == &k->entry); lru_front(table, &k2->entry); unit_assert( table->lru_start == &k2->entry && table->lru_end == &k->entry); /* remove last in list */ lru_remove(table, &k->entry); unit_assert( table->lru_start == &k2->entry && table->lru_end == &k2->entry); /* empty the list */ lru_remove(table, &k2->entry); unit_assert( table->lru_start == NULL && table->lru_end == NULL); lock_quick_unlock(&table->lock); delkey(k); delkey(k2); }
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; } }