]> pd.if.org Git - nbds/blob - test/map_test2.c
port to Ubuntu 8.10 x86-64 w/ gcc 4.3.2
[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 = 10000;
140
141     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     static const int num_threads = 2;
184     volatile int wait = num_threads;
185 #ifdef TEST_STRING_KEYS
186     map_t *map = map_alloc(map_type_, &DATATYPE_NSTRING);
187 #else
188     map_t *map = map_alloc(map_type_, NULL);
189 #endif
190
191     struct timeval tv1, tv2;
192     gettimeofday(&tv1, NULL);
193
194     // In 2 threads, add & remove even & odd elements concurrently
195     int i;
196     for (i = 0; i < num_threads; ++i) {
197         wd[i].id = i;
198         wd[i].tc = tc;
199         wd[i].map = map;
200         wd[i].wait = &wait;
201         int rc = nbd_thread_create(thread + i, i, add_remove_worker, wd + i);
202         if (rc != 0) { perror("nbd_thread_create"); return; }
203     }
204
205     for (i = 0; i < num_threads; ++i) {
206         pthread_join(thread[i], NULL);
207     }
208
209     gettimeofday(&tv2, NULL);
210     int ms = (int)(1000000*(tv2.tv_sec - tv1.tv_sec) + tv2.tv_usec - tv1.tv_usec) / 1000;
211     map_print(map);
212     printf("Th:%d Time:%dms\n", num_threads, ms);
213     fflush(stdout);
214
215     // In the end, all members should be removed
216     ASSERT_EQUAL( 0, map_count(map) );
217     ASSERT_EQUAL( 0, iterator_size(map) );
218
219     // In a quiecent state; it is safe to free.
220     map_free(map);
221 }
222
223 void basic_iteration_test (CuTest* tc) {
224 #ifdef TEST_STRING_KEYS
225     map_t *map = map_alloc(map_type_, &DATATYPE_NSTRING);
226     nstring_t *s1 = ns_alloc(3); strcpy(s1->data, "k1");
227     nstring_t *s2 = ns_alloc(3); strcpy(s2->data, "k2");
228     map_key_t k1 = (map_key_t)s1;
229     map_key_t k2 = (map_key_t)s2;
230     nstring_t *x_k;
231     nstring_t *y_k;
232 #else
233     map_t *map = map_alloc(map_type_, NULL);
234     map_key_t k1 = (map_key_t)1;
235     map_key_t k2 = (map_key_t)2;
236     map_key_t x_k;
237     map_key_t y_k;
238 #endif
239
240     ASSERT_EQUAL( DOES_NOT_EXIST, map_add    (map, k1,1) );
241     ASSERT_EQUAL( DOES_NOT_EXIST, map_add    (map, k2,2) );
242
243     map_val_t x_v, y_v;
244     map_iter_t *iter = map_iter_begin(map, 0);
245     x_v = map_iter_next(iter, (map_key_t *)&x_k);
246     y_v = map_iter_next(iter, (map_key_t *)&y_k);
247     ASSERT_EQUAL( DOES_NOT_EXIST, map_iter_next(iter, NULL) );
248     map_iter_free(iter);
249 #ifdef TEST_STRING_KEYS
250     ASSERT_EQUAL( TRUE, (ns_cmp(x_k, s1) == 0 && x_v == 1) || (ns_cmp(y_k, s1) == 0 && y_v == 1) );
251     ASSERT_EQUAL( TRUE, (ns_cmp(x_k, s2) == 0 && x_v == 2) || (ns_cmp(y_k, s2) == 0 && y_v == 2) );
252     nbd_free(s1);
253     nbd_free(s2);
254 #else
255     ASSERT_EQUAL( TRUE, (x_k == k1 && x_v == 1) || (y_k == k1 && y_v == 1) );
256     ASSERT_EQUAL( TRUE, (x_k == k2 && x_v == 2) || (y_k == k2 && y_v == 2) );
257 #endif
258
259     map_free(map);
260 }
261
262 void big_iteration_test (CuTest* tc) {
263     static const int n = 10000;
264     
265 #ifdef TEST_STRING_KEYS
266     map_t *map = map_alloc(map_type_, &DATATYPE_NSTRING);
267     nstring_t *s = ns_alloc(9);
268     nstring_t *s3 = ns_alloc(3); strcpy(s3->data, "k3");
269     nstring_t *s4 = ns_alloc(3); strcpy(s4->data, "k4");
270     map_key_t k3 = (map_key_t)s3;
271     map_key_t k4 = (map_key_t)s4;
272     map_key_t key = (map_key_t)s;
273 #else
274     map_t *map = map_alloc(map_type_, NULL);
275     map_key_t k3 = (map_key_t)3;
276     map_key_t k4 = (map_key_t)4;
277     map_key_t key;
278 #endif
279
280     for (int i = 1; i <= n; ++i) {
281 #ifdef TEST_STRING_KEYS
282         s->len = 1 + snprintf(s->data, 9, "k%d", i);
283 #else
284         key = (map_key_t)i;
285 #endif
286         ASSERT_EQUAL( DOES_NOT_EXIST, map_get(map, key)    );
287         ASSERT_EQUAL( DOES_NOT_EXIST, map_set(map, key, i) );
288         ASSERT_EQUAL( i,              map_get(map, key)    );
289         rcu_update(); // In a quiecent state.
290     }
291
292     ASSERT_EQUAL( n, map_count(map) );
293     ASSERT_EQUAL( n, iterator_size(map) );
294
295     uint64_t sum = 0;
296     map_val_t val;
297     map_iter_t *iter = map_iter_begin(map, 0);
298     while ((val = map_iter_next(iter, NULL)) != DOES_NOT_EXIST) {
299         sum += val;
300     }
301     map_iter_free(iter);
302     ASSERT_EQUAL(n*(n+1)/2, sum);
303     ASSERT_EQUAL(3, map_remove(map, k3));
304     ASSERT_EQUAL(4, map_remove(map, k4));
305     sum = 0;
306     iter = map_iter_begin(map, 0);
307     while ((val = map_iter_next(iter, NULL)) != DOES_NOT_EXIST) {
308         sum += val;
309     }
310     map_iter_free(iter);
311     ASSERT_EQUAL(n*(n+1)/2 - (3+4), sum);
312         
313 #ifdef TEST_STRING_KEYS
314     nbd_free(s);
315 #endif
316 }
317
318 int main (void) {
319     lwt_set_trace_level("r0m3s3");
320
321     static const map_impl_t *map_types[] = { &ll_map_impl, &sl_map_impl, &ht_map_impl };
322     for (int i = 0; i < sizeof(map_types)/sizeof(*map_types); ++i) {
323         map_type_ = map_types[i];
324
325         // Create and run test suite
326         CuString *output = CuStringNew();
327         CuSuite* suite = CuSuiteNew();
328
329         SUITE_ADD_TEST(suite, concurrent_add_remove_test);
330         SUITE_ADD_TEST(suite, basic_test);
331         SUITE_ADD_TEST(suite, basic_iteration_test);
332         SUITE_ADD_TEST(suite, big_iteration_test);
333
334         CuSuiteRun(suite);
335         CuSuiteDetails(suite, output);
336         printf("%s\n", output->buffer);
337     }
338
339     return 0;
340 }