#include "rcu_hash.h" #include "maat_utils.h" #include struct rcu_hash_table *g_htable = NULL; struct user_data { int id; char name[32]; }; void data_free(void *user_ctx, void *data) { FREE(data); } TEST(rcu_hash_new, invalid_input_parameter) { struct rcu_hash_table *htable = rcu_hash_new(NULL); EXPECT_TRUE(htable == NULL); } TEST(rcu_hash_add_one_node, single_thread) { /* add one node to hash */ struct rcu_hash_table *htable = rcu_hash_new(data_free); EXPECT_TRUE(htable != NULL); struct user_data *data = ALLOC(struct user_data, 1); data->id = 101; char name[64] = "www.baidu.com"; memcpy(data->name, name, strlen(name)); char key[64] = "http_url"; size_t key_len = strlen(key); /* add to hash */ rcu_hash_add(htable, key, key_len, (void *)data); /* find in hash before commit */ void *res = rcu_hash_find(htable, key, key_len); EXPECT_TRUE(res == NULL); int ret = rcu_hash_count(htable); EXPECT_EQ(ret, 0); void **data_array = NULL; rcu_hash_commit(htable); ret = rcu_hash_list(htable, &data_array); EXPECT_EQ(ret, 1); if (data_array != NULL) { free(data_array); data_array = NULL; } /* find in hash after commit */ res = rcu_hash_find(htable, key, key_len); EXPECT_TRUE(res != NULL); struct user_data *res_data = (struct user_data *)res; EXPECT_EQ(res_data->id, 101); EXPECT_STREQ(res_data->name, "www.baidu.com"); ret = rcu_hash_count(htable); EXPECT_EQ(ret, 1); rcu_hash_free(htable); } TEST(rcu_hash_add_multi_node, single_thread) { /* add multi node to hash */ struct rcu_hash_table *htable = rcu_hash_new(data_free); EXPECT_TRUE(htable != NULL); struct user_data *data0 = ALLOC(struct user_data, 1); data0->id = 101; char name0[64] = "www.baidu.com"; memcpy(data0->name, name0, strlen(name0)); char key0[64] = "http_url"; size_t key0_len = strlen(key0); rcu_hash_add(htable, key0, key0_len, (void *)data0); struct user_data *data1 = ALLOC(struct user_data, 1); data1->id = 102; char name1[64] = "127.0.0.1"; memcpy(data1->name, name1, strlen(name1)); char key1[64] = "http_host"; size_t key1_len = strlen(key1); rcu_hash_add(htable, key1, key1_len, (void *)data1); struct user_data *data2 = ALLOC(struct user_data, 1); data2->id = 103; char name2[64] = "mahuateng"; memcpy(data2->name, name2, strlen(name2)); char key2[64] = "192.168.0.1"; size_t key2_len = strlen(key2); rcu_hash_add(htable, key2, key2_len, (void *)data2); struct user_data *data3 = ALLOC(struct user_data, 1); data3->id = 104; char name3[64] = "liyanhong"; memcpy(data3->name, name3, strlen(name3)); char key3[64] = "192.168.0.2"; size_t key3_len = strlen(key3); rcu_hash_add(htable, key3, key3_len, (void *)data3); /* find in hash before commit */ void *res = rcu_hash_find(htable, key0, key0_len); EXPECT_TRUE(res == NULL); res = rcu_hash_find(htable, key1, key1_len); EXPECT_TRUE(res == NULL); int ret = rcu_hash_count(htable); EXPECT_EQ(ret, 0); void **data_array = NULL; ret = rcu_hash_list(htable, &data_array); EXPECT_EQ(ret, 0); if (data_array != NULL) { free(data_array); data_array = NULL; } rcu_hash_commit(htable); ret = rcu_hash_list(htable, &data_array); EXPECT_EQ(ret, 4); if (data_array != NULL) { free(data_array); data_array = NULL; } /* find in hash after commit */ res = rcu_hash_find(htable, key0, key0_len); EXPECT_TRUE(res != NULL); struct user_data *res_data0 = (struct user_data *)res; EXPECT_EQ(res_data0->id, 101); EXPECT_STREQ(res_data0->name, "www.baidu.com"); res = rcu_hash_find(htable, key1, key1_len); EXPECT_TRUE(res != NULL); struct user_data *res_data1 = (struct user_data *)res; EXPECT_EQ(res_data1->id, 102); EXPECT_STREQ(res_data1->name, "127.0.0.1"); res = rcu_hash_find(htable, key2, key2_len); EXPECT_TRUE(res != NULL); struct user_data *res_data2 = (struct user_data *)res; EXPECT_EQ(res_data2->id, 103); EXPECT_STREQ(res_data2->name, "mahuateng"); res = rcu_hash_find(htable, key3, key3_len); EXPECT_TRUE(res != NULL); struct user_data *res_data3 = (struct user_data *)res; EXPECT_EQ(res_data3->id, 104); EXPECT_STREQ(res_data3->name, "liyanhong"); ret = rcu_hash_count(htable); EXPECT_EQ(ret, 4); rcu_hash_free(htable); } TEST(rcu_hash_del_one_node, single_thread) { /* case1: add and del before commit */ struct rcu_hash_table *htable = rcu_hash_new(data_free); EXPECT_TRUE(htable != NULL); struct user_data *data = ALLOC(struct user_data, 1); data->id = 101; char name[64] = "www.baidu.com"; memcpy(data->name, name, strlen(name)); char key[64] = "http_url"; size_t key_len = strlen(key); /* add to hash */ rcu_hash_add(htable, key, key_len, (void *)data); void **data_array = NULL; int ret = rcu_hash_list(htable, &data_array); EXPECT_EQ(ret, 0); if (data_array != NULL) { free(data_array); data_array = NULL; } /* find in hash before commit */ void *res = rcu_hash_find(htable, key, key_len); EXPECT_TRUE(res == NULL); ret = rcu_hash_count(htable); EXPECT_EQ(ret, 0); rcu_hash_del(htable, key, key_len); ret = rcu_hash_list(htable, &data_array); EXPECT_EQ(ret, 0); if (data_array != NULL) { free(data_array); data_array = NULL; } rcu_hash_commit(htable); /* find in hash after commit */ res = rcu_hash_find(htable, key, key_len); EXPECT_TRUE(res == NULL); /* case2: add && commit, and del */ struct user_data *data1 = ALLOC(struct user_data, 1); data1->id = 102; char name1[64] = "127.0.0.1"; memcpy(data1->name, name1, strlen(name1)); char key1[64] = "http_host"; size_t key1_len = strlen(key1); rcu_hash_add(htable, key1, key1_len, (void *)data1); /* add commit */ rcu_hash_commit(htable); rcu_hash_del(htable, key1, key1_len); res = rcu_hash_find(htable, key1, key1_len); EXPECT_TRUE(res != NULL); struct user_data *res_data = (struct user_data *)res; EXPECT_EQ(res_data->id, 102); EXPECT_STREQ(res_data->name, "127.0.0.1"); ret = rcu_hash_count(htable); EXPECT_EQ(ret, 1); /* delete commit */ rcu_hash_commit(htable); res = rcu_hash_find(htable, key1, key1_len); EXPECT_TRUE(res == NULL); ret = rcu_hash_count(htable); EXPECT_EQ(ret, 0); rcu_hash_free(htable); } TEST(rcu_hash_del_multi_node, single_thread) { /* case1: add and del before commit */ struct rcu_hash_table *htable = rcu_hash_new(data_free); EXPECT_TRUE(htable != NULL); struct user_data *data1 = ALLOC(struct user_data, 1); data1->id = 101; char name1[64] = "www.baidu.com"; memcpy(data1->name, name1, strlen(name1)); char key1[64] = "http_url"; size_t key1_len = strlen(key1); rcu_hash_add(htable, key1, key1_len, (void *)data1); struct user_data *data2 = ALLOC(struct user_data, 1); data2->id = 102; char name2[64] = "127.0.0.1"; memcpy(data2->name, name2, strlen(name2)); char key2[64] = "http_host"; size_t key2_len = strlen(key2); rcu_hash_add(htable, key2, key2_len, (void *)data2); /* find in hash before commit */ void *res = rcu_hash_find(htable, key1, key1_len); EXPECT_TRUE(res == NULL); int ret = rcu_hash_count(htable); EXPECT_EQ(ret, 0); /* add del, then commit */ rcu_hash_del(htable, key1, key1_len); rcu_hash_commit(htable); /* find in hash after commit */ res = rcu_hash_find(htable, key1, key1_len); EXPECT_TRUE(res == NULL); res = rcu_hash_find(htable, key2, key2_len); EXPECT_TRUE(res != NULL); ret = rcu_hash_count(htable); EXPECT_EQ(ret, 1); rcu_hash_free(htable); } TEST(rcu_hash_add_with_same_key, single_thread) { struct rcu_hash_table *htable = rcu_hash_new(data_free); EXPECT_TRUE(htable != NULL); char key[64] = "http_url"; size_t key_len = strlen(key); //add data1 struct user_data *data1 = ALLOC(struct user_data, 1); data1->id = 101; char name1[64] = "www.baidu.com"; memcpy(data1->name, name1, strlen(name1)); int ret = rcu_hash_add(htable, key, key_len, (void *)data1); EXPECT_EQ(ret, 0); void *res = rcu_hash_find(htable, key, key_len); EXPECT_TRUE(res == NULL); //add data2 struct user_data *data2 = ALLOC(struct user_data, 1); data2->id = 102; char name2[64] = "www.google.com"; memcpy(data2->name, name2, strlen(name2)); ret = rcu_hash_add(htable, key, key_len, (void *)data2); EXPECT_EQ(ret, -1); FREE(data2); rcu_hash_commit(htable); res = rcu_hash_find(htable, key, key_len); EXPECT_TRUE(res != NULL); struct user_data *tmp_data = (struct user_data *)res; EXPECT_EQ(tmp_data->id, 101); EXPECT_STREQ(tmp_data->name, "www.baidu.com"); rcu_hash_free(htable); } TEST(rcu_hash_del_with_same_key, single_thread) { struct rcu_hash_table *htable = rcu_hash_new(data_free); EXPECT_TRUE(htable != NULL); char key[64] = "http_url"; size_t key_len = strlen(key); int ret = rcu_hash_del(htable, key, key_len); EXPECT_EQ(ret, 0); //add data1 struct user_data *data1 = ALLOC(struct user_data, 1); data1->id = 101; char name1[64] = "www.baidu.com"; memcpy(data1->name, name1, strlen(name1)); ret = rcu_hash_add(htable, key, key_len, (void *)data1); EXPECT_EQ(ret, 0); void *res = rcu_hash_find(htable, key, key_len); EXPECT_TRUE(res == NULL); ret = rcu_hash_del(htable, key, key_len); EXPECT_EQ(ret, 0); //add data2 struct user_data *data2 = ALLOC(struct user_data, 1); data2->id = 102; char name2[64] = "www.google.com"; memcpy(data2->name, name2, strlen(name2)); ret = rcu_hash_add(htable, key, key_len, (void *)data2); EXPECT_EQ(ret, 0); rcu_hash_commit(htable); res = rcu_hash_find(htable, key, key_len); EXPECT_TRUE(res != NULL); struct user_data *tmp_data = (struct user_data *)res; EXPECT_EQ(tmp_data->id, 102); EXPECT_STREQ(tmp_data->name, "www.google.com"); rcu_hash_free(htable); } TEST(rcu_hash_modify_with_same_key, single_thread) { struct rcu_hash_table *htable = rcu_hash_new(data_free); EXPECT_TRUE(htable != NULL); char key[64] = "http_url"; size_t key_len = strlen(key); //add data1 struct user_data *data1 = ALLOC(struct user_data, 1); data1->id = 101; char name1[64] = "www.baidu.com"; memcpy(data1->name, name1, strlen(name1)); rcu_hash_add(htable, key, key_len, (void *)data1); void *res = rcu_hash_find(htable, key, key_len); EXPECT_TRUE(res == NULL); //del data1 rcu_hash_del(htable, key, key_len); //add data2 struct user_data *data2 = ALLOC(struct user_data, 1); data2->id = 102; char name2[64] = "www.google.com"; memcpy(data2->name, name2, strlen(name2)); rcu_hash_add(htable, key, key_len, (void *)data2); rcu_hash_commit(htable); res = rcu_hash_find(htable, key, key_len); struct user_data *tmp_data = (struct user_data *)res; EXPECT_EQ(tmp_data->id, 102); EXPECT_STREQ(tmp_data->name, "www.google.com"); rcu_hash_free(htable); } TEST(global_rcu_hash_add, single_thread) { EXPECT_TRUE(g_htable != NULL); char key1[64] = "http_url"; size_t key1_len = strlen(key1); struct user_data *data1 = ALLOC(struct user_data, 1); data1->id = 101; char name1[64] = "www.baidu.com"; memcpy(data1->name, name1, strlen(name1)); rcu_hash_add(g_htable, key1, key1_len, (void *)data1); int ret = rcu_hash_count(g_htable); EXPECT_EQ(ret, 0); rcu_hash_commit(g_htable); ret = rcu_hash_count(g_htable); EXPECT_EQ(ret, 1); void *res = rcu_hash_find(g_htable, key1, key1_len); EXPECT_TRUE(res != NULL); } TEST(global_rcu_hash_find, single_thread) { EXPECT_TRUE(g_htable != NULL); const char *key = "http_url"; size_t key_len = strlen(key); void *res = rcu_hash_find(g_htable, key, key_len); EXPECT_TRUE(res != NULL); } TEST(global_rcu_hash_del, single_thread) { EXPECT_TRUE(g_htable != NULL); const char *key = "http_url"; size_t key_len = strlen(key); void *res = rcu_hash_find(g_htable, key, key_len); EXPECT_TRUE(res != NULL); rcu_hash_del(g_htable, key, key_len); rcu_hash_commit(g_htable); res = rcu_hash_find(g_htable, key, key_len); EXPECT_TRUE(res == NULL); } #define THREAD_NUM 10 struct thread_param { int thread_id; int test_count; unsigned long long time_elapse_ms; }; void *rcu_scan_thread(void *arg) { struct thread_param *param = (struct thread_param *)arg; int hit_cnt = 0; void **data_array = NULL; sleep(2); for (int index = 0; index < param->test_count; index++) { size_t count = rcu_hash_list(g_htable, &data_array); for (size_t i = 0; i < count; i++) { struct user_data *user_data = (struct user_data *)data_array[i]; if (user_data != NULL && user_data->id == 101) { hit_cnt++; } } } int *is_all_hit = ALLOC(int, 1); *is_all_hit = (hit_cnt == param->test_count) ? 1 : 0; printf("thread[%d]: hit_cnt:%d\n", param->thread_id, hit_cnt); return is_all_hit; } void *rcu_update_thread(void *arg) { const char *key = "http_url"; size_t key_len = strlen(key); for (int i = 0; i < 10; i++) { rcu_hash_del(g_htable, key, key_len); rcu_hash_commit(g_htable); sleep(1); struct user_data *data = ALLOC(struct user_data, 1); data->id = 101; char name[64] = "www.baidu.com"; memcpy(data->name, name, strlen(name)); rcu_hash_add(g_htable, key, key_len, data); rcu_hash_commit(g_htable); } int *is_all_hit = ALLOC(int, 1); *is_all_hit = 1; return is_all_hit; } TEST(rcu_hash_update, multi_thread) { pthread_t threads[THREAD_NUM + 1]; struct thread_param t_param[THREAD_NUM + 1]; for (int i = 0; i < THREAD_NUM + 1; i++) { t_param[i].thread_id = i; t_param[i].test_count = 1000 * 1000; t_param[i].time_elapse_ms = 0; if (i < THREAD_NUM) { pthread_create(&threads[i], NULL, rcu_scan_thread, t_param+i); } else { pthread_create(&threads[i], NULL, rcu_update_thread, t_param+i); } } int *is_all_hit = NULL; unsigned long long time_elapse_ms = 0, scan_count = 0; for (int i = 0; i < THREAD_NUM + 1; i++) { pthread_join(threads[i], (void **)&is_all_hit); time_elapse_ms += t_param[i].time_elapse_ms; scan_count += t_param[i].test_count; EXPECT_EQ(*is_all_hit, 1); *is_all_hit = 0; free(is_all_hit); } } int main(int argc, char ** argv) { int ret=0; ::testing::InitGoogleTest(&argc, argv); g_htable = rcu_hash_new(data_free); ret=RUN_ALL_TESTS(); rcu_hash_free(g_htable); return ret; }