use generic map interface in tests
[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 #include <stdio.h>
6 #include <pthread.h>
7 #include "runtime.h"
8 #include "CuTest.h"
9 #include "common.h"
10 #include "map.h"
11 #include "mem.h"
12 #include "lwt.h"
13
14 #define ASSERT_EQUAL(x, y) CuAssertIntEquals(tc, x, y)
15
16 typedef struct worker_data {
17     int id;
18     CuTest *tc;
19     map_t *ht;
20     int *wait;
21 } worker_data_t;
22
23 static map_type_t map_type_;
24
25 // Test some basic stuff; add a few keys, remove a few keys
26 void basic_test (CuTest* tc) {
27
28     map_t *ht = map_alloc(map_type_);
29
30     ASSERT_EQUAL( 0,              map_count(ht)            );
31     ASSERT_EQUAL( DOES_NOT_EXIST, map_add(ht,"a",2,10)     );
32     ASSERT_EQUAL( 1,              map_count(ht)            );
33     ASSERT_EQUAL( DOES_NOT_EXIST, map_add(ht,"b",2,20)     );
34     ASSERT_EQUAL( 2,              map_count(ht)            );
35     ASSERT_EQUAL( 20,             map_get(ht,"b",2)        );
36     ASSERT_EQUAL( 10,             map_set(ht,"a",2,11)     );
37     ASSERT_EQUAL( 20,             map_set(ht,"b",2,21)     );
38     ASSERT_EQUAL( 2,              map_count(ht)            );
39     ASSERT_EQUAL( 21,             map_add(ht,"b",2,22)     );
40     ASSERT_EQUAL( 11,             map_remove(ht,"a",2)     );
41     ASSERT_EQUAL( DOES_NOT_EXIST, map_get(ht,"a",2)        );
42     ASSERT_EQUAL( 1,              map_count(ht)            );
43     ASSERT_EQUAL( DOES_NOT_EXIST, map_remove(ht,"a",2)     );
44     ASSERT_EQUAL( 21,             map_remove(ht,"b",2)     );
45     ASSERT_EQUAL( 0,              map_count(ht)            );
46     ASSERT_EQUAL( DOES_NOT_EXIST, map_remove(ht,"b",2)     );
47     ASSERT_EQUAL( DOES_NOT_EXIST, map_remove(ht,"c",2)     );
48     ASSERT_EQUAL( 0,              map_count(ht)            );
49     
50     ASSERT_EQUAL( DOES_NOT_EXIST, map_add(ht,"d",2,40)     );
51     ASSERT_EQUAL( 40,             map_get(ht,"d",2)        );
52     ASSERT_EQUAL( 1,              map_count(ht)            );
53     ASSERT_EQUAL( 40,             map_remove(ht,"d",2)     );
54     ASSERT_EQUAL( DOES_NOT_EXIST, map_get(ht,"d",2)        );
55     ASSERT_EQUAL( 0,              map_count(ht)            );
56
57     ASSERT_EQUAL( DOES_NOT_EXIST, map_replace(ht,"d",2,10) );
58     ASSERT_EQUAL( DOES_NOT_EXIST, map_get(ht,"d",2)        );
59     ASSERT_EQUAL( DOES_NOT_EXIST, map_set(ht,"d",2,40)     );
60     ASSERT_EQUAL( 40,             map_replace(ht,"d",2,41) );
61     ASSERT_EQUAL( 41,             map_get(ht,"d",2)        );
62     ASSERT_EQUAL( 41,             map_remove(ht,"d",2)     );
63     ASSERT_EQUAL( DOES_NOT_EXIST, map_get(ht,"d",2)        );
64     ASSERT_EQUAL( 0,              map_count(ht)            );
65
66     ASSERT_EQUAL( DOES_NOT_EXIST, map_replace(ht,"b",2,20) );
67     ASSERT_EQUAL( DOES_NOT_EXIST, map_get(ht,"b",2)        );
68
69     // In the end, all entries should be removed
70     ASSERT_EQUAL( DOES_NOT_EXIST, map_set(ht,"b",2,20)     );
71     ASSERT_EQUAL( 20,             map_replace(ht,"b",2,21) );
72     ASSERT_EQUAL( 21,             map_get(ht,"b",2)        );
73     ASSERT_EQUAL( 21,             map_remove(ht,"b",2)     );
74     ASSERT_EQUAL( DOES_NOT_EXIST, map_get(ht,"b",2)        );
75     ASSERT_EQUAL( 0,              map_count(ht)            );
76
77     map_free(ht);
78
79     // In a quiecent state; it is safe to free.
80     rcu_update();
81 }
82
83 void *simple_worker (void *arg) {
84     worker_data_t *wd = (worker_data_t *)arg;
85     map_t *ht = wd->ht;
86     CuTest* tc = wd->tc;
87     uint64_t d = wd->id;
88     int iters = map_type_ == MAP_TYPE_LIST ? 100 : 1000000;
89
90     SYNC_ADD(wd->wait, -1);
91     do { } while (*((volatile worker_data_t *)wd)->wait); // wait for all workers to be ready
92
93     for (int j = 0; j < 10; ++j) {
94         for (int i = d; i < iters; i+=2) {
95             char key[10];
96             sprintf(key, "k%u", i); 
97             TRACE("t0", "test map_add() iteration (%llu, %llu)", j, i);
98             CuAssertIntEquals_Msg(tc, key, DOES_NOT_EXIST, map_add(ht, key, strlen(key)+1, d+1) );
99             rcu_update();
100         }
101         for (int i = d; i < iters; i+=2) {
102             char key[10];
103             sprintf(key, "k%u", i); 
104             TRACE("t0", "test map_remove() iteration (%llu, %llu)", j, i);
105             CuAssertIntEquals_Msg(tc, key, d+1, map_remove(ht, key, strlen(key)+1) );
106             rcu_update();
107         }
108     }
109     return NULL;
110 }
111
112 // Do some simple concurrent testing
113 void simple_add_remove (CuTest* tc) {
114
115     pthread_t thread[2];
116     worker_data_t wd[2];
117     int wait = 2;
118     map_t *ht = map_alloc(map_type_);
119
120     // In 2 threads, add & remove even & odd elements concurrently
121     int i;
122     for (i = 0; i < 2; ++i) {
123         wd[i].id = i;
124         wd[i].tc = tc;
125         wd[i].ht = ht;
126         wd[i].wait = &wait;
127         int rc = nbd_thread_create(thread + i, i, simple_worker, wd + i);
128         if (rc != 0) { perror("nbd_thread_create"); return; }
129     }
130     for (i = 0; i < 2; ++i) {
131         pthread_join(thread[i], NULL);
132     }
133
134     // In the end, all members should be removed
135     ASSERT_EQUAL( 0, map_count(ht) );
136
137     // In a quiecent state; it is safe to free.
138     map_free(ht);
139 }
140
141
142 void *inserter_worker (void *arg) {
143     //pthread_t thread[NUM_THREADS];
144
145     //map_t *ht = map_alloc(MAP_TYPE_HASHTABLE);
146     return NULL;
147 }
148
149 // Concurrent insertion
150 void concurrent_insert (CuTest* tc) {
151 }
152
153 int main (void) {
154
155     nbd_init();
156     //lwt_set_trace_level("h0");
157
158     map_type_t map_types[] = { MAP_TYPE_LIST, MAP_TYPE_SKIPLIST, MAP_TYPE_HASHTABLE };
159     for (int i = 0; i < sizeof(map_types)/sizeof(*map_types); ++i) {
160         map_type_ = map_types[i];
161
162         // Create and run test suite
163         CuString *output = CuStringNew();
164         CuSuite* suite = CuSuiteNew();
165
166         SUITE_ADD_TEST(suite, basic_test);
167         SUITE_ADD_TEST(suite, simple_add_remove);
168
169         CuSuiteRun(suite);
170         CuSuiteSummary(suite, output);
171         CuSuiteDetails(suite, output);
172         printf("%s\n", output->buffer);
173     }
174
175     return 0;
176 }