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