static void test_clear() { genhash_t* h=get_test_hash(); assert(genhash_size(h) == 26); genhash_clear(h); assert(genhash_size(h) == 0); genhash_free(h); }
static void test_function_update() { genhash_t* h=genhash_init(4, get_string_hash_ops()); int type=0; assert_hash_val(NULL, h, "x"); type=genhash_fun_update(h, "x", update_fun, free_str, NULL); assert(type == NEW); assert_hash_val("", h, "x"); type=genhash_fun_update(h, "x", update_fun, free_str, NULL); assert(type == MODIFICATION); assert_hash_val("x", h, "x"); type=genhash_fun_update(h, "x", update_fun, free_str, NULL); assert(type == MODIFICATION); assert_hash_val("xx", h, "x"); assert(genhash_size(h) == 1); genhash_free(h); }
static void test_multiple_keys() { genhash_t* h=genhash_init(1, get_string_hash_ops()); int deleted = 0, i = 0; /* Pollute the space to allow some hash collisions */ for(i=0; i<16000; i++) { char key[8]; snprintf(key, sizeof(key), "k%d", i); genhash_store(h, key, key); assert_hash_val(key, h, key); } assert_hash_val(NULL, h, "x"); genhash_store(h, "x", "a"); genhash_store(h, "x", "b"); assert_hash_val("b", h, "x"); deleted=genhash_delete(h, "x"); assert(deleted == 1); assert_hash_val("a", h, "x"); deleted=genhash_delete(h, "x"); assert(deleted == 1); assert_hash_val(NULL, h, "x"); deleted=genhash_delete(h, "x"); assert(deleted == 0); genhash_store(h, "x", "a"); genhash_store(h, "x", "b"); genhash_store(h, "y", "yz"); assert(genhash_size(h) == 16003); assert(genhash_size_for_key(h, "x") == 2); deleted=genhash_delete_all(h, "x"); assert(deleted == 2); genhash_free(h); }
void mcache_set(mcache *m, void *it, uint64_t exptime, bool add_only, bool mod_exptime_if_exists) { assert(it); assert(m->funcs); assert(m->funcs->item_get_next(it) == NULL); assert(m->funcs->item_get_prev(it) == NULL); if (m == NULL) { return; } /* TODO: Our lock areas are possibly too wide. */ if (m->lock) { cb_mutex_enter(m->lock); } if (m->map != NULL) { /* Evict some items if necessary. */ int i; for (i = 0; m->lru_tail != NULL && i < 20; i++) { void *last_it; if ((uint32_t)genhash_size(m->map) < m->max) { break; } last_it = m->lru_tail; mcache_item_unlink(m, last_it); if (m->key_alloc) { int len = m->funcs->item_key_len(last_it); char buf[KEY_MAX_LENGTH + 10]; memcpy(buf, m->funcs->item_key(last_it), len); buf[len] = '\0'; genhash_delete(m->map, buf); } else { genhash_delete(m->map, m->funcs->item_key(last_it)); } m->tot_evictions++; } if ((uint32_t)genhash_size(m->map) < m->max) { char *key = m->funcs->item_key(it); int key_len = m->funcs->item_key_len(it); char *key_buf = NULL; if (m->key_alloc) { /* The ITEM_key is not NULL or space terminated, */ /* and we need a copy, too, for hashtable ownership. */ /* TODO: Move this outside the lock area? */ key_buf = malloc(key_len + 1); if (key_buf != NULL) { memcpy(key_buf, key, key_len); key_buf[key_len] = '\0'; key = key_buf; } else { key = NULL; } } if (key != NULL) { void *existing = add_only ? genhash_find(m->map, key) : NULL; if (existing != NULL) { mcache_item_unlink(m, existing); mcache_item_touch(m, existing); if (mod_exptime_if_exists) { m->funcs->item_set_exptime(existing, exptime); } m->tot_add_skips++; if (settings.verbose > 1) { moxi_log_write("mcache add-skip: %s\n", key); } if (key_buf != NULL) { free(key_buf); } } else { m->funcs->item_set_exptime(it, exptime); m->funcs->item_add_ref(it); genhash_update(m->map, key, it); m->tot_adds++; m->tot_add_bytes += m->funcs->item_len(it); if (settings.verbose > 1) { moxi_log_write("mcache add: %s\n", key); } } } else { m->tot_add_fails++; } } else { m->tot_add_fails++; } } if (m->lock) { cb_mutex_exit(m->lock); } }