]> pd.if.org Git - nbds/blob - test/map_test2.c
f9444ca0077999c18a1f58f2dea19283219112c9
[nbds] / test / map_test2.c
1 /* 
2  * Written by Josh Dybnis and released to the public domain, as explained at
3  * http://creativecommons.org/licenses/publicdomain
4  *
5  * tests ported from high-scale-lib
6  * http://sourceforge.net/projects/high-scale-lib
7  */
8 #include <stdio.h>
9 #include <pthread.h>
10 #include <sys/time.h>
11
12 #include "CuTest.h"
13
14 #include "common.h"
15 #include "runtime.h"
16 #include "nstring.h"
17 #include "map.h"
18 #include "list.h"
19 #include "skiplist.h"
20 #include "hashtable.h"
21 #include "lwt.h"
22 #include "mem.h"
23
24 #define ASSERT_EQUAL(x, y) CuAssertIntEquals(tc, x, y)
25
26 //#define TEST_STRING_KEYS
27
28 typedef struct worker_data {
29     int id;
30     CuTest *tc;
31     map_t *map;
32     volatile int *wait;
33 } worker_data_t;
34
35 static const map_impl_t *map_type_;
36
37 static size_t iterator_size (map_t *map) {
38     map_iter_t *iter = map_iter_begin(map, 0);
39     size_t count = 0;
40     while (map_iter_next(iter, NULL) != DOES_NOT_EXIST) {
41         count++;
42     }
43     map_iter_free(iter);
44     return count;
45 }
46
47 // Test some basic stuff; add a few keys, remove a few keys
48 void basic_test (CuTest* tc) {
49
50 #ifdef TEST_STRING_KEYS
51     map_t *map = map_alloc(map_type_, &DATATYPE_NSTRING);
52     nstring_t *s1 = ns_alloc(3); strcpy(s1->data, "k1");
53     nstring_t *s2 = ns_alloc(3); strcpy(s2->data, "k2");
54     nstring_t *s3 = ns_alloc(3); strcpy(s3->data, "k3");
55     nstring_t *s4 = ns_alloc(3); strcpy(s4->data, "k4");
56     map_key_t k1 = (map_key_t)s1;
57     map_key_t k2 = (map_key_t)s2;
58     map_key_t k3 = (map_key_t)s3;
59     map_key_t k4 = (map_key_t)s4;
60 #else
61     map_t *map = map_alloc(map_type_, NULL);
62     map_key_t k1 = (map_key_t)1;
63     map_key_t k2 = (map_key_t)2;
64     map_key_t k3 = (map_key_t)3;
65     map_key_t k4 = (map_key_t)4;
66 #endif
67
68     ASSERT_EQUAL( 0,              map_count  (map)        );
69     ASSERT_EQUAL( DOES_NOT_EXIST, map_add    (map, k1,10) );
70     ASSERT_EQUAL( 1,              map_count  (map)        );
71     ASSERT_EQUAL( 1,              iterator_size(map)      );
72     ASSERT_EQUAL( DOES_NOT_EXIST, map_add    (map, k2,20) );
73     ASSERT_EQUAL( 2,              map_count  (map)        );
74     ASSERT_EQUAL( 2,              iterator_size(map)      );
75     ASSERT_EQUAL( 20,             map_get    (map, k2)    );
76     ASSERT_EQUAL( 10,             map_set    (map, k1,11) );
77     ASSERT_EQUAL( 20,             map_set    (map, k2,21) );
78     ASSERT_EQUAL( 2,              map_count  (map)        );
79     ASSERT_EQUAL( 2,              iterator_size(map)      );
80     ASSERT_EQUAL( 21,             map_add    (map, k2,22) );
81     ASSERT_EQUAL( 11,             map_remove (map, k1)    );
82     ASSERT_EQUAL( DOES_NOT_EXIST, map_get    (map, k1)    );
83     ASSERT_EQUAL( 1,              map_count  (map)        );
84     ASSERT_EQUAL( 1,              iterator_size(map)      );
85     ASSERT_EQUAL( DOES_NOT_EXIST, map_remove (map, k1)    );
86     ASSERT_EQUAL( 21,             map_remove (map, k2)    );
87     ASSERT_EQUAL( 0,              map_count  (map)        );
88     ASSERT_EQUAL( 0,              iterator_size(map)      );
89     ASSERT_EQUAL( DOES_NOT_EXIST, map_remove (map, k2)    );
90     ASSERT_EQUAL( DOES_NOT_EXIST, map_remove (map, k3)    );
91     ASSERT_EQUAL( 0,              map_count  (map)        );
92     ASSERT_EQUAL( 0,              iterator_size(map)      );
93     
94     ASSERT_EQUAL( DOES_NOT_EXIST, map_add    (map, k4,40) );
95     ASSERT_EQUAL( 40,             map_get    (map, k4)    );
96     ASSERT_EQUAL( 1,              map_count  (map)        );
97     ASSERT_EQUAL( 1,              iterator_size(map)      );
98     ASSERT_EQUAL( 40,             map_remove (map, k4)    );
99     ASSERT_EQUAL( DOES_NOT_EXIST, map_get    (map, k4)    );
100     ASSERT_EQUAL( 0,              map_count  (map)        );
101     ASSERT_EQUAL( 0,              iterator_size(map)      );
102
103     ASSERT_EQUAL( DOES_NOT_EXIST, map_replace(map, k4,10) );
104     ASSERT_EQUAL( DOES_NOT_EXIST, map_get    (map, k4)    );
105     ASSERT_EQUAL( DOES_NOT_EXIST, map_set    (map, k4,40) );
106     ASSERT_EQUAL( 40,             map_replace(map, k4,41) );
107     ASSERT_EQUAL( 41,             map_get    (map, k4)    );
108     ASSERT_EQUAL( 41,             map_remove (map, k4)    );
109     ASSERT_EQUAL( DOES_NOT_EXIST, map_get    (map, k4)    );
110     ASSERT_EQUAL( 0,              map_count  (map)        );
111     ASSERT_EQUAL( 0,              iterator_size(map)      );
112
113     ASSERT_EQUAL( DOES_NOT_EXIST, map_replace(map, k2,20) );
114     ASSERT_EQUAL( DOES_NOT_EXIST, map_get    (map, k2)    );
115
116     // In the end, all entries should be removed
117     ASSERT_EQUAL( DOES_NOT_EXIST, map_set    (map, k2,20) );
118     ASSERT_EQUAL( 20,             map_replace(map, k2,21) );
119     ASSERT_EQUAL( 21,             map_get    (map, k2)    );
120     ASSERT_EQUAL( 21,             map_remove (map, k2)    );
121     ASSERT_EQUAL( DOES_NOT_EXIST, map_get    (map, k2)    );
122     ASSERT_EQUAL( 0,              map_count  (map)        );
123     ASSERT_EQUAL( 0,              iterator_size(map)      );
124
125     map_free(map);
126
127     rcu_update(); // In a quiecent state.
128 #ifdef TEST_STRING_KEYS
129     nbd_free(s1); nbd_free(s2); nbd_free(s3); nbd_free(s4);
130 #endif
131 }
132
133 void *add_remove_worker (void *arg) {
134     worker_data_t *wd = (worker_data_t *)arg;
135     map_t *map = wd->map;
136     CuTest* tc = wd->tc;
137     int d = wd->id;
138     int iters = 10000;
139
140     SYNC_ADD(wd->wait, -1);
141     do { } while (*wd->wait); // wait for all workers to be ready
142
143     map_key_t key;
144 #ifdef TEST_STRING_KEYS
145     nstring_t *s = ns_alloc(9);
146     key = (map_key_t)s;
147 #endif
148
149     for (int j = 0; j < 10; ++j) {
150         for (int i = d+1; i < iters; i+=2) {
151 #ifdef TEST_STRING_KEYS
152             s->len = 1 + snprintf(s->data, 9, "%u", i);
153 #else
154             key = (map_key_t)i;
155 #endif
156             TRACE("t0", "test map_add() iteration (%llu, %llu)", j, i);
157             ASSERT_EQUAL(DOES_NOT_EXIST, map_add(map, key, d+1) );
158             rcu_update(); // In a quiecent state.
159         }
160         for (int i = d+1; i < iters; i+=2) {
161 #ifdef TEST_STRING_KEYS
162             s->len = 1 + snprintf(s->data, 9, "%u", i);
163 #else
164             key = (map_key_t)i;
165 #endif
166             TRACE("t0", "test map_remove() iteration (%llu, %llu)", j, i);
167             ASSERT_EQUAL(d+1, map_remove(map, key) );
168             rcu_update(); // In a quiecent state.
169         }
170     }
171 #ifdef TEST_STRING_KEYS
172     nbd_free(s);
173 #endif
174     return NULL;
175 }
176
177 // Do some simple concurrent testing
178 void concurrent_add_remove_test (CuTest* tc) {
179
180     pthread_t thread[2];
181     worker_data_t wd[2];
182     static const int num_threads = 2;
183     volatile int wait = num_threads;
184 #ifdef TEST_STRING_KEYS
185     map_t *map = map_alloc(map_type_, &DATATYPE_NSTRING);
186 #else
187     map_t *map = map_alloc(map_type_, NULL);
188 #endif
189
190     struct timeval tv1, tv2;
191     gettimeofday(&tv1, NULL);
192
193     // In 2 threads, add & remove even & odd elements concurrently
194     int i;
195     for (i = 0; i < num_threads; ++i) {
196         wd[i].id = i;
197         wd[i].tc = tc;
198         wd[i].map = map;
199         wd[i].wait = &wait;
200         int rc = nbd_thread_create(thread + i, i, add_remove_worker, wd + i);
201         if (rc != 0) { perror("nbd_thread_create"); return; }
202     }
203
204     for (i = 0; i < num_threads; ++i) {
205         pthread_join(thread[i], NULL);
206     }
207
208     gettimeofday(&tv2, NULL);
209     int ms = (int)(1000000*(tv2.tv_sec - tv1.tv_sec) + tv2.tv_usec - tv1.tv_usec) / 1000;
210     map_print(map);
211     printf("Th:%d Time:%dms\n", num_threads, ms);
212     fflush(stdout);
213
214     // In the end, all members should be removed
215     ASSERT_EQUAL( 0, map_count(map) );
216     ASSERT_EQUAL( 0, iterator_size(map) );
217
218     // In a quiecent state; it is safe to free.
219     map_free(map);
220 }
221
222 void basic_iteration_test (CuTest* tc) {
223 #ifdef TEST_STRING_KEYS
224     map_t *map = map_alloc(map_type_, &DATATYPE_NSTRING);
225     nstring_t *s1 = ns_alloc(3); strcpy(s1->data, "k1");
226     nstring_t *s2 = ns_alloc(3); strcpy(s2->data, "k2");
227     map_key_t k1 = (map_key_t)s1;
228     map_key_t k2 = (map_key_t)s2;
229     nstring_t *x_k;
230     nstring_t *y_k;
231 #else
232     map_t *map = map_alloc(map_type_, NULL);
233     map_key_t k1 = (map_key_t)1;
234     map_key_t k2 = (map_key_t)2;
235     map_key_t x_k;
236     map_key_t y_k;
237 #endif
238
239     ASSERT_EQUAL( DOES_NOT_EXIST, map_add    (map, k1,1) );
240     ASSERT_EQUAL( DOES_NOT_EXIST, map_add    (map, k2,2) );
241
242     map_val_t x_v, y_v;
243     map_iter_t *iter = map_iter_begin(map, 0);
244     x_v = map_iter_next(iter, (map_key_t *)&x_k);
245     y_v = map_iter_next(iter, (map_key_t *)&y_k);
246     ASSERT_EQUAL( DOES_NOT_EXIST, map_iter_next(iter, NULL) );
247     map_iter_free(iter);
248 #ifdef TEST_STRING_KEYS
249     ASSERT_EQUAL( TRUE, (ns_cmp(x_k, s1) == 0 && x_v == 1) || (ns_cmp(y_k, s1) == 0 && y_v == 1) );
250     ASSERT_EQUAL( TRUE, (ns_cmp(x_k, s2) == 0 && x_v == 2) || (ns_cmp(y_k, s2) == 0 && y_v == 2) );
251     nbd_free(s1);
252     nbd_free(s2);
253 #else
254     ASSERT_EQUAL( TRUE, (x_k == k1 && x_v == 1) || (y_k == k1 && y_v == 1) );
255     ASSERT_EQUAL( TRUE, (x_k == k2 && x_v == 2) || (y_k == k2 && y_v == 2) );
256 #endif
257
258     map_free(map);
259 }
260
261 void big_iteration_test (CuTest* tc) {
262     static const int n = 10000;
263     
264 #ifdef TEST_STRING_KEYS
265     map_t *map = map_alloc(map_type_, &DATATYPE_NSTRING);
266     nstring_t *s = ns_alloc(9);
267     nstring_t *s3 = ns_alloc(3); strcpy(s3->data, "k3");
268     nstring_t *s4 = ns_alloc(3); strcpy(s4->data, "k4");
269     map_key_t k3 = (map_key_t)s3;
270     map_key_t k4 = (map_key_t)s4;
271     map_key_t key = (map_key_t)s;
272 #else
273     map_t *map = map_alloc(map_type_, NULL);
274     map_key_t k3 = (map_key_t)3;
275     map_key_t k4 = (map_key_t)4;
276     map_key_t key;
277 #endif
278
279     for (int i = 1; i <= n; ++i) {
280 #ifdef TEST_STRING_KEYS
281         s->len = 1 + snprintf(s->data, 9, "k%d", i);
282 #else
283         key = (map_key_t)i;
284 #endif
285         ASSERT_EQUAL( DOES_NOT_EXIST, map_get(map, key)    );
286         ASSERT_EQUAL( DOES_NOT_EXIST, map_set(map, key, i) );
287         ASSERT_EQUAL( i,              map_get(map, key)    );
288         rcu_update(); // In a quiecent state.
289     }
290
291     ASSERT_EQUAL( n, map_count(map) );
292     ASSERT_EQUAL( n, iterator_size(map) );
293
294     uint64_t sum = 0;
295     map_val_t val;
296     map_iter_t *iter = map_iter_begin(map, 0);
297     while ((val = map_iter_next(iter, NULL)) != DOES_NOT_EXIST) {
298         sum += val;
299     }
300     map_iter_free(iter);
301     ASSERT_EQUAL(n*(n+1)/2, sum);
302     ASSERT_EQUAL(3, map_remove(map, k3));
303     ASSERT_EQUAL(4, map_remove(map, k4));
304     sum = 0;
305     iter = map_iter_begin(map, 0);
306     while ((val = map_iter_next(iter, NULL)) != DOES_NOT_EXIST) {
307         sum += val;
308     }
309     map_iter_free(iter);
310     ASSERT_EQUAL(n*(n+1)/2 - (3+4), sum);
311         
312 #ifdef TEST_STRING_KEYS
313     nbd_free(s);
314 #endif
315 }
316
317 int main (void) {
318
319     nbd_init();
320     lwt_set_trace_level("h3");
321
322     static const map_impl_t *map_types[] = { &ll_map_impl, &sl_map_impl, &ht_map_impl };
323     for (int i = 0; i < sizeof(map_types)/sizeof(*map_types); ++i) {
324         map_type_ = map_types[i];
325
326         // Create and run test suite
327         CuString *output = CuStringNew();
328         CuSuite* suite = CuSuiteNew();
329
330         SUITE_ADD_TEST(suite, basic_test);
331         SUITE_ADD_TEST(suite, basic_iteration_test);
332         SUITE_ADD_TEST(suite, big_iteration_test);
333         SUITE_ADD_TEST(suite, concurrent_add_remove_test);
334
335         CuSuiteRun(suite);
336         CuSuiteDetails(suite, output);
337         printf("%s\n", output->buffer);
338     }
339
340     return 0;
341 }