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