1 #include <stdio.h>
2 #include <string.h>
3 #include <sys/time.h>
4 #include <unistd.h>
5 
6 #include "../cyrusdb.h"
7 #include "../xmalloc.h"
8 #include "../assert.h"
9 
10 #ifdef BACKEND
11 struct cyrusdb_backend *DB = &(BACKEND);
12 #else
13 struct cyrusdb_backend *DB = &cyrusdb_skiplist;
14 #endif
15 
16 #define TRY(s) do { \
17     r = s; \
18     if (r && r != CYRUSDB_NOTFOUND) { \
19         printf("%s failed (i=%d): %d\n", #s, i, r); \
20         exit(1); \
21     } \
22 } while (0)
23 
24 char *victim;
25 int count;
26 int verbose = 0;
27 
28 struct timeval t_add = { 0, 0 };
29 struct timeval t_mod = { 0, 0 };
30 struct timeval t_del = { 0, 0 };
31 struct timeval t_find = { 0, 0 };
32 
33 int c_add = 0;
34 int c_mod = 0;
35 int c_del = 0;
36 int c_find = 0;
37 
38 
39 #define ADDDIFF(a, b, c) do { a.tv_sec += (c.tv_sec - b.tv_sec); \
40                               a.tv_usec += (c.tv_usec - b.tv_usec); \
41                               while (a.tv_usec < 0) \
42                                 { a.tv_sec--; a.tv_usec += 1000000; } \
43                               while (a.tv_usec > 1000000) \
44                                 { a.tv_sec++; a.tv_usec -= 1000000; } } while (0)
45 
countem(void * rock,const char * key,int keylen,const char * data,int datalen)46 int countem(void *rock,
47         const char *key, int keylen,
48         const char *data, int datalen)
49 {
50     (void)rock; (void)key; (void)keylen; (void)data; (void)datalen;
51     count++;
52     return 0;
53 }
54 
findvictim(void * rock,const char * key,int keylen,const char * data,int datalen)55 int findvictim(void *rock,
56                const char *key, int keylen,
57                const char *data, int datalen)
58 {
59     (void)rock; (void)keylen; (void)data; (void)datalen;
60     if (!victim) {
61         if ((rand() % count) == 0) {
62             victim = xstrdup(key);
63         }
64     }
65     count--;
66     return 0;
67 }
68 
genrand(int len)69 char *genrand(int len)
70 {
71     char *ret = xmalloc(len + 1);
72     char *p = ret;
73 
74     while (len--) {
75         *p++ = 'a' + (rand() % 26);
76     }
77     *p = '\0';
78 
79     return ret;
80 }
81 
fatal(const char * msg,int code)82 void fatal(const char *msg, int code)
83 {
84     printf("fatal: %s\n", msg);
85     exit(code);
86 }
87 
do_report(void)88 void do_report(void)
89 {
90         printf("\n");
91     printf("*** add %ld.%ld %d\n", t_add.tv_sec, t_add.tv_usec, c_add);
92     printf("*** mod %ld.%ld %d\n", t_mod.tv_sec, t_mod.tv_usec, c_mod);
93     printf("*** del %ld.%ld %d\n", t_del.tv_sec, t_del.tv_usec, c_del);
94     printf("*** find %ld.%ld %d\n", t_find.tv_sec, t_find.tv_usec, c_find);
95 
96     printf("\n");
97     printf("*** add %lf\n", ((double) t_add.tv_sec +
98                              ((double) t_add.tv_usec) / 1000000) /
99            (double) c_add);
100     printf("*** mod %lf\n", ((double) t_mod.tv_sec +
101                              ((double) t_mod.tv_usec) / 1000000) /
102            (double) c_mod);
103     printf("*** del %lf\n", ((double) t_del.tv_sec +
104                              ((double) t_del.tv_usec) / 1000000) /
105            (double) c_del);
106     printf("*** find %lf\n", ((double) t_find.tv_sec +
107                              ((double) t_find.tv_usec) / 1000000) /
108            (double) c_find);
109 
110 
111 }
112 
main(int argc,char * argv[])113 int main(int argc, char *argv[])
114 {
115     int iter;
116     int seed;
117     int i;
118     char *key;
119     char *val;
120     struct db *db;
121     int r;
122     struct txn *txn;
123     const char *data;
124     int datalen;
125     struct timeval t1, t2;
126     int initsize;
127 
128     if (argc > 1) {
129         iter = atoi(argv[1]);
130     } else {
131       printf("%s [iterations] [rndseed] [initsize]\n", argv[0]);
132       printf("if iterations is negative, run forever and report every -iter\n");
133       exit(1);
134     }
135     TRY(DB->init(".", 0));
136 
137     if (argc > 2) {
138         srand(atoi(argv[2]));
139     }
140 
141     TRY(cyrusdb_open(DB, "scratch", &db));
142 
143     if (cyrusdb_consistent) {
144         TRY(cyrusdb_consistent(db));
145     }
146 
147     if (argc > 3) {
148       initsize = atoi(argv[3]);
149 
150       txn = NULL;
151       for (i = 0; i < initsize; i++) {
152         /* generate a random key */
153         key = genrand(10 + (rand() % 10));
154 
155         /* generate a random value */
156         val = genrand(10 + (rand() % 100));
157 
158         TRY(cyrusdb_store(db, key, strlen(key), val, strlen(val), &txn));
159       }
160 
161       TRY(cyrusdb_commit(db, txn));
162       if (cyrusdb_consistent) {
163         TRY(cyrusdb_consistent(db));
164       }
165     }
166 
167     printf("starting...\n");
168 
169     /* repeat for ever if iter < 0 */
170     for (i = 0; iter > 0 ? (i < iter) : 1; i++) {
171         int oper = rand() % 10;
172 
173         if (i > 0 && iter < 0 && ((i % -iter) == 0)) {
174           do_report();
175         }
176 
177         switch (oper) {
178         case 0:
179             /* do an ADD */
180 
181             if (verbose) printf("A");
182 
183             /* insert it */
184             gettimeofday(&t1, NULL);
185 
186             /* generate a random key */
187             key = genrand(10 + (rand() % 10));
188 
189             /* generate a random value */
190             val = genrand(10 + (rand() % 100));
191 
192             txn = NULL;
193             TRY(cyrusdb_store(db, key, strlen(key), val, strlen(val), &txn));
194             TRY(cyrusdb_commit(db, txn));
195             gettimeofday(&t2, NULL);
196 
197             ADDDIFF(t_add, t1, t2);
198             c_add++;
199 
200             free(key);
201             free(val);
202 
203             break;
204 
205         case 1: /* do a modify */
206             if (verbose) printf("M");
207 
208             gettimeofday(&t1, NULL);
209 
210             /* pick a random victim */
211             count = 0;
212             victim = NULL;
213             txn = NULL;
214             TRY(cyrusdb_foreach(db, NULL, 0, &countem, NULL, NULL, &txn));
215 
216             if (count == 0) continue;
217 
218             TRY(cyrusdb_foreach(db, NULL, 0, &findvictim, NULL, NULL, &txn));
219 
220             assert(victim != NULL);
221 
222             /* generate a random value */
223             val = genrand(10 + (rand() % 100));
224 
225             /* do an add */
226             TRY(cyrusdb_store(db, victim, strlen(victim), val, strlen(val), &txn));
227             free(val);
228 
229             TRY(cyrusdb_commit(db, txn));
230             free(victim); victim = NULL;
231 
232             gettimeofday(&t2, NULL);
233 
234             ADDDIFF(t_mod, t1, t2);
235             c_mod++;
236 
237             break;
238 
239         case 2: /* do a delete */
240             if (verbose) printf("D");
241 
242             gettimeofday(&t1, NULL);
243 
244             /* pick a random victim */
245             count = 0;
246             victim = NULL;
247             txn = NULL;
248             TRY(cyrusdb_foreach(db, NULL, 0, &countem, NULL, NULL, &txn));
249 
250             if (count == 0) continue;
251 
252             TRY(cyrusdb_foreach(db, NULL, 0, &findvictim, NULL, NULL, &txn));
253             assert(victim != NULL);
254 
255             /* delete it */
256             TRY(cyrusdb_delete(db, victim, strlen(victim), &txn, 0));
257 
258             TRY(cyrusdb_commit(db, txn));
259             free(victim); victim = NULL;
260 
261             gettimeofday(&t2, NULL);
262 
263             ADDDIFF(t_del, t1, t2);
264             c_del++;
265 
266             break;
267 
268         default:
269             /* do a "read" */
270             if (verbose) printf("R");
271 
272             gettimeofday(&t1, NULL);
273 
274             /* generate a random key */
275             key = genrand(10 + (rand() % 10));
276 
277             txn = NULL;
278             TRY(cyrusdb_fetch(db, key, strlen(key), &data, &datalen, &txn));
279             TRY(cyrusdb_commit(db, txn));
280 
281             gettimeofday(&t2, NULL);
282 
283             ADDDIFF(t_find, t1, t2);
284             c_find++;
285 
286             free(key);
287         }
288 
289         fflush(stdout);
290 
291 #if 0
292         /* run the consistency function, if any */
293         if (cyrusdb_consistent) {
294             TRY(cyrusdb_consistent(db));
295         }
296 #endif
297     }
298 
299     TRY(cyrusdb_close(db));
300     TRY(DB->done());
301 
302     do_report();
303     return 0;
304 }
305