int hi_rehash(hi_handle_t *hi_hndl, uint32_t new_table_size) { int ret, auto_rehash; void *key, *data; uint32_t keylen; hi_handle_t *hi_handle; hi_iterator_t *iterator; /* create a clean handle for the new structure */ ret = lhi_create_vanilla_hdnl(&hi_handle); if (ret != SUCCESS) return ret; /* we take over the original settings done * by the user taken at hi_create() time */ lhi_transform_hndl_2_hndl(hi_hndl, hi_handle); hi_handle->table_size = new_table_size; /* Allocate memory fot accounting the number of * elements within every bucket in the table. */ ret = XMALLOC((void **) &hi_handle->bucket_size, hi_handle->table_size * sizeof(*hi_handle->bucket_size)); if (ret != 0) { return HI_ERR_SYSTEM; } /* 0 objects in the list at start-up */ hi_handle->no_objects = 0; /* Initiate mutex lock if build with thread * support. */ hi_handle->mutex_lock = NULL; ret = lhi_pthread_mutex_init(&hi_handle->mutex_lock, NULL); if (ret != 0) { return HI_ERR_SYSTEM; } /* Create internal data structure for * list, array or rbtree */ switch (hi_handle->coll_eng) { case COLL_ENG_LIST: case COLL_ENG_LIST_HASH: case COLL_ENG_LIST_MTF: case COLL_ENG_LIST_MTF_HASH: ret = lhi_create_eng_list(hi_handle); if (ret != SUCCESS) return ret; break; case COLL_ENG_ARRAY: case COLL_ENG_ARRAY_HASH: case COLL_ENG_ARRAY_DYN: case COLL_ENG_ARRAY_DYN_HASH: ret = lhi_create_eng_array(hi_handle); if (ret != SUCCESS) return ret; break; case COLL_ENG_RBTREE: ret = lhi_create_eng_rbtree(hi_handle); if (ret != SUCCESS) return ret; break; default: return HI_ERR_INTERNAL; break; } ret = hi_iterator_create(hi_hndl, &iterator); if (ret != SUCCESS) return ret; auto_rehash = hi_handle->rehash_auto; hi_handle->rehash_auto = 0; while ((ret = hi_iterator_getnext(iterator, &data, &key, &keylen)) == SUCCESS) { ret = hi_insert(hi_handle, key, keylen, data); if (ret != SUCCESS) { hi_iterator_fini(iterator); hi_fini(hi_handle); hi_handle->rehash_auto = auto_rehash; return ret; } } hi_handle->rehash_auto = auto_rehash; /* verify that no error occured during iterator run */ if (ret != HI_ERR_NODATA) { hi_iterator_fini(iterator); return ret; } hi_iterator_fini(iterator); /* free old hashish handle */ lhi_fini_internal(hi_hndl); memcpy(hi_hndl, hi_handle, sizeof(*hi_hndl)); return SUCCESS; }
int hi_insert_int16_t(hi_handle_t *hi_hndl, const int16_t key, const void *data) { return hi_insert(hi_hndl, (uint8_t *) &key, sizeof(int16_t), (void *)data); }
static void check_iterator(enum coll_eng engine, enum hash_alg hash_alg) { int ret, i; hi_handle_t *hi_hndl; struct hi_init_set hi_set; hi_iterator_t *iterator; void *data_ptr = (void *) 0xdeadbeef; void *key; uint32_t keylen; hi_set_zero(&hi_set); ret = hi_set_bucket_size(&hi_set, 100); assert(ret == 0); ret = hi_set_hash_alg(&hi_set, hash_alg); assert(ret == 0); ret = hi_set_coll_eng(&hi_set, engine); assert(ret == 0); ret = hi_set_key_cmp_func(&hi_set, hi_cmp_str); assert(ret == 0); /* we need aditional arguments for ARRAY based engines */ switch (engine) { case COLL_ENG_ARRAY: case COLL_ENG_ARRAY_HASH: case COLL_ENG_ARRAY_DYN: case COLL_ENG_ARRAY_DYN_HASH: ret = hi_set_coll_eng_array_size(&hi_set, 20); assert(ret == 0); break; default: break; }; ret = hi_create(&hi_hndl, &hi_set); if (ret != 0) print_error(ret); assert(ret == 0); ret = hi_insert(hi_hndl, (void *) "key", sizeof("key"), "data"); assert(ret == 0); ret = hi_insert(hi_hndl, (void *) "key1", sizeof("key1"), "data1"); assert(ret == 0); ret = hi_insert(hi_hndl, (void *) "key2", sizeof("key2"), "data2"); assert(ret == 0); ret = hi_iterator_create(hi_hndl, &iterator); if (ret != 0) return; for (i = 0; i < 2; i++) { bool got_key[] = { 0, 0, 0 }; unsigned int j; for (j = 0 ; j < 3 ; j++) { data_ptr = NULL; ret = hi_iterator_getnext(iterator, &data_ptr, &key, &keylen); assert(ret == 0); assert(data_ptr); if (strcmp(data_ptr, "data") == 0) { assert(!got_key[0]); got_key[0] = true; continue; } if (strcmp(data_ptr, "data1") == 0) { assert(!got_key[1]); got_key[1] = true; continue; } assert (strcmp(data_ptr, "data2") == 0); assert(!got_key[2]); got_key[2] = true; } ret = hi_iterator_getnext(iterator, &data_ptr, &key, &keylen); assert (ret == HI_ERR_NODATA); ret = hi_iterator_reset(iterator); assert(ret == 0); } hi_iterator_fini(iterator); ret = hi_remove(hi_hndl, (void *) "key", sizeof("key"), &data_ptr); assert(ret == 0); ret = hi_remove(hi_hndl, (void *) "key1", sizeof("key1"), &data_ptr); assert(ret == 0); ret = hi_remove(hi_hndl, (void *) "key2", sizeof("key2"), &data_ptr); assert(ret == 0); ret = hi_fini(hi_hndl); assert(ret == 0); fputs("passed\n", stdout); }
static void check_insert(enum coll_eng engine, enum hash_alg hash_alg) { int ret; hi_handle_t *hi_hndl; struct hi_init_set hi_set; void *data_ptr = (void *) 0xdeadbeef; hi_set_zero(&hi_set); ret = hi_set_bucket_size(&hi_set, 100); assert(ret == 0); ret = hi_set_hash_alg(&hi_set, hash_alg); assert(ret == 0); ret = hi_set_coll_eng(&hi_set, engine); assert(ret == 0); ret = hi_set_key_cmp_func(&hi_set, hi_cmp_str); assert(ret == 0); /* we need aditional arguments for ARRAY based engines */ switch (engine) { case COLL_ENG_ARRAY: case COLL_ENG_ARRAY_HASH: case COLL_ENG_ARRAY_DYN: case COLL_ENG_ARRAY_DYN_HASH: ret = hi_set_coll_eng_array_size(&hi_set, 20); assert(ret == 0); break; default: break; }; ret = hi_create(&hi_hndl, &hi_set); if (ret != 0) print_error(ret); assert(ret == 0); ret = hi_insert(hi_hndl, (void *) "key", sizeof("key"), "XX"); assert(ret == 0); /* same key -> must fail */ ret = hi_insert(hi_hndl, (void *) "key", sizeof("key"), "XX"); assert(ret == HI_ERR_DUPKEY); /* key already in data structure -> must return 0 (SUCCESS) */ ret = hi_get(hi_hndl, (void *) "key", sizeof("key"), &data_ptr); assert(ret == 0); //assert(data_ptr == NULL); ret = hi_remove(hi_hndl, (void *) "key", sizeof("key"), &data_ptr); assert(ret == 0); ret = hi_get(hi_hndl, (void *) "key", sizeof("key"), &data_ptr); assert(ret == HI_ERR_NOKEY); ret = hi_fini(hi_hndl); assert(ret == 0); fputs("passed\n", stdout); }
static void check_get_remove(enum coll_eng engine, enum hash_alg hash_alg) { int ret; hi_handle_t *hi_hndl; struct hi_init_set hi_set; void *data_ret; hi_set_zero(&hi_set); ret = hi_set_bucket_size(&hi_set, 100); assert(ret == 0); ret = hi_set_hash_alg(&hi_set, hash_alg); assert(ret == 0); ret = hi_set_coll_eng(&hi_set, engine); assert(ret == 0); ret = hi_set_key_cmp_func(&hi_set, hi_cmp_str); assert(ret == 0); /* we need aditional arguments for ARRAY based engines */ switch (engine) { case COLL_ENG_ARRAY: case COLL_ENG_ARRAY_HASH: case COLL_ENG_ARRAY_DYN: case COLL_ENG_ARRAY_DYN_HASH: ret = hi_set_coll_eng_array_size(&hi_set, 20); assert(ret == 0); break; default: break; }; ret = hi_create(&hi_hndl, &hi_set); if (ret != 0) print_error(ret); assert(ret == 0); assert(hi_hndl->no_objects == 0); ret = hi_insert(hi_hndl, (void *) "key", sizeof("key"), "DATA"); assert(ret == 0); assert(hi_hndl->no_objects == 1); ret = hi_insert(hi_hndl, (void *) "key2", sizeof("key2"), "DATAX"); assert(ret == 0); assert(hi_hndl->no_objects == 2); ret = hi_insert(hi_hndl, (void *) "key3", sizeof("key3"), "DATAX"); assert(ret == 0); assert(hi_hndl->no_objects == 3); /* key already in data structure -> must return 0 (SUCCESS) */ ret = hi_get(hi_hndl, (void *) "key", sizeof("key"), &data_ret); if (ret != 0) print_error(ret); check_data(data_ret, "DATA"); assert(hi_hndl->no_objects == 3); ret = hi_get(hi_hndl, (void *) "key3", sizeof("key3"), &data_ret); if (ret != 0) print_error(ret); check_data(data_ret, "DATAX"); assert(hi_hndl->no_objects == 3); data_ret = NULL; ret = hi_remove(hi_hndl, (void *) "key", sizeof("key"), &data_ret); assert(ret == 0); assert(hi_hndl->no_objects == 2); check_data(data_ret, "DATA"); data_ret = NULL; ret = hi_remove(hi_hndl, (void *) "key2", sizeof("key2"), &data_ret); assert(ret == 0); assert(hi_hndl->no_objects == 1); ret = hi_remove(hi_hndl, (void *) "key3", sizeof("key3"), &data_ret); assert(ret == 0); assert(hi_hndl->no_objects == 0); check_data(data_ret, "DATAX"); ret = hi_fini(hi_hndl); assert(ret == 0); fputs("passed\n", stdout); }
/* concurrent_test do the following: * o It creates and removes randomly entries * whithin the hash table. At the end the count * must be equal to the expected */ static void concurrent_test(int num) { int i, ret; void *data; char *ptr_bucket[TEST_ITER_NO][2]; struct drand48_data seed_data; unsigned long seed; long int rand_res; seed = get_proper_seed(); /* init per thread seed */ srand48_r(seed, &seed_data); /* sleep for some amount of time */ lrand48_r(&seed_data, &rand_res); msleep(rand_res % 40000); /* max 4s */ fprintf(stderr, "+%d", num); for (i =0; i < TEST_ITER_NO; i++) { int sucess; char *key_ptr, *data_ptr; /* insert at least TEST_ITER_NO data * sets */ do { sucess = 1; random_string(KEYLEN, &key_ptr, &seed_data); random_string(DATALEN, &data_ptr, &seed_data); ptr_bucket[i][KEY] = key_ptr; ptr_bucket[i][DATA] = data_ptr; ret = hi_insert(hi_hndl, (void *) key_ptr, strlen(key_ptr), (void *) data_ptr); if (ret < 0) { fprintf(stderr, "# Key (%s) already in hash\n", key_ptr); fprintf(stderr, "Error %s\n", ret == HI_ERR_SYSTEM ? strerror(errno) : hi_strerror(ret)); sucess = 0; free(key_ptr); free(data_ptr); } } while (!sucess); } lrand48_r(&seed_data, &rand_res); msleep(rand_res % 4000); /* max 4s */ /* verify storage and cleanup */ for (i = 0; i < TEST_ITER_NO; i++) { ret = hi_remove(hi_hndl, ptr_bucket[i][KEY], strlen(ptr_bucket[i][KEY]), &data); if (ret == 0) { if (data != ptr_bucket[i][DATA]) { fprintf(stderr, "Failed: should %s - is %s\n", ptr_bucket[i][DATA], (char *) data); } free(ptr_bucket[i][KEY]); free(ptr_bucket[i][DATA]); } else { fprintf(stderr, "# already deleted\n"); } } fprintf(stderr, "-%d", num); }
/* The ending \0 of string is also a part of the key and should not be forgotten */ int hi_insert_str(hi_handle_t *hi_hndl, const char *key, const void *data) { return hi_insert(hi_hndl, (uint8_t *) key, strlen(key) + 1, (void *)data); }