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