]> pd.if.org Git - nbds/blob - test/map_test2.c
52438ea763364f5384b86aaf189cf0d87d6ff005
[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 #include "rcu.h"
24
25 #define ASSERT_EQUAL(x, y) CuAssertIntEquals(tc, x, y)
26
27 //#define TEST_STRING_KEYS
28
29 typedef struct worker_data {
30     int id;
31     CuTest *tc;
32     map_t *map;
33     volatile int *wait;
34 } worker_data_t;
35
36 static const map_impl_t *map_type_;
37
38 static size_t iterator_size (map_t *map) {
39     map_iter_t *iter = map_iter_begin(map, 0);
40     size_t count = 0;
41     while (map_iter_next(iter, NULL) != DOES_NOT_EXIST) {
42         count++;
43     }
44     map_iter_free(iter);
45     return count;
46 }
47
48 // Test some basic stuff; add a few keys, remove a few keys
49 void basic_test (CuTest* tc) {
50
51 #ifdef TEST_STRING_KEYS
52     map_t *map = map_alloc(map_type_, &DATATYPE_NSTRING);
53     nstring_t *s1 = ns_alloc(3); strcpy(s1->data, "k1");
54     nstring_t *s2 = ns_alloc(3); strcpy(s2->data, "k2");
55     nstring_t *s3 = ns_alloc(3); strcpy(s3->data, "k3");
56     nstring_t *s4 = ns_alloc(3); strcpy(s4->data, "k4");
57     map_key_t k1 = (map_key_t)s1;
58     map_key_t k2 = (map_key_t)s2;
59     map_key_t k3 = (map_key_t)s3;
60     map_key_t k4 = (map_key_t)s4;
61 #else
62     map_t *map = map_alloc(map_type_, NULL);
63     map_key_t k1 = (map_key_t)1;
64     map_key_t k2 = (map_key_t)2;
65     map_key_t k3 = (map_key_t)3;
66     map_key_t k4 = (map_key_t)4;
67 #endif
68
69     ASSERT_EQUAL( 0,              map_count  (map)        );
70     ASSERT_EQUAL( DOES_NOT_EXIST, map_add    (map, k1,10) );
71     ASSERT_EQUAL( 1,              map_count  (map)        );
72     ASSERT_EQUAL( 1,              iterator_size(map)      );
73     ASSERT_EQUAL( DOES_NOT_EXIST, map_add    (map, k2,20) );
74     ASSERT_EQUAL( 2,              map_count  (map)        );
75     ASSERT_EQUAL( 2,              iterator_size(map)      );
76     ASSERT_EQUAL( 20,             map_get    (map, k2)    );
77     ASSERT_EQUAL( 10,             map_set    (map, k1,11) );
78     ASSERT_EQUAL( 20,             map_set    (map, k2,21) );
79     ASSERT_EQUAL( 2,              map_count  (map)        );
80     ASSERT_EQUAL( 2,              iterator_size(map)      );
81     ASSERT_EQUAL( 21,             map_add    (map, k2,22) );
82     ASSERT_EQUAL( 11,             map_remove (map, k1)    );
83     ASSERT_EQUAL( DOES_NOT_EXIST, map_get    (map, k1)    );
84     ASSERT_EQUAL( 1,              map_count  (map)        );
85     ASSERT_EQUAL( 1,              iterator_size(map)      );
86     ASSERT_EQUAL( DOES_NOT_EXIST, map_remove (map, k1)    );
87     ASSERT_EQUAL( 21,             map_remove (map, k2)    );
88     ASSERT_EQUAL( 0,              map_count  (map)        );
89     ASSERT_EQUAL( 0,              iterator_size(map)      );
90     ASSERT_EQUAL( DOES_NOT_EXIST, map_remove (map, k2)    );
91     ASSERT_EQUAL( DOES_NOT_EXIST, map_remove (map, k3)    );
92     ASSERT_EQUAL( 0,              map_count  (map)        );
93     ASSERT_EQUAL( 0,              iterator_size(map)      );
94     
95     ASSERT_EQUAL( DOES_NOT_EXIST, map_add    (map, k4,40) );
96     ASSERT_EQUAL( 40,             map_get    (map, k4)    );
97     ASSERT_EQUAL( 1,              map_count  (map)        );
98     ASSERT_EQUAL( 1,              iterator_size(map)      );
99     ASSERT_EQUAL( 40,             map_remove (map, k4)    );
100     ASSERT_EQUAL( DOES_NOT_EXIST, map_get    (map, k4)    );
101     ASSERT_EQUAL( 0,              map_count  (map)        );
102     ASSERT_EQUAL( 0,              iterator_size(map)      );
103
104     ASSERT_EQUAL( DOES_NOT_EXIST, map_replace(map, k4,10) );
105     ASSERT_EQUAL( DOES_NOT_EXIST, map_get    (map, k4)    );
106     ASSERT_EQUAL( DOES_NOT_EXIST, map_set    (map, k4,40) );
107     ASSERT_EQUAL( 40,             map_replace(map, k4,41) );
108     ASSERT_EQUAL( 41,             map_get    (map, k4)    );
109     ASSERT_EQUAL( 41,             map_remove (map, k4)    );
110     ASSERT_EQUAL( DOES_NOT_EXIST, map_get    (map, k4)    );
111     ASSERT_EQUAL( 0,              map_count  (map)        );
112     ASSERT_EQUAL( 0,              iterator_size(map)      );
113
114     ASSERT_EQUAL( DOES_NOT_EXIST, map_replace(map, k2,20) );
115     ASSERT_EQUAL( DOES_NOT_EXIST, map_get    (map, k2)    );
116
117     // In the end, all entries should be removed
118     ASSERT_EQUAL( DOES_NOT_EXIST, map_set    (map, k2,20) );
119     ASSERT_EQUAL( 20,             map_replace(map, k2,21) );
120     ASSERT_EQUAL( 21,             map_get    (map, k2)    );
121     ASSERT_EQUAL( 21,             map_remove (map, k2)    );
122     ASSERT_EQUAL( DOES_NOT_EXIST, map_get    (map, k2)    );
123     ASSERT_EQUAL( 0,              map_count  (map)        );
124     ASSERT_EQUAL( 0,              iterator_size(map)      );
125
126     map_free(map);
127
128     rcu_update(); // In a quiecent state.
129 #ifdef TEST_STRING_KEYS
130     nbd_free(s1); nbd_free(s2); nbd_free(s3); nbd_free(s4);
131 #endif
132 }
133
134 void *add_remove_worker (void *arg) {
135     worker_data_t *wd = (worker_data_t *)arg;
136     map_t *map = wd->map;
137     CuTest* tc = wd->tc;
138     int d = wd->id;
139     int iters = (map_type_ == &MAP_IMPL_LL ? 10000 : 100000);
140
141     (void)SYNC_ADD(wd->wait, -1);
142     do { } while (*wd->wait); // wait for all workers to be ready
143
144     map_key_t key;
145 #ifdef TEST_STRING_KEYS
146     nstring_t *s = ns_alloc(9);
147     key = (map_key_t)s;
148 #endif
149
150     for (int j = 0; j < 10; ++j) {
151         for (int i = d+1; i < iters; i+=2) {
152 #ifdef TEST_STRING_KEYS
153             s->len = 1 + snprintf(s->data, 9, "%u", i);
154 #else
155             key = (map_key_t)i;
156 #endif
157             TRACE("t0", "test map_add() iteration (%llu, %llu)", j, i);
158             ASSERT_EQUAL(DOES_NOT_EXIST, map_add(map, key, d+1) );
159             rcu_update(); // In a quiecent state.
160         }
161         for (int i = d+1; i < iters; i+=2) {
162 #ifdef TEST_STRING_KEYS
163             s->len = 1 + snprintf(s->data, 9, "%u", i);
164 #else
165             key = (map_key_t)i;
166 #endif
167             TRACE("t0", "test map_remove() iteration (%llu, %llu)", j, i);
168             ASSERT_EQUAL(d+1, map_remove(map, key) );
169             rcu_update(); // In a quiecent state.
170         }
171     }
172 #ifdef TEST_STRING_KEYS
173     nbd_free(s);
174 #endif
175     return NULL;
176 }
177
178 // Do some simple concurrent testing
179 void concurrent_add_remove_test (CuTest* tc) {
180
181     pthread_t thread[2];
182     worker_data_t wd[2];
183     volatile int wait = 2;
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 < 2; ++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 < 2; ++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("Time:%dms\n", 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     lwt_set_trace_level("r0m3l2t0");
319
320     static const map_impl_t *map_types[] = { &MAP_IMPL_LL, &MAP_IMPL_SL, &MAP_IMPL_HT };
321     for (int i = 0; i < sizeof(map_types)/sizeof(*map_types); ++i) {
322         map_type_ = map_types[i];
323
324         // Create and run test suite
325         CuString *output = CuStringNew();
326         CuSuite* suite = CuSuiteNew();
327
328         SUITE_ADD_TEST(suite, concurrent_add_remove_test);
329 //        SUITE_ADD_TEST(suite, basic_test);
330 //        SUITE_ADD_TEST(suite, basic_iteration_test);
331 //        SUITE_ADD_TEST(suite, big_iteration_test);
332
333         CuSuiteRun(suite);
334         CuSuiteDetails(suite, output);
335         printf("%s\n", output->buffer);
336     }
337
338     return 0;
339 }