1 /*************************************************************************************************
2 * The test cases of the file tree database
3 * Copyright (C) 2009-2012 Mikio Hirabayashi
4 * This file is part of Kyoto Cabinet.
5 * This program is free software: you can redistribute it and/or modify it under the terms of
6 * the GNU General Public License as published by the Free Software Foundation, either version
7 * 3 of the License, or any later version.
8 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 * See the GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License along with this program.
12 * If not, see <http://www.gnu.org/licenses/>.
13 *************************************************************************************************/
14
15
16 #include <kchashdb.h>
17 #include "cmdcommon.h"
18
19
20 // global variables
21 const char* g_progname; // program name
22 uint32_t g_randseed; // random seed
23 int64_t g_memusage; // memory usage
24
25
26 // function prototypes
27 int main(int argc, char** argv);
28 static void usage();
29 static void dberrprint(kc::BasicDB* db, int32_t line, const char* func);
30 static void dbmetaprint(kc::BasicDB* db, bool verbose);
31 static int32_t runorder(int argc, char** argv);
32 static int32_t runqueue(int argc, char** argv);
33 static int32_t runwicked(int argc, char** argv);
34 static int32_t runtran(int argc, char** argv);
35 static int32_t procorder(const char* path, int64_t rnum, int32_t thnum, bool rnd, int32_t mode,
36 bool tran, int32_t oflags, int32_t apow, int32_t fpow,
37 int32_t opts, int64_t bnum, int32_t psiz, int64_t msiz,
38 int64_t dfunit, int64_t pccap, kc::Comparator* rcomp, bool lv);
39 static int32_t procqueue(const char* path, int64_t rnum, int32_t thnum, int32_t itnum, bool rnd,
40 int32_t oflags, int32_t apow, int32_t fpow, int32_t opts, int64_t bnum,
41 int32_t psiz, int64_t msiz, int64_t dfunit, int64_t pccap,
42 kc::Comparator* rcomp, bool lv);
43 static int32_t procwicked(const char* path, int64_t rnum, int32_t thnum, int32_t itnum,
44 int32_t oflags, int32_t apow, int32_t fpow, int32_t opts, int64_t bnum,
45 int32_t psiz, int64_t msiz, int64_t dfunit, int64_t pccap,
46 kc::Comparator* rcomp, bool lv);
47 static int32_t proctran(const char* path, int64_t rnum, int32_t thnum, int32_t itnum, bool hard,
48 int32_t oflags, int32_t apow, int32_t fpow, int32_t opts, int64_t bnum,
49 int32_t psiz, int64_t msiz, int64_t dfunit, int64_t pccap,
50 kc::Comparator* rcomp, bool lv);
51
52
53 // main routine
main(int argc,char ** argv)54 int main(int argc, char** argv) {
55 g_progname = argv[0];
56 const char* ebuf = kc::getenv("KCRNDSEED");
57 g_randseed = ebuf ? (uint32_t)kc::atoi(ebuf) : (uint32_t)(kc::time() * 1000);
58 mysrand(g_randseed);
59 g_memusage = memusage();
60 kc::setstdiobin();
61 if (argc < 2) usage();
62 int32_t rv = 0;
63 if (!std::strcmp(argv[1], "order")) {
64 rv = runorder(argc, argv);
65 } else if (!std::strcmp(argv[1], "queue")) {
66 rv = runqueue(argc, argv);
67 } else if (!std::strcmp(argv[1], "wicked")) {
68 rv = runwicked(argc, argv);
69 } else if (!std::strcmp(argv[1], "tran")) {
70 rv = runtran(argc, argv);
71 } else {
72 usage();
73 }
74 if (rv != 0) {
75 oprintf("FAILED: KCRNDSEED=%u PID=%ld", g_randseed, (long)kc::getpid());
76 for (int32_t i = 0; i < argc; i++) {
77 oprintf(" %s", argv[i]);
78 }
79 oprintf("\n\n");
80 }
81 return rv;
82 }
83
84
85 // print the usage and exit
usage()86 static void usage() {
87 eprintf("%s: test cases of the file tree database of Kyoto Cabinet\n", g_progname);
88 eprintf("\n");
89 eprintf("usage:\n");
90 eprintf(" %s order [-th num] [-rnd] [-set|-get|-getw|-rem|-etc] [-tran]"
91 " [-oat|-oas|-onl|-otl|-onr] [-apow num] [-fpow num] [-ts] [-tl] [-tc] [-bnum num]"
92 " [-psiz num] [-msiz num] [-dfunit num] [-pccap num] [-rcd|-rcld|-rcdd] [-lv]"
93 " path rnum\n", g_progname);
94 eprintf(" %s queue [-th num] [-it num] [-rnd] [-oat|-oas|-onl|-otl|-onr]"
95 " [-apow num] [-fpow num] [-ts] [-tl] [-tc] [-bnum num] [-psiz num] [-msiz num]"
96 " [-dfunit num] [-pccap num] [-rcd|-rcld|-rcdd] [-lv] path rnum\n", g_progname);
97 eprintf(" %s wicked [-th num] [-it num] [-oat|-oas|-onl|-otl|-onr]"
98 " [-apow num] [-fpow num] [-ts] [-tl] [-tc] [-bnum num] [-psiz num] [-msiz num]"
99 " [-dfunit num] [-pccap num] [-rcd|-rcld|-rcdd] [-lv] path rnum\n", g_progname);
100 eprintf(" %s tran [-th num] [-it num] [-hard] [-oat|-oas|-onl|-otl|-onr]"
101 " [-apow num] [-fpow num] [-ts] [-tl] [-tc] [-bnum num] [-psiz num] [-msiz num]"
102 " [-dfunit num] [-pccap num] [-rcd|-rcld|-rcdd] [-lv] path rnum\n", g_progname);
103 eprintf("\n");
104 std::exit(1);
105 }
106
107
108 // print the error message of a database
dberrprint(kc::BasicDB * db,int32_t line,const char * func)109 static void dberrprint(kc::BasicDB* db, int32_t line, const char* func) {
110 const kc::BasicDB::Error& err = db->error();
111 oprintf("%s: %d: %s: %s: %d: %s: %s\n",
112 g_progname, line, func, db->path().c_str(), err.code(), err.name(), err.message());
113 }
114
115
116 // print members of a database
dbmetaprint(kc::BasicDB * db,bool verbose)117 static void dbmetaprint(kc::BasicDB* db, bool verbose) {
118 if (verbose) {
119 std::map<std::string, std::string> status;
120 status["opaque"] = "";
121 status["fbpnum_used"] = "";
122 status["bnum_used"] = "";
123 status["cusage_lcnt"] = "";
124 status["cusage_lsiz"] = "";
125 status["cusage_icnt"] = "";
126 status["cusage_isiz"] = "";
127 status["tree_level"] = "";
128 if (db->status(&status)) {
129 uint32_t type = kc::atoi(status["type"].c_str());
130 oprintf("type: %s (%s) (type=0x%02X)\n",
131 kc::BasicDB::typecname(type), kc::BasicDB::typestring(type), type);
132 uint32_t chksum = kc::atoi(status["chksum"].c_str());
133 oprintf("format version: %s (libver=%s.%s) (chksum=0x%02X)\n", status["fmtver"].c_str(),
134 status["libver"].c_str(), status["librev"].c_str(), chksum);
135 oprintf("path: %s\n", status["path"].c_str());
136 int32_t flags = kc::atoi(status["flags"].c_str());
137 oprintf("status flags:");
138 if (flags & kc::TreeDB::FOPEN) oprintf(" open");
139 if (flags & kc::TreeDB::FFATAL) oprintf(" fatal");
140 oprintf(" (flags=%d)", flags);
141 if (kc::atoi(status["recovered"].c_str()) > 0) oprintf(" (recovered)");
142 if (kc::atoi(status["reorganized"].c_str()) > 0) oprintf(" (reorganized)");
143 if (kc::atoi(status["trimmed"].c_str()) > 0) oprintf(" (trimmed)");
144 oprintf("\n", flags);
145 int32_t apow = kc::atoi(status["apow"].c_str());
146 oprintf("alignment: %d (apow=%d)\n", 1 << apow, apow);
147 int32_t fpow = kc::atoi(status["fpow"].c_str());
148 int32_t fbpnum = fpow > 0 ? 1 << fpow : 0;
149 int32_t fbpused = kc::atoi(status["fbpnum_used"].c_str());
150 int64_t frgcnt = kc::atoi(status["frgcnt"].c_str());
151 oprintf("free block pool: %d (fpow=%d) (used=%d) (frg=%lld)\n",
152 fbpnum, fpow, fbpused, (long long)frgcnt);
153 int32_t opts = kc::atoi(status["opts"].c_str());
154 oprintf("options:");
155 if (opts & kc::TreeDB::TSMALL) oprintf(" small");
156 if (opts & kc::TreeDB::TLINEAR) oprintf(" linear");
157 if (opts & kc::TreeDB::TCOMPRESS) oprintf(" compress");
158 oprintf(" (opts=%d)\n", opts);
159 oprintf("comparator: %s\n", status["rcomp"].c_str());
160 if (status["opaque"].size() >= 16) {
161 const char* opaque = status["opaque"].c_str();
162 oprintf("opaque:");
163 if (std::count(opaque, opaque + 16, 0) != 16) {
164 for (int32_t i = 0; i < 16; i++) {
165 oprintf(" %02X", ((unsigned char*)opaque)[i]);
166 }
167 } else {
168 oprintf(" 0");
169 }
170 oprintf("\n");
171 }
172 int64_t bnum = kc::atoi(status["bnum"].c_str());
173 int64_t bnumused = kc::atoi(status["bnum_used"].c_str());
174 int64_t count = kc::atoi(status["count"].c_str());
175 int64_t pnum = kc::atoi(status["pnum"].c_str());
176 int64_t lcnt = kc::atoi(status["lcnt"].c_str());
177 int64_t icnt = kc::atoi(status["icnt"].c_str());
178 int32_t tlevel = kc::atoi(status["tree_level"].c_str());
179 int32_t psiz = kc::atoi(status["psiz"].c_str());
180 double load = 0;
181 if (pnum > 0 && bnumused > 0) {
182 load = (double)pnum / bnumused;
183 if (!(opts & kc::TreeDB::TLINEAR)) load = std::log(load + 1) / std::log(2.0);
184 }
185 oprintf("buckets: %lld (used=%lld) (load=%.2f)\n",
186 (long long)bnum, (long long)bnumused, load);
187 oprintf("pages: %lld (leaf=%lld) (inner=%lld) (level=%d) (psiz=%d)\n",
188 (long long)pnum, (long long)lcnt, (long long)icnt, tlevel, psiz);
189 int64_t pccap = kc::atoi(status["pccap"].c_str());
190 int64_t cusage = kc::atoi(status["cusage"].c_str());
191 int64_t culcnt = kc::atoi(status["cusage_lcnt"].c_str());
192 int64_t culsiz = kc::atoi(status["cusage_lsiz"].c_str());
193 int64_t cuicnt = kc::atoi(status["cusage_icnt"].c_str());
194 int64_t cuisiz = kc::atoi(status["cusage_isiz"].c_str());
195 oprintf("cache: %lld (cap=%lld) (ratio=%.2f) (leaf=%lld:%lld) (inner=%lld:%lld)\n",
196 (long long)cusage, (long long)pccap, (double)cusage / pccap,
197 (long long)culsiz, (long long)culcnt, (long long)cuisiz, (long long)cuicnt);
198 std::string cntstr = unitnumstr(count);
199 oprintf("count: %lld (%s)\n", count, cntstr.c_str());
200 int64_t size = kc::atoi(status["size"].c_str());
201 int64_t msiz = kc::atoi(status["msiz"].c_str());
202 int64_t realsize = kc::atoi(status["realsize"].c_str());
203 std::string sizestr = unitnumstrbyte(size);
204 oprintf("size: %lld (%s) (map=%lld)", size, sizestr.c_str(), (long long)msiz);
205 if (size != realsize) oprintf(" (gap=%lld)", (long long)(realsize - size));
206 oprintf("\n");
207 }
208 } else {
209 oprintf("count: %lld\n", (long long)db->count());
210 oprintf("size: %lld\n", (long long)db->size());
211 }
212 int64_t musage = memusage();
213 if (musage > 0) oprintf("memory: %lld\n", (long long)(musage - g_memusage));
214 }
215
216
217 // parse arguments of order command
runorder(int argc,char ** argv)218 static int32_t runorder(int argc, char** argv) {
219 bool argbrk = false;
220 const char* path = NULL;
221 const char* rstr = NULL;
222 int32_t thnum = 1;
223 bool rnd = false;
224 int32_t mode = 0;
225 bool tran = false;
226 int32_t oflags = 0;
227 int32_t apow = -1;
228 int32_t fpow = -1;
229 int32_t opts = 0;
230 int64_t bnum = -1;
231 int64_t psiz = -1;
232 int64_t msiz = -1;
233 int64_t dfunit = -1;
234 int64_t pccap = 0;
235 kc::Comparator* rcomp = NULL;
236 bool lv = false;
237 for (int32_t i = 2; i < argc; i++) {
238 if (!argbrk && argv[i][0] == '-') {
239 if (!std::strcmp(argv[i], "--")) {
240 argbrk = true;
241 } else if (!std::strcmp(argv[i], "-th")) {
242 if (++i >= argc) usage();
243 thnum = kc::atoix(argv[i]);
244 } else if (!std::strcmp(argv[i], "-rnd")) {
245 rnd = true;
246 } else if (!std::strcmp(argv[i], "-set")) {
247 mode = 's';
248 } else if (!std::strcmp(argv[i], "-get")) {
249 mode = 'g';
250 } else if (!std::strcmp(argv[i], "-getw")) {
251 mode = 'w';
252 } else if (!std::strcmp(argv[i], "-rem")) {
253 mode = 'r';
254 } else if (!std::strcmp(argv[i], "-etc")) {
255 mode = 'e';
256 } else if (!std::strcmp(argv[i], "-tran")) {
257 tran = true;
258 } else if (!std::strcmp(argv[i], "-oat")) {
259 oflags |= kc::TreeDB::OAUTOTRAN;
260 } else if (!std::strcmp(argv[i], "-oas")) {
261 oflags |= kc::TreeDB::OAUTOSYNC;
262 } else if (!std::strcmp(argv[i], "-onl")) {
263 oflags |= kc::TreeDB::ONOLOCK;
264 } else if (!std::strcmp(argv[i], "-otl")) {
265 oflags |= kc::TreeDB::OTRYLOCK;
266 } else if (!std::strcmp(argv[i], "-onr")) {
267 oflags |= kc::TreeDB::ONOREPAIR;
268 } else if (!std::strcmp(argv[i], "-apow")) {
269 if (++i >= argc) usage();
270 apow = kc::atoix(argv[i]);
271 } else if (!std::strcmp(argv[i], "-fpow")) {
272 if (++i >= argc) usage();
273 fpow = kc::atoix(argv[i]);
274 } else if (!std::strcmp(argv[i], "-ts")) {
275 opts |= kc::TreeDB::TSMALL;
276 } else if (!std::strcmp(argv[i], "-tl")) {
277 opts |= kc::TreeDB::TLINEAR;
278 } else if (!std::strcmp(argv[i], "-tc")) {
279 opts |= kc::TreeDB::TCOMPRESS;
280 } else if (!std::strcmp(argv[i], "-bnum")) {
281 if (++i >= argc) usage();
282 bnum = kc::atoix(argv[i]);
283 } else if (!std::strcmp(argv[i], "-psiz")) {
284 if (++i >= argc) usage();
285 psiz = kc::atoix(argv[i]);
286 } else if (!std::strcmp(argv[i], "-msiz")) {
287 if (++i >= argc) usage();
288 msiz = kc::atoix(argv[i]);
289 } else if (!std::strcmp(argv[i], "-dfunit")) {
290 if (++i >= argc) usage();
291 dfunit = kc::atoix(argv[i]);
292 } else if (!std::strcmp(argv[i], "-pccap")) {
293 if (++i >= argc) usage();
294 pccap = kc::atoix(argv[i]);
295 } else if (!std::strcmp(argv[i], "-rcd")) {
296 rcomp = kc::DECIMALCOMP;
297 } else if (!std::strcmp(argv[i], "-rcld")) {
298 rcomp = kc::LEXICALDESCCOMP;
299 } else if (!std::strcmp(argv[i], "-rcdd")) {
300 rcomp = kc::DECIMALDESCCOMP;
301 } else if (!std::strcmp(argv[i], "-lv")) {
302 lv = true;
303 } else {
304 usage();
305 }
306 } else if (!path) {
307 argbrk = true;
308 path = argv[i];
309 } else if (!rstr) {
310 rstr = argv[i];
311 } else {
312 usage();
313 }
314 }
315 if (!path || !rstr) usage();
316 int64_t rnum = kc::atoix(rstr);
317 if (rnum < 1 || thnum < 1) usage();
318 if (thnum > THREADMAX) thnum = THREADMAX;
319 int32_t rv = procorder(path, rnum, thnum, rnd, mode, tran, oflags,
320 apow, fpow, opts, bnum, psiz, msiz, dfunit, pccap, rcomp, lv);
321 return rv;
322 }
323
324
325 // parse arguments of queue command
runqueue(int argc,char ** argv)326 static int32_t runqueue(int argc, char** argv) {
327 bool argbrk = false;
328 const char* path = NULL;
329 const char* rstr = NULL;
330 int32_t thnum = 1;
331 int32_t itnum = 1;
332 bool rnd = false;
333 int32_t oflags = 0;
334 int32_t apow = -1;
335 int32_t fpow = -1;
336 int32_t opts = 0;
337 int64_t bnum = -1;
338 int64_t psiz = -1;
339 int64_t msiz = -1;
340 int64_t dfunit = -1;
341 int64_t pccap = 0;
342 kc::Comparator* rcomp = NULL;
343 bool lv = false;
344 for (int32_t i = 2; i < argc; i++) {
345 if (!argbrk && argv[i][0] == '-') {
346 if (!std::strcmp(argv[i], "--")) {
347 argbrk = true;
348 } else if (!std::strcmp(argv[i], "-th")) {
349 if (++i >= argc) usage();
350 thnum = kc::atoix(argv[i]);
351 } else if (!std::strcmp(argv[i], "-it")) {
352 if (++i >= argc) usage();
353 itnum = kc::atoix(argv[i]);
354 } else if (!std::strcmp(argv[i], "-rnd")) {
355 rnd = true;
356 } else if (!std::strcmp(argv[i], "-oat")) {
357 oflags |= kc::TreeDB::OAUTOTRAN;
358 } else if (!std::strcmp(argv[i], "-oas")) {
359 oflags |= kc::TreeDB::OAUTOSYNC;
360 } else if (!std::strcmp(argv[i], "-onl")) {
361 oflags |= kc::TreeDB::ONOLOCK;
362 } else if (!std::strcmp(argv[i], "-otl")) {
363 oflags |= kc::TreeDB::OTRYLOCK;
364 } else if (!std::strcmp(argv[i], "-onr")) {
365 oflags |= kc::TreeDB::ONOREPAIR;
366 } else if (!std::strcmp(argv[i], "-apow")) {
367 if (++i >= argc) usage();
368 apow = kc::atoix(argv[i]);
369 } else if (!std::strcmp(argv[i], "-fpow")) {
370 if (++i >= argc) usage();
371 fpow = kc::atoix(argv[i]);
372 } else if (!std::strcmp(argv[i], "-ts")) {
373 opts |= kc::TreeDB::TSMALL;
374 } else if (!std::strcmp(argv[i], "-tl")) {
375 opts |= kc::TreeDB::TLINEAR;
376 } else if (!std::strcmp(argv[i], "-tc")) {
377 opts |= kc::TreeDB::TCOMPRESS;
378 } else if (!std::strcmp(argv[i], "-bnum")) {
379 if (++i >= argc) usage();
380 bnum = kc::atoix(argv[i]);
381 } else if (!std::strcmp(argv[i], "-psiz")) {
382 if (++i >= argc) usage();
383 psiz = kc::atoix(argv[i]);
384 } else if (!std::strcmp(argv[i], "-msiz")) {
385 if (++i >= argc) usage();
386 msiz = kc::atoix(argv[i]);
387 } else if (!std::strcmp(argv[i], "-dfunit")) {
388 if (++i >= argc) usage();
389 dfunit = kc::atoix(argv[i]);
390 } else if (!std::strcmp(argv[i], "-pccap")) {
391 if (++i >= argc) usage();
392 pccap = kc::atoix(argv[i]);
393 } else if (!std::strcmp(argv[i], "-rcd")) {
394 rcomp = kc::DECIMALCOMP;
395 } else if (!std::strcmp(argv[i], "-rcld")) {
396 rcomp = kc::LEXICALDESCCOMP;
397 } else if (!std::strcmp(argv[i], "-rcdd")) {
398 rcomp = kc::DECIMALDESCCOMP;
399 } else if (!std::strcmp(argv[i], "-lv")) {
400 lv = true;
401 } else {
402 usage();
403 }
404 } else if (!path) {
405 argbrk = true;
406 path = argv[i];
407 } else if (!rstr) {
408 rstr = argv[i];
409 } else {
410 usage();
411 }
412 }
413 if (!path || !rstr) usage();
414 int64_t rnum = kc::atoix(rstr);
415 if (rnum < 1 || thnum < 1 || itnum < 1) usage();
416 if (thnum > THREADMAX) thnum = THREADMAX;
417 int32_t rv = procqueue(path, rnum, thnum, itnum, rnd, oflags,
418 apow, fpow, opts, bnum, psiz, msiz, dfunit, pccap, rcomp, lv);
419 return rv;
420 }
421
422
423 // parse arguments of wicked command
runwicked(int argc,char ** argv)424 static int32_t runwicked(int argc, char** argv) {
425 bool argbrk = false;
426 const char* path = NULL;
427 const char* rstr = NULL;
428 int32_t thnum = 1;
429 int32_t itnum = 1;
430 int32_t oflags = 0;
431 int32_t apow = -1;
432 int32_t fpow = -1;
433 int32_t opts = 0;
434 int64_t bnum = -1;
435 int64_t psiz = -1;
436 int64_t msiz = -1;
437 int64_t dfunit = -1;
438 int64_t pccap = 0;
439 kc::Comparator* rcomp = NULL;
440 bool lv = false;
441 for (int32_t i = 2; i < argc; i++) {
442 if (!argbrk && argv[i][0] == '-') {
443 if (!std::strcmp(argv[i], "--")) {
444 argbrk = true;
445 } else if (!std::strcmp(argv[i], "-th")) {
446 if (++i >= argc) usage();
447 thnum = kc::atoix(argv[i]);
448 } else if (!std::strcmp(argv[i], "-it")) {
449 if (++i >= argc) usage();
450 itnum = kc::atoix(argv[i]);
451 } else if (!std::strcmp(argv[i], "-oat")) {
452 oflags |= kc::TreeDB::OAUTOTRAN;
453 } else if (!std::strcmp(argv[i], "-oas")) {
454 oflags |= kc::TreeDB::OAUTOSYNC;
455 } else if (!std::strcmp(argv[i], "-onl")) {
456 oflags |= kc::TreeDB::ONOLOCK;
457 } else if (!std::strcmp(argv[i], "-otl")) {
458 oflags |= kc::TreeDB::OTRYLOCK;
459 } else if (!std::strcmp(argv[i], "-onr")) {
460 oflags |= kc::TreeDB::ONOREPAIR;
461 } else if (!std::strcmp(argv[i], "-apow")) {
462 if (++i >= argc) usage();
463 apow = kc::atoix(argv[i]);
464 } else if (!std::strcmp(argv[i], "-fpow")) {
465 if (++i >= argc) usage();
466 fpow = kc::atoix(argv[i]);
467 } else if (!std::strcmp(argv[i], "-ts")) {
468 opts |= kc::TreeDB::TSMALL;
469 } else if (!std::strcmp(argv[i], "-tl")) {
470 opts |= kc::TreeDB::TLINEAR;
471 } else if (!std::strcmp(argv[i], "-tc")) {
472 opts |= kc::TreeDB::TCOMPRESS;
473 } else if (!std::strcmp(argv[i], "-bnum")) {
474 if (++i >= argc) usage();
475 bnum = kc::atoix(argv[i]);
476 } else if (!std::strcmp(argv[i], "-psiz")) {
477 if (++i >= argc) usage();
478 psiz = kc::atoix(argv[i]);
479 } else if (!std::strcmp(argv[i], "-msiz")) {
480 if (++i >= argc) usage();
481 msiz = kc::atoix(argv[i]);
482 } else if (!std::strcmp(argv[i], "-dfunit")) {
483 if (++i >= argc) usage();
484 dfunit = kc::atoix(argv[i]);
485 } else if (!std::strcmp(argv[i], "-pccap")) {
486 if (++i >= argc) usage();
487 pccap = kc::atoix(argv[i]);
488 } else if (!std::strcmp(argv[i], "-rcd")) {
489 rcomp = kc::DECIMALCOMP;
490 } else if (!std::strcmp(argv[i], "-rcld")) {
491 rcomp = kc::LEXICALDESCCOMP;
492 } else if (!std::strcmp(argv[i], "-rcdd")) {
493 rcomp = kc::DECIMALDESCCOMP;
494 } else if (!std::strcmp(argv[i], "-lv")) {
495 lv = true;
496 } else {
497 usage();
498 }
499 } else if (!path) {
500 argbrk = true;
501 path = argv[i];
502 } else if (!rstr) {
503 rstr = argv[i];
504 } else {
505 usage();
506 }
507 }
508 if (!path || !rstr) usage();
509 int64_t rnum = kc::atoix(rstr);
510 if (rnum < 1 || thnum < 1 || itnum < 1) usage();
511 if (thnum > THREADMAX) thnum = THREADMAX;
512 int32_t rv = procwicked(path, rnum, thnum, itnum, oflags,
513 apow, fpow, opts, bnum, psiz, msiz, dfunit, pccap, rcomp, lv);
514 return rv;
515 }
516
517
518 // parse arguments of tran command
runtran(int argc,char ** argv)519 static int32_t runtran(int argc, char** argv) {
520 bool argbrk = false;
521 const char* path = NULL;
522 const char* rstr = NULL;
523 int32_t thnum = 1;
524 int32_t itnum = 1;
525 bool hard = false;
526 int32_t oflags = 0;
527 int32_t apow = -1;
528 int32_t fpow = -1;
529 int32_t opts = 0;
530 int64_t bnum = -1;
531 int64_t psiz = -1;
532 int64_t msiz = -1;
533 int64_t dfunit = -1;
534 int64_t pccap = 0;
535 kc::Comparator* rcomp = NULL;
536 bool lv = false;
537 for (int32_t i = 2; i < argc; i++) {
538 if (!argbrk && argv[i][0] == '-') {
539 if (!std::strcmp(argv[i], "--")) {
540 argbrk = true;
541 } else if (!std::strcmp(argv[i], "-th")) {
542 if (++i >= argc) usage();
543 thnum = kc::atoix(argv[i]);
544 } else if (!std::strcmp(argv[i], "-it")) {
545 if (++i >= argc) usage();
546 itnum = kc::atoix(argv[i]);
547 } else if (!std::strcmp(argv[i], "-hard")) {
548 hard = true;
549 } else if (!std::strcmp(argv[i], "-oat")) {
550 oflags |= kc::TreeDB::OAUTOTRAN;
551 } else if (!std::strcmp(argv[i], "-oas")) {
552 oflags |= kc::TreeDB::OAUTOSYNC;
553 } else if (!std::strcmp(argv[i], "-onl")) {
554 oflags |= kc::TreeDB::ONOLOCK;
555 } else if (!std::strcmp(argv[i], "-otl")) {
556 oflags |= kc::TreeDB::OTRYLOCK;
557 } else if (!std::strcmp(argv[i], "-onr")) {
558 oflags |= kc::TreeDB::ONOREPAIR;
559 } else if (!std::strcmp(argv[i], "-apow")) {
560 if (++i >= argc) usage();
561 apow = kc::atoix(argv[i]);
562 } else if (!std::strcmp(argv[i], "-fpow")) {
563 if (++i >= argc) usage();
564 fpow = kc::atoix(argv[i]);
565 } else if (!std::strcmp(argv[i], "-ts")) {
566 opts |= kc::TreeDB::TSMALL;
567 } else if (!std::strcmp(argv[i], "-tl")) {
568 opts |= kc::TreeDB::TLINEAR;
569 } else if (!std::strcmp(argv[i], "-tc")) {
570 opts |= kc::TreeDB::TCOMPRESS;
571 } else if (!std::strcmp(argv[i], "-bnum")) {
572 if (++i >= argc) usage();
573 bnum = kc::atoix(argv[i]);
574 } else if (!std::strcmp(argv[i], "-psiz")) {
575 if (++i >= argc) usage();
576 psiz = kc::atoix(argv[i]);
577 } else if (!std::strcmp(argv[i], "-msiz")) {
578 if (++i >= argc) usage();
579 msiz = kc::atoix(argv[i]);
580 } else if (!std::strcmp(argv[i], "-dfunit")) {
581 if (++i >= argc) usage();
582 dfunit = kc::atoix(argv[i]);
583 } else if (!std::strcmp(argv[i], "-pccap")) {
584 if (++i >= argc) usage();
585 pccap = kc::atoix(argv[i]);
586 } else if (!std::strcmp(argv[i], "-rcd")) {
587 rcomp = kc::DECIMALCOMP;
588 } else if (!std::strcmp(argv[i], "-rcld")) {
589 rcomp = kc::LEXICALDESCCOMP;
590 } else if (!std::strcmp(argv[i], "-rcdd")) {
591 rcomp = kc::DECIMALDESCCOMP;
592 } else if (!std::strcmp(argv[i], "-lv")) {
593 lv = true;
594 } else {
595 usage();
596 }
597 } else if (!path) {
598 argbrk = true;
599 path = argv[i];
600 } else if (!rstr) {
601 rstr = argv[i];
602 } else {
603 usage();
604 }
605 }
606 if (!path || !rstr) usage();
607 int64_t rnum = kc::atoix(rstr);
608 if (rnum < 1 || thnum < 1 || itnum < 1) usage();
609 if (thnum > THREADMAX) thnum = THREADMAX;
610 int32_t rv = proctran(path, rnum, thnum, itnum, hard, oflags,
611 apow, fpow, opts, bnum, psiz, msiz, dfunit, pccap, rcomp, lv);
612 return rv;
613 }
614
615
616 // perform order command
procorder(const char * path,int64_t rnum,int32_t thnum,bool rnd,int32_t mode,bool tran,int32_t oflags,int32_t apow,int32_t fpow,int32_t opts,int64_t bnum,int32_t psiz,int64_t msiz,int64_t dfunit,int64_t pccap,kc::Comparator * rcomp,bool lv)617 static int32_t procorder(const char* path, int64_t rnum, int32_t thnum, bool rnd, int32_t mode,
618 bool tran, int32_t oflags, int32_t apow, int32_t fpow,
619 int32_t opts, int64_t bnum, int32_t psiz, int64_t msiz,
620 int64_t dfunit, int64_t pccap, kc::Comparator* rcomp, bool lv) {
621 oprintf("<In-order Test>\n seed=%u path=%s rnum=%lld thnum=%d rnd=%d mode=%d tran=%d"
622 " oflags=%d apow=%d fpow=%d opts=%d bnum=%lld psiz=%d msiz=%lld"
623 " dfunit=%lld pccap=%lld rcomp=%p lv=%d\n\n",
624 g_randseed, path, (long long)rnum, thnum, rnd, mode, tran, oflags, apow, fpow, opts,
625 (long long)bnum, psiz, (long long)msiz, (long long)dfunit, (long long)pccap,
626 rcomp, lv);
627 bool err = false;
628 kc::TreeDB db;
629 oprintf("opening the database:\n");
630 double stime = kc::time();
631 db.tune_logger(stdlogger(g_progname, &std::cout),
632 lv ? kc::UINT32MAX : kc::BasicDB::Logger::WARN | kc::BasicDB::Logger::ERROR);
633 if (apow >= 0) db.tune_alignment(apow);
634 if (fpow >= 0) db.tune_fbp(fpow);
635 if (opts > 0) db.tune_options(opts);
636 if (bnum > 0) db.tune_buckets(bnum);
637 if (psiz > 0) db.tune_page(psiz);
638 if (msiz >= 0) db.tune_map(msiz);
639 if (dfunit > 0) db.tune_defrag(dfunit);
640 if (pccap > 0) db.tune_page_cache(pccap);
641 if (rcomp) db.tune_comparator(rcomp);
642 uint32_t omode = kc::TreeDB::OWRITER | kc::TreeDB::OCREATE | kc::TreeDB::OTRUNCATE;
643 if (mode == 'r') {
644 omode = kc::TreeDB::OWRITER | kc::TreeDB::OCREATE;
645 } else if (mode == 'g' || mode == 'w') {
646 omode = kc::TreeDB::OREADER;
647 }
648 if (!db.open(path, omode | oflags)) {
649 dberrprint(&db, __LINE__, "DB::open");
650 err = true;
651 }
652 double etime = kc::time();
653 dbmetaprint(&db, false);
654 oprintf("time: %.3f\n", etime - stime);
655 if (mode == 0 || mode == 's' || mode == 'e') {
656 oprintf("setting records:\n");
657 stime = kc::time();
658 class ThreadSet : public kc::Thread {
659 public:
660 void setparams(int32_t id, kc::BasicDB* db, int64_t rnum, int32_t thnum,
661 bool rnd, bool tran) {
662 id_ = id;
663 db_ = db;
664 rnum_ = rnum;
665 thnum_ = thnum;
666 err_ = false;
667 rnd_ = rnd;
668 tran_ = tran;
669 }
670 bool error() {
671 return err_;
672 }
673 void run() {
674 int64_t base = id_ * rnum_;
675 int64_t range = rnum_ * thnum_;
676 for (int64_t i = 1; !err_ && i <= rnum_; i++) {
677 if (tran_ && !db_->begin_transaction(false)) {
678 dberrprint(db_, __LINE__, "DB::begin_transaction");
679 err_ = true;
680 }
681 char kbuf[RECBUFSIZ];
682 size_t ksiz = std::sprintf(kbuf, "%08lld",
683 (long long)(rnd_ ? myrand(range) + 1 : base + i));
684 if (!db_->set(kbuf, ksiz, kbuf, ksiz)) {
685 dberrprint(db_, __LINE__, "DB::set");
686 err_ = true;
687 }
688 if (rnd_ && i % 8 == 0) {
689 switch (myrand(8)) {
690 case 0: {
691 if (!db_->set(kbuf, ksiz, kbuf, ksiz)) {
692 dberrprint(db_, __LINE__, "DB::set");
693 err_ = true;
694 }
695 break;
696 }
697 case 1: {
698 if (!db_->append(kbuf, ksiz, kbuf, ksiz)) {
699 dberrprint(db_, __LINE__, "DB::append");
700 err_ = true;
701 }
702 break;
703 }
704 case 2: {
705 if (!db_->remove(kbuf, ksiz) && db_->error() != kc::BasicDB::Error::NOREC) {
706 dberrprint(db_, __LINE__, "DB::remove");
707 err_ = true;
708 }
709 break;
710 }
711 case 3: {
712 kc::DB::Cursor* cur = db_->cursor();
713 if (cur->jump(kbuf, ksiz)) {
714 switch (myrand(8)) {
715 default: {
716 size_t rsiz;
717 char* rbuf = cur->get_key(&rsiz, myrand(10) == 0);
718 if (rbuf) {
719 delete[] rbuf;
720 } else if (db_->error() != kc::BasicDB::Error::NOREC) {
721 dberrprint(db_, __LINE__, "Cursor::get_key");
722 err_ = true;
723 }
724 break;
725 }
726 case 1: {
727 size_t rsiz;
728 char* rbuf = cur->get_value(&rsiz, myrand(10) == 0);
729 if (rbuf) {
730 delete[] rbuf;
731 } else if (db_->error() != kc::BasicDB::Error::NOREC) {
732 dberrprint(db_, __LINE__, "Cursor::get_value");
733 err_ = true;
734 }
735 break;
736 }
737 case 2: {
738 size_t rksiz;
739 const char* rvbuf;
740 size_t rvsiz;
741 char* rkbuf = cur->get(&rksiz, &rvbuf, &rvsiz, myrand(10) == 0);
742 if (rkbuf) {
743 delete[] rkbuf;
744 } else if (db_->error() != kc::BasicDB::Error::NOREC) {
745 dberrprint(db_, __LINE__, "Cursor::get");
746 err_ = true;
747 }
748 break;
749 }
750 case 3: {
751 std::string key, value;
752 if (!cur->get(&key, &value, myrand(10) == 0) &&
753 db_->error() != kc::BasicDB::Error::NOREC) {
754 dberrprint(db_, __LINE__, "Cursor::get");
755 err_ = true;
756 }
757 break;
758 }
759 case 4: {
760 if (myrand(8) == 0 && !cur->remove() &&
761 db_->error() != kc::BasicDB::Error::NOREC) {
762 dberrprint(db_, __LINE__, "Cursor::remove");
763 err_ = true;
764 }
765 break;
766 }
767 }
768 } else if (db_->error() != kc::BasicDB::Error::NOREC) {
769 dberrprint(db_, __LINE__, "Cursor::jump");
770 err_ = true;
771 }
772 delete cur;
773 break;
774 }
775 default: {
776 size_t vsiz;
777 char* vbuf = db_->get(kbuf, ksiz, &vsiz);
778 if (vbuf) {
779 delete[] vbuf;
780 } else if (db_->error() != kc::BasicDB::Error::NOREC) {
781 dberrprint(db_, __LINE__, "DB::get");
782 err_ = true;
783 }
784 break;
785 }
786 }
787 }
788 if (tran_ && !db_->end_transaction(true)) {
789 dberrprint(db_, __LINE__, "DB::end_transaction");
790 err_ = true;
791 }
792 if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
793 oputchar('.');
794 if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
795 }
796 }
797 }
798 private:
799 int32_t id_;
800 kc::BasicDB* db_;
801 int64_t rnum_;
802 int32_t thnum_;
803 bool err_;
804 bool rnd_;
805 bool tran_;
806 };
807 ThreadSet threadsets[THREADMAX];
808 if (thnum < 2) {
809 threadsets[0].setparams(0, &db, rnum, thnum, rnd, tran);
810 threadsets[0].run();
811 if (threadsets[0].error()) err = true;
812 } else {
813 for (int32_t i = 0; i < thnum; i++) {
814 threadsets[i].setparams(i, &db, rnum, thnum, rnd, tran);
815 threadsets[i].start();
816 }
817 for (int32_t i = 0; i < thnum; i++) {
818 threadsets[i].join();
819 if (threadsets[i].error()) err = true;
820 }
821 }
822 etime = kc::time();
823 dbmetaprint(&db, mode == 's');
824 oprintf("time: %.3f\n", etime - stime);
825 }
826 if (mode == 'e') {
827 oprintf("adding records:\n");
828 stime = kc::time();
829 class ThreadAdd : public kc::Thread {
830 public:
831 void setparams(int32_t id, kc::BasicDB* db, int64_t rnum, int32_t thnum,
832 bool rnd, bool tran) {
833 id_ = id;
834 db_ = db;
835 rnum_ = rnum;
836 thnum_ = thnum;
837 err_ = false;
838 rnd_ = rnd;
839 tran_ = tran;
840 }
841 bool error() {
842 return err_;
843 }
844 void run() {
845 int64_t base = id_ * rnum_;
846 int64_t range = rnum_ * thnum_;
847 for (int64_t i = 1; !err_ && i <= rnum_; i++) {
848 if (tran_ && !db_->begin_transaction(false)) {
849 dberrprint(db_, __LINE__, "DB::begin_transaction");
850 err_ = true;
851 }
852 char kbuf[RECBUFSIZ];
853 size_t ksiz = std::sprintf(kbuf, "%08lld",
854 (long long)(rnd_ ? myrand(range) + 1 : base + i));
855 if (!db_->add(kbuf, ksiz, kbuf, ksiz) &&
856 db_->error() != kc::BasicDB::Error::DUPREC) {
857 dberrprint(db_, __LINE__, "DB::add");
858 err_ = true;
859 }
860 if (tran_ && !db_->end_transaction(true)) {
861 dberrprint(db_, __LINE__, "DB::end_transaction");
862 err_ = true;
863 }
864 if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
865 oputchar('.');
866 if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
867 }
868 }
869 }
870 private:
871 int32_t id_;
872 kc::BasicDB* db_;
873 int64_t rnum_;
874 int32_t thnum_;
875 bool err_;
876 bool rnd_;
877 bool tran_;
878 };
879 ThreadAdd threadadds[THREADMAX];
880 if (thnum < 2) {
881 threadadds[0].setparams(0, &db, rnum, thnum, rnd, tran);
882 threadadds[0].run();
883 if (threadadds[0].error()) err = true;
884 } else {
885 for (int32_t i = 0; i < thnum; i++) {
886 threadadds[i].setparams(i, &db, rnum, thnum, rnd, tran);
887 threadadds[i].start();
888 }
889 for (int32_t i = 0; i < thnum; i++) {
890 threadadds[i].join();
891 if (threadadds[i].error()) err = true;
892 }
893 }
894 etime = kc::time();
895 dbmetaprint(&db, false);
896 oprintf("time: %.3f\n", etime - stime);
897 }
898 if (mode == 'e') {
899 oprintf("appending records:\n");
900 stime = kc::time();
901 class ThreadAppend : public kc::Thread {
902 public:
903 void setparams(int32_t id, kc::BasicDB* db, int64_t rnum, int32_t thnum,
904 bool rnd, bool tran) {
905 id_ = id;
906 db_ = db;
907 rnum_ = rnum;
908 thnum_ = thnum;
909 err_ = false;
910 rnd_ = rnd;
911 tran_ = tran;
912 }
913 bool error() {
914 return err_;
915 }
916 void run() {
917 int64_t base = id_ * rnum_;
918 int64_t range = rnum_ * thnum_;
919 for (int64_t i = 1; !err_ && i <= rnum_; i++) {
920 if (tran_ && !db_->begin_transaction(false)) {
921 dberrprint(db_, __LINE__, "DB::begin_transaction");
922 err_ = true;
923 }
924 char kbuf[RECBUFSIZ];
925 size_t ksiz = std::sprintf(kbuf, "%08lld",
926 (long long)(rnd_ ? myrand(range) + 1 : base + i));
927 if (!db_->append(kbuf, ksiz, kbuf, ksiz)) {
928 dberrprint(db_, __LINE__, "DB::append");
929 err_ = true;
930 }
931 if (tran_ && !db_->end_transaction(true)) {
932 dberrprint(db_, __LINE__, "DB::end_transaction");
933 err_ = true;
934 }
935 if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
936 oputchar('.');
937 if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
938 }
939 }
940 }
941 private:
942 int32_t id_;
943 kc::BasicDB* db_;
944 int64_t rnum_;
945 int32_t thnum_;
946 bool err_;
947 bool rnd_;
948 bool tran_;
949 };
950 ThreadAppend threadappends[THREADMAX];
951 if (thnum < 2) {
952 threadappends[0].setparams(0, &db, rnum, thnum, rnd, tran);
953 threadappends[0].run();
954 if (threadappends[0].error()) err = true;
955 } else {
956 for (int32_t i = 0; i < thnum; i++) {
957 threadappends[i].setparams(i, &db, rnum, thnum, rnd, tran);
958 threadappends[i].start();
959 }
960 for (int32_t i = 0; i < thnum; i++) {
961 threadappends[i].join();
962 if (threadappends[i].error()) err = true;
963 }
964 }
965 etime = kc::time();
966 dbmetaprint(&db, false);
967 oprintf("time: %.3f\n", etime - stime);
968 char* opaque = db.opaque();
969 if (opaque) {
970 std::memcpy(opaque, "1234567890123456", 16);
971 if (!db.synchronize_opaque()) {
972 dberrprint(&db, __LINE__, "DB::synchronize_opaque");
973 err = true;
974 }
975 } else {
976 dberrprint(&db, __LINE__, "DB::opaque");
977 err = true;
978 }
979 }
980 if (mode == 0 || mode == 'g' || mode == 'e') {
981 oprintf("getting records:\n");
982 stime = kc::time();
983 class ThreadGet : public kc::Thread {
984 public:
985 void setparams(int32_t id, kc::BasicDB* db, int64_t rnum, int32_t thnum,
986 bool rnd, bool tran) {
987 id_ = id;
988 db_ = db;
989 rnum_ = rnum;
990 thnum_ = thnum;
991 err_ = false;
992 rnd_ = rnd;
993 tran_ = tran;
994 }
995 bool error() {
996 return err_;
997 }
998 void run() {
999 int64_t base = id_ * rnum_;
1000 int64_t range = rnum_ * thnum_;
1001 for (int64_t i = 1; !err_ && i <= rnum_; i++) {
1002 if (tran_ && !db_->begin_transaction(false)) {
1003 dberrprint(db_, __LINE__, "DB::begin_transaction");
1004 err_ = true;
1005 }
1006 char kbuf[RECBUFSIZ];
1007 size_t ksiz = std::sprintf(kbuf, "%08lld",
1008 (long long)(rnd_ ? myrand(range) + 1 : base + i));
1009 size_t vsiz;
1010 char* vbuf = db_->get(kbuf, ksiz, &vsiz);
1011 if (vbuf) {
1012 if (vsiz < ksiz || std::memcmp(vbuf, kbuf, ksiz)) {
1013 dberrprint(db_, __LINE__, "DB::get");
1014 err_ = true;
1015 }
1016 delete[] vbuf;
1017 } else if (!rnd_ || db_->error() != kc::BasicDB::Error::NOREC) {
1018 dberrprint(db_, __LINE__, "DB::get");
1019 err_ = true;
1020 }
1021 if (rnd_ && i % 8 == 0) {
1022 switch (myrand(8)) {
1023 case 0: {
1024 if (!db_->set(kbuf, ksiz, kbuf, ksiz) &&
1025 db_->error() != kc::BasicDB::Error::NOPERM) {
1026 dberrprint(db_, __LINE__, "DB::set");
1027 err_ = true;
1028 }
1029 break;
1030 }
1031 case 1: {
1032 if (!db_->append(kbuf, ksiz, kbuf, ksiz) &&
1033 db_->error() != kc::BasicDB::Error::NOPERM) {
1034 dberrprint(db_, __LINE__, "DB::append");
1035 err_ = true;
1036 }
1037 break;
1038 }
1039 case 2: {
1040 if (!db_->remove(kbuf, ksiz) &&
1041 db_->error() != kc::BasicDB::Error::NOPERM &&
1042 db_->error() != kc::BasicDB::Error::NOREC) {
1043 dberrprint(db_, __LINE__, "DB::remove");
1044 err_ = true;
1045 }
1046 break;
1047 }
1048 case 3: {
1049 kc::DB::Cursor* cur = db_->cursor();
1050 if (cur->jump(kbuf, ksiz)) {
1051 switch (myrand(8)) {
1052 default: {
1053 size_t rsiz;
1054 char* rbuf = cur->get_key(&rsiz, myrand(10) == 0);
1055 if (rbuf) {
1056 delete[] rbuf;
1057 } else if (db_->error() != kc::BasicDB::Error::NOREC) {
1058 dberrprint(db_, __LINE__, "Cursor::get_key");
1059 err_ = true;
1060 }
1061 break;
1062 }
1063 case 1: {
1064 size_t rsiz;
1065 char* rbuf = cur->get_value(&rsiz, myrand(10) == 0);
1066 if (rbuf) {
1067 delete[] rbuf;
1068 } else if (db_->error() != kc::BasicDB::Error::NOREC) {
1069 dberrprint(db_, __LINE__, "Cursor::get_value");
1070 err_ = true;
1071 }
1072 break;
1073 }
1074 case 2: {
1075 size_t rksiz;
1076 const char* rvbuf;
1077 size_t rvsiz;
1078 char* rkbuf = cur->get(&rksiz, &rvbuf, &rvsiz, myrand(10) == 0);
1079 if (rkbuf) {
1080 delete[] rkbuf;
1081 } else if (db_->error() != kc::BasicDB::Error::NOREC) {
1082 dberrprint(db_, __LINE__, "Cursor::get");
1083 err_ = true;
1084 }
1085 break;
1086 }
1087 case 3: {
1088 std::string key, value;
1089 if (!cur->get(&key, &value, myrand(10) == 0) &&
1090 db_->error() != kc::BasicDB::Error::NOREC) {
1091 dberrprint(db_, __LINE__, "Cursor::get");
1092 err_ = true;
1093 }
1094 break;
1095 }
1096 case 4: {
1097 if (myrand(8) == 0 && !cur->remove() &&
1098 db_->error() != kc::BasicDB::Error::NOPERM &&
1099 db_->error() != kc::BasicDB::Error::NOREC) {
1100 dberrprint(db_, __LINE__, "Cursor::remove");
1101 err_ = true;
1102 }
1103 break;
1104 }
1105 }
1106 } else if (db_->error() != kc::BasicDB::Error::NOREC) {
1107 dberrprint(db_, __LINE__, "Cursor::jump");
1108 err_ = true;
1109 }
1110 delete cur;
1111 break;
1112 }
1113 default: {
1114 size_t vsiz;
1115 char* vbuf = db_->get(kbuf, ksiz, &vsiz);
1116 if (vbuf) {
1117 delete[] vbuf;
1118 } else if (db_->error() != kc::BasicDB::Error::NOREC) {
1119 dberrprint(db_, __LINE__, "DB::get");
1120 err_ = true;
1121 }
1122 break;
1123 }
1124 }
1125 }
1126 if (tran_ && !db_->end_transaction(true)) {
1127 dberrprint(db_, __LINE__, "DB::end_transaction");
1128 err_ = true;
1129 }
1130 if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
1131 oputchar('.');
1132 if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
1133 }
1134 }
1135 }
1136 private:
1137 int32_t id_;
1138 kc::BasicDB* db_;
1139 int64_t rnum_;
1140 int32_t thnum_;
1141 bool err_;
1142 bool rnd_;
1143 bool tran_;
1144 };
1145 ThreadGet threadgets[THREADMAX];
1146 if (thnum < 2) {
1147 threadgets[0].setparams(0, &db, rnum, thnum, rnd, tran);
1148 threadgets[0].run();
1149 if (threadgets[0].error()) err = true;
1150 } else {
1151 for (int32_t i = 0; i < thnum; i++) {
1152 threadgets[i].setparams(i, &db, rnum, thnum, rnd, tran);
1153 threadgets[i].start();
1154 }
1155 for (int32_t i = 0; i < thnum; i++) {
1156 threadgets[i].join();
1157 if (threadgets[i].error()) err = true;
1158 }
1159 }
1160 etime = kc::time();
1161 dbmetaprint(&db, mode == 'g');
1162 oprintf("time: %.3f\n", etime - stime);
1163 }
1164 if (mode == 'w' || mode == 'e') {
1165 oprintf("getting records with a buffer:\n");
1166 stime = kc::time();
1167 class ThreadGetBuffer : public kc::Thread {
1168 public:
1169 void setparams(int32_t id, kc::BasicDB* db, int64_t rnum, int32_t thnum,
1170 bool rnd, bool tran) {
1171 id_ = id;
1172 db_ = db;
1173 rnum_ = rnum;
1174 thnum_ = thnum;
1175 err_ = false;
1176 rnd_ = rnd;
1177 tran_ = tran;
1178 }
1179 bool error() {
1180 return err_;
1181 }
1182 void run() {
1183 int64_t base = id_ * rnum_;
1184 int64_t range = rnum_ * thnum_;
1185 for (int64_t i = 1; !err_ && i <= rnum_; i++) {
1186 if (tran_ && !db_->begin_transaction(false)) {
1187 dberrprint(db_, __LINE__, "DB::begin_transaction");
1188 err_ = true;
1189 }
1190 char kbuf[RECBUFSIZ];
1191 size_t ksiz = std::sprintf(kbuf, "%08lld",
1192 (long long)(rnd_ ? myrand(range) + 1 : base + i));
1193 char vbuf[RECBUFSIZ];
1194 int32_t vsiz = db_->get(kbuf, ksiz, vbuf, sizeof(vbuf));
1195 if (vsiz >= 0) {
1196 if (vsiz < (int32_t)ksiz || std::memcmp(vbuf, kbuf, ksiz)) {
1197 dberrprint(db_, __LINE__, "DB::get");
1198 err_ = true;
1199 }
1200 } else if (!rnd_ || db_->error() != kc::BasicDB::Error::NOREC) {
1201 dberrprint(db_, __LINE__, "DB::get");
1202 err_ = true;
1203 }
1204 if (tran_ && !db_->end_transaction(true)) {
1205 dberrprint(db_, __LINE__, "DB::end_transaction");
1206 err_ = true;
1207 }
1208 if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
1209 oputchar('.');
1210 if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
1211 }
1212 }
1213 }
1214 private:
1215 int32_t id_;
1216 kc::BasicDB* db_;
1217 int64_t rnum_;
1218 int32_t thnum_;
1219 bool err_;
1220 bool rnd_;
1221 bool tran_;
1222 };
1223 ThreadGetBuffer threadgetbuffers[THREADMAX];
1224 if (thnum < 2) {
1225 threadgetbuffers[0].setparams(0, &db, rnum, thnum, rnd, tran);
1226 threadgetbuffers[0].run();
1227 if (threadgetbuffers[0].error()) err = true;
1228 } else {
1229 for (int32_t i = 0; i < thnum; i++) {
1230 threadgetbuffers[i].setparams(i, &db, rnum, thnum, rnd, tran);
1231 threadgetbuffers[i].start();
1232 }
1233 for (int32_t i = 0; i < thnum; i++) {
1234 threadgetbuffers[i].join();
1235 if (threadgetbuffers[i].error()) err = true;
1236 }
1237 }
1238 etime = kc::time();
1239 dbmetaprint(&db, mode == 'w');
1240 oprintf("time: %.3f\n", etime - stime);
1241 }
1242 if (mode == 'e') {
1243 oprintf("traversing the database by the inner iterator:\n");
1244 stime = kc::time();
1245 int64_t cnt = db.count();
1246 class VisitorIterator : public kc::DB::Visitor {
1247 public:
1248 explicit VisitorIterator(int64_t rnum, bool rnd) :
1249 rnum_(rnum), rnd_(rnd), cnt_(0), rbuf_() {
1250 std::memset(rbuf_, '+', sizeof(rbuf_));
1251 }
1252 int64_t cnt() {
1253 return cnt_;
1254 }
1255 private:
1256 const char* visit_full(const char* kbuf, size_t ksiz,
1257 const char* vbuf, size_t vsiz, size_t* sp) {
1258 cnt_++;
1259 const char* rv = NOP;
1260 switch (rnd_ ? myrand(7) : cnt_ % 7) {
1261 case 0: {
1262 rv = rbuf_;
1263 *sp = rnd_ ? myrand(sizeof(rbuf_)) : sizeof(rbuf_) / (cnt_ % 5 + 1);
1264 break;
1265 }
1266 case 1: {
1267 rv = REMOVE;
1268 break;
1269 }
1270 }
1271 if (rnum_ > 250 && cnt_ % (rnum_ / 250) == 0) {
1272 oputchar('.');
1273 if (cnt_ == rnum_ || cnt_ % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)cnt_);
1274 }
1275 return rv;
1276 }
1277 int64_t rnum_;
1278 bool rnd_;
1279 int64_t cnt_;
1280 char rbuf_[RECBUFSIZ];
1281 } visitoriterator(rnum, rnd);
1282 if (tran && !db.begin_transaction(false)) {
1283 dberrprint(&db, __LINE__, "DB::begin_transaction");
1284 err = true;
1285 }
1286 if (!db.iterate(&visitoriterator, true)) {
1287 dberrprint(&db, __LINE__, "DB::iterate");
1288 err = true;
1289 }
1290 if (rnd) oprintf(" (end)\n");
1291 if (tran && !db.end_transaction(true)) {
1292 dberrprint(&db, __LINE__, "DB::end_transaction");
1293 err = true;
1294 }
1295 if (visitoriterator.cnt() != cnt) {
1296 dberrprint(&db, __LINE__, "DB::iterate");
1297 err = true;
1298 }
1299 etime = kc::time();
1300 dbmetaprint(&db, false);
1301 oprintf("time: %.3f\n", etime - stime);
1302 }
1303 if (mode == 'e') {
1304 oprintf("traversing the database by the outer cursor:\n");
1305 stime = kc::time();
1306 int64_t cnt = db.count();
1307 class VisitorCursor : public kc::DB::Visitor {
1308 public:
1309 explicit VisitorCursor(int64_t rnum, bool rnd) :
1310 rnum_(rnum), rnd_(rnd), cnt_(0), rbuf_() {
1311 std::memset(rbuf_, '-', sizeof(rbuf_));
1312 }
1313 int64_t cnt() {
1314 return cnt_;
1315 }
1316 private:
1317 const char* visit_full(const char* kbuf, size_t ksiz,
1318 const char* vbuf, size_t vsiz, size_t* sp) {
1319 cnt_++;
1320 const char* rv = NOP;
1321 switch (rnd_ ? myrand(7) : cnt_ % 7) {
1322 case 0: {
1323 rv = rbuf_;
1324 *sp = rnd_ ? myrand(sizeof(rbuf_)) : sizeof(rbuf_) / (cnt_ % 5 + 1);
1325 break;
1326 }
1327 case 1: {
1328 rv = REMOVE;
1329 break;
1330 }
1331 }
1332 if (rnum_ > 250 && cnt_ % (rnum_ / 250) == 0) {
1333 oputchar('.');
1334 if (cnt_ == rnum_ || cnt_ % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)cnt_);
1335 }
1336 return rv;
1337 }
1338 int64_t rnum_;
1339 bool rnd_;
1340 int64_t cnt_;
1341 char rbuf_[RECBUFSIZ];
1342 } visitorcursor(rnum, rnd);
1343 if (tran && !db.begin_transaction(false)) {
1344 dberrprint(&db, __LINE__, "DB::begin_transaction");
1345 err = true;
1346 }
1347 kc::TreeDB::Cursor cur(&db);
1348 if (!cur.jump() && db.error() != kc::BasicDB::Error::NOREC) {
1349 dberrprint(&db, __LINE__, "Cursor::jump");
1350 err = true;
1351 }
1352 kc::DB::Cursor* paracur = db.cursor();
1353 int64_t range = rnum * thnum;
1354 while (!err && cur.accept(&visitorcursor, true, !rnd)) {
1355 if (rnd) {
1356 char kbuf[RECBUFSIZ];
1357 size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)myrand(range));
1358 switch (myrand(3)) {
1359 case 0: {
1360 if (!db.remove(kbuf, ksiz) && db.error() != kc::BasicDB::Error::NOREC) {
1361 dberrprint(&db, __LINE__, "DB::remove");
1362 err = true;
1363 }
1364 break;
1365 }
1366 case 1: {
1367 if (!paracur->jump(kbuf, ksiz) && db.error() != kc::BasicDB::Error::NOREC) {
1368 dberrprint(&db, __LINE__, "Cursor::jump");
1369 err = true;
1370 }
1371 break;
1372 }
1373 default: {
1374 if (!cur.step() && db.error() != kc::BasicDB::Error::NOREC) {
1375 dberrprint(&db, __LINE__, "Cursor::step");
1376 err = true;
1377 }
1378 break;
1379 }
1380 }
1381 }
1382 }
1383 if (db.error() != kc::BasicDB::Error::NOREC) {
1384 dberrprint(&db, __LINE__, "Cursor::accept");
1385 err = true;
1386 }
1387 oprintf(" (end)\n");
1388 delete paracur;
1389 if (tran && !db.end_transaction(true)) {
1390 dberrprint(&db, __LINE__, "DB::end_transaction");
1391 err = true;
1392 }
1393 if (!rnd && visitorcursor.cnt() != cnt) {
1394 dberrprint(&db, __LINE__, "Cursor::accept");
1395 err = true;
1396 }
1397 etime = kc::time();
1398 dbmetaprint(&db, false);
1399 oprintf("time: %.3f\n", etime - stime);
1400 }
1401 if (mode == 'e') {
1402 oprintf("synchronizing the database:\n");
1403 stime = kc::time();
1404 if (!db.synchronize(false, NULL)) {
1405 dberrprint(&db, __LINE__, "DB::synchronize");
1406 err = true;
1407 }
1408 class SyncProcessor : public kc::BasicDB::FileProcessor {
1409 public:
1410 explicit SyncProcessor(int64_t rnum, bool rnd, int64_t size, int64_t msiz) :
1411 rnum_(rnum), rnd_(rnd), size_(size), msiz_(msiz) {}
1412 private:
1413 bool process(const std::string& path, int64_t count, int64_t size) {
1414 kc::File::Status sbuf;
1415 if (!kc::File::status(path, &sbuf)) return false;
1416 if (sbuf.size != size_ && sbuf.size != msiz_ &&
1417 sbuf.size % (1 << 20) != 0) return false;
1418 if (size != size_) return false;
1419 return true;
1420 }
1421 int64_t rnum_;
1422 bool rnd_;
1423 int64_t size_;
1424 int64_t msiz_;
1425 } syncprocessor(rnum, rnd, db.size(), msiz);
1426 if (!db.synchronize(false, &syncprocessor)) {
1427 dberrprint(&db, __LINE__, "DB::synchronize");
1428 err = true;
1429 }
1430 if (!db.occupy(rnd ? myrand(2) == 0 : true, &syncprocessor)) {
1431 dberrprint(&db, __LINE__, "DB::occupy");
1432 err = true;
1433 }
1434 etime = kc::time();
1435 dbmetaprint(&db, false);
1436 oprintf("time: %.3f\n", etime - stime);
1437 }
1438 if (mode == 'e' && db.size() < (256LL << 20)) {
1439 oprintf("dumping records into snapshot:\n");
1440 stime = kc::time();
1441 std::ostringstream ostrm;
1442 if (!db.dump_snapshot(&ostrm)) {
1443 dberrprint(&db, __LINE__, "DB::dump_snapshot");
1444 err = true;
1445 }
1446 etime = kc::time();
1447 dbmetaprint(&db, false);
1448 oprintf("time: %.3f\n", etime - stime);
1449 oprintf("loading records from snapshot:\n");
1450 stime = kc::time();
1451 int64_t cnt = db.count();
1452 if (rnd && myrand(2) == 0 && !db.clear()) {
1453 dberrprint(&db, __LINE__, "DB::clear");
1454 err = true;
1455 }
1456 const std::string& str = ostrm.str();
1457 std::istringstream istrm(str);
1458 if (!db.load_snapshot(&istrm) || db.count() != cnt) {
1459 dberrprint(&db, __LINE__, "DB::load_snapshot");
1460 err = true;
1461 }
1462 etime = kc::time();
1463 dbmetaprint(&db, false);
1464 oprintf("time: %.3f\n", etime - stime);
1465 }
1466 if (mode == 0 || mode == 'r' || mode == 'e') {
1467 oprintf("removing records:\n");
1468 stime = kc::time();
1469 class ThreadRemove : public kc::Thread {
1470 public:
1471 void setparams(int32_t id, kc::BasicDB* db, int64_t rnum, int32_t thnum,
1472 bool rnd, int32_t mode, bool tran) {
1473 id_ = id;
1474 db_ = db;
1475 rnum_ = rnum;
1476 thnum_ = thnum;
1477 err_ = false;
1478 rnd_ = rnd;
1479 mode_ = mode;
1480 tran_ = tran;
1481 }
1482 bool error() {
1483 return err_;
1484 }
1485 void run() {
1486 int64_t base = id_ * rnum_;
1487 int64_t range = rnum_ * thnum_;
1488 for (int64_t i = 1; !err_ && i <= rnum_; i++) {
1489 if (tran_ && !db_->begin_transaction(false)) {
1490 dberrprint(db_, __LINE__, "DB::begin_transaction");
1491 err_ = true;
1492 }
1493 char kbuf[RECBUFSIZ];
1494 size_t ksiz = std::sprintf(kbuf, "%08lld",
1495 (long long)(rnd_ ? myrand(range) + 1 : base + i));
1496 if (!db_->remove(kbuf, ksiz) &&
1497 ((!rnd_ && mode_ != 'e') || db_->error() != kc::BasicDB::Error::NOREC)) {
1498 dberrprint(db_, __LINE__, "DB::remove");
1499 err_ = true;
1500 }
1501 if (rnd_ && i % 8 == 0) {
1502 switch (myrand(8)) {
1503 case 0: {
1504 if (!db_->set(kbuf, ksiz, kbuf, ksiz)) {
1505 dberrprint(db_, __LINE__, "DB::set");
1506 err_ = true;
1507 }
1508 break;
1509 }
1510 case 1: {
1511 if (!db_->append(kbuf, ksiz, kbuf, ksiz)) {
1512 dberrprint(db_, __LINE__, "DB::append");
1513 err_ = true;
1514 }
1515 break;
1516 }
1517 case 2: {
1518 if (!db_->remove(kbuf, ksiz) &&
1519 db_->error() != kc::BasicDB::Error::NOREC) {
1520 dberrprint(db_, __LINE__, "DB::remove");
1521 err_ = true;
1522 }
1523 break;
1524 }
1525 case 3: {
1526 kc::DB::Cursor* cur = db_->cursor();
1527 if (cur->jump(kbuf, ksiz)) {
1528 switch (myrand(8)) {
1529 default: {
1530 size_t rsiz;
1531 char* rbuf = cur->get_key(&rsiz, myrand(10) == 0);
1532 if (rbuf) {
1533 delete[] rbuf;
1534 } else if (db_->error() != kc::BasicDB::Error::NOREC) {
1535 dberrprint(db_, __LINE__, "Cursor::get_key");
1536 err_ = true;
1537 }
1538 break;
1539 }
1540 case 1: {
1541 size_t rsiz;
1542 char* rbuf = cur->get_value(&rsiz, myrand(10) == 0);
1543 if (rbuf) {
1544 delete[] rbuf;
1545 } else if (db_->error() != kc::BasicDB::Error::NOREC) {
1546 dberrprint(db_, __LINE__, "Cursor::get_value");
1547 err_ = true;
1548 }
1549 break;
1550 }
1551 case 2: {
1552 size_t rksiz;
1553 const char* rvbuf;
1554 size_t rvsiz;
1555 char* rkbuf = cur->get(&rksiz, &rvbuf, &rvsiz, myrand(10) == 0);
1556 if (rkbuf) {
1557 delete[] rkbuf;
1558 } else if (db_->error() != kc::BasicDB::Error::NOREC) {
1559 dberrprint(db_, __LINE__, "Cursor::get");
1560 err_ = true;
1561 }
1562 break;
1563 }
1564 case 3: {
1565 std::string key, value;
1566 if (!cur->get(&key, &value, myrand(10) == 0) &&
1567 db_->error() != kc::BasicDB::Error::NOREC) {
1568 dberrprint(db_, __LINE__, "Cursor::get");
1569 err_ = true;
1570 }
1571 break;
1572 }
1573 case 4: {
1574 if (myrand(8) == 0 && !cur->remove() &&
1575 db_->error() != kc::BasicDB::Error::NOREC) {
1576 dberrprint(db_, __LINE__, "Cursor::remove");
1577 err_ = true;
1578 }
1579 break;
1580 }
1581 }
1582 } else if (db_->error() != kc::BasicDB::Error::NOREC) {
1583 dberrprint(db_, __LINE__, "Cursor::jump");
1584 err_ = true;
1585 }
1586 delete cur;
1587 break;
1588 }
1589 default: {
1590 size_t vsiz;
1591 char* vbuf = db_->get(kbuf, ksiz, &vsiz);
1592 if (vbuf) {
1593 delete[] vbuf;
1594 } else if (db_->error() != kc::BasicDB::Error::NOREC) {
1595 dberrprint(db_, __LINE__, "DB::get");
1596 err_ = true;
1597 }
1598 break;
1599 }
1600 }
1601 }
1602 if (tran_ && !db_->end_transaction(true)) {
1603 dberrprint(db_, __LINE__, "DB::end_transaction");
1604 err_ = true;
1605 }
1606 if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
1607 oputchar('.');
1608 if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
1609 }
1610 }
1611 }
1612 private:
1613 int32_t id_;
1614 kc::BasicDB* db_;
1615 int64_t rnum_;
1616 int32_t thnum_;
1617 bool err_;
1618 bool rnd_;
1619 int32_t mode_;
1620 bool tran_;
1621 };
1622 ThreadRemove threadremoves[THREADMAX];
1623 if (thnum < 2) {
1624 threadremoves[0].setparams(0, &db, rnum, thnum, rnd, mode, tran);
1625 threadremoves[0].run();
1626 if (threadremoves[0].error()) err = true;
1627 } else {
1628 for (int32_t i = 0; i < thnum; i++) {
1629 threadremoves[i].setparams(i, &db, rnum, thnum, rnd, mode, tran);
1630 threadremoves[i].start();
1631 }
1632 for (int32_t i = 0; i < thnum; i++) {
1633 threadremoves[i].join();
1634 if (threadremoves[i].error()) err = true;
1635 }
1636 }
1637 etime = kc::time();
1638 dbmetaprint(&db, mode == 'r' || mode == 'e');
1639 oprintf("time: %.3f\n", etime - stime);
1640 }
1641 oprintf("closing the database:\n");
1642 stime = kc::time();
1643 if (!db.close()) {
1644 dberrprint(&db, __LINE__, "DB::close");
1645 err = true;
1646 }
1647 etime = kc::time();
1648 oprintf("time: %.3f\n", etime - stime);
1649 oprintf("%s\n\n", err ? "error" : "ok");
1650 return err ? 1 : 0;
1651 }
1652
1653
1654 // perform queue command
procqueue(const char * path,int64_t rnum,int32_t thnum,int32_t itnum,bool rnd,int32_t oflags,int32_t apow,int32_t fpow,int32_t opts,int64_t bnum,int32_t psiz,int64_t msiz,int64_t dfunit,int64_t pccap,kc::Comparator * rcomp,bool lv)1655 static int32_t procqueue(const char* path, int64_t rnum, int32_t thnum, int32_t itnum, bool rnd,
1656 int32_t oflags, int32_t apow, int32_t fpow, int32_t opts, int64_t bnum,
1657 int32_t psiz, int64_t msiz, int64_t dfunit, int64_t pccap,
1658 kc::Comparator* rcomp, bool lv) {
1659 oprintf("<Queue Test>\n seed=%u path=%s rnum=%lld thnum=%d itnum=%d rnd=%d"
1660 " oflags=%d apow=%d fpow=%d opts=%d bnum=%lld psiz=%d msiz=%lld"
1661 " dfunit=%lld pccap=%lld rcomp=%p lv=%d\n\n",
1662 g_randseed, path, (long long)rnum, thnum, itnum, rnd, oflags, apow, fpow, opts,
1663 (long long)bnum, psiz, (long long)msiz, (long long)dfunit, (long long)pccap,
1664 rcomp, lv);
1665 bool err = false;
1666 kc::TreeDB db;
1667 db.tune_logger(stdlogger(g_progname, &std::cout),
1668 lv ? kc::UINT32MAX : kc::BasicDB::Logger::WARN | kc::BasicDB::Logger::ERROR);
1669 if (apow >= 0) db.tune_alignment(apow);
1670 if (fpow >= 0) db.tune_fbp(fpow);
1671 if (opts > 0) db.tune_options(opts);
1672 if (bnum > 0) db.tune_buckets(bnum);
1673 if (psiz > 0) db.tune_page(psiz);
1674 if (msiz >= 0) db.tune_map(msiz);
1675 if (dfunit > 0) db.tune_defrag(dfunit);
1676 if (pccap > 0) db.tune_page_cache(pccap);
1677 if (rcomp) db.tune_comparator(rcomp);
1678 for (int32_t itcnt = 1; itcnt <= itnum; itcnt++) {
1679 if (itnum > 1) oprintf("iteration %d:\n", itcnt);
1680 double stime = kc::time();
1681 uint32_t omode = kc::TreeDB::OWRITER | kc::TreeDB::OCREATE;
1682 if (itcnt == 1) omode |= kc::TreeDB::OTRUNCATE;
1683 if (!db.open(path, omode | oflags)) {
1684 dberrprint(&db, __LINE__, "DB::open");
1685 err = true;
1686 }
1687 class ThreadQueue : public kc::Thread {
1688 public:
1689 void setparams(int32_t id, kc::TreeDB* db, int64_t rnum, int32_t thnum, bool rnd,
1690 int64_t width) {
1691 id_ = id;
1692 db_ = db;
1693 rnum_ = rnum;
1694 thnum_ = thnum;
1695 rnd_ = rnd;
1696 width_ = width;
1697 err_ = false;
1698 }
1699 bool error() {
1700 return err_;
1701 }
1702 void run() {
1703 kc::DB::Cursor* cur = db_->cursor();
1704 int64_t base = id_ * rnum_;
1705 int64_t range = rnum_ * thnum_;
1706 for (int64_t i = 1; !err_ && i <= rnum_; i++) {
1707 char kbuf[RECBUFSIZ];
1708 size_t ksiz = std::sprintf(kbuf, "%010lld", (long long)(base + i));
1709 if (!db_->set(kbuf, ksiz, kbuf, ksiz)) {
1710 dberrprint(db_, __LINE__, "DB::set");
1711 err_ = true;
1712 }
1713 if (rnd_) {
1714 if (myrand(width_ / 2) == 0) {
1715 if (!cur->jump() && db_->error() != kc::BasicDB::Error::NOREC) {
1716 dberrprint(db_, __LINE__, "Cursor::jump");
1717 err_ = true;
1718 }
1719 ksiz = std::sprintf(kbuf, "%010lld", (long long)myrand(range) + 1);
1720 switch (myrand(10)) {
1721 case 0: {
1722 if (!db_->set(kbuf, ksiz, kbuf, ksiz)) {
1723 dberrprint(db_, __LINE__, "DB::set");
1724 err_ = true;
1725 }
1726 break;
1727 }
1728 case 1: {
1729 if (!db_->append(kbuf, ksiz, kbuf, ksiz)) {
1730 dberrprint(db_, __LINE__, "DB::append");
1731 err_ = true;
1732 }
1733 break;
1734 }
1735 case 2: {
1736 if (!db_->remove(kbuf, ksiz) &&
1737 db_->error() != kc::BasicDB::Error::NOREC) {
1738 dberrprint(db_, __LINE__, "DB::remove");
1739 err_ = true;
1740 }
1741 break;
1742 }
1743 }
1744 int64_t dnum = myrand(width_) + 2;
1745 for (int64_t j = 0; j < dnum; j++) {
1746 if (myrand(2) == 0) {
1747 size_t rsiz;
1748 char* rbuf = cur->get_key(&rsiz);
1749 if (rbuf) {
1750 if (myrand(10) == 0 && !db_->remove(rbuf, rsiz) &&
1751 db_->error() != kc::BasicDB::Error::NOREC) {
1752 dberrprint(db_, __LINE__, "DB::remove");
1753 err_ = true;
1754 }
1755 if (myrand(2) == 0 && !cur->jump(rbuf, rsiz) &&
1756 db_->error() != kc::BasicDB::Error::NOREC) {
1757 dberrprint(db_, __LINE__, "Cursor::jump");
1758 err_ = true;
1759 }
1760 if (myrand(10) == 0 && !db_->remove(rbuf, rsiz) &&
1761 db_->error() != kc::BasicDB::Error::NOREC) {
1762 dberrprint(db_, __LINE__, "DB::remove");
1763 err_ = true;
1764 }
1765 delete[] rbuf;
1766 } else if (db_->error() != kc::BasicDB::Error::NOREC) {
1767 dberrprint(db_, __LINE__, "Cursor::get_key");
1768 err_ = true;
1769 }
1770 }
1771 if (!cur->remove() && db_->error() != kc::BasicDB::Error::NOREC) {
1772 dberrprint(db_, __LINE__, "Cursor::remove");
1773 err_ = true;
1774 }
1775 }
1776 }
1777 } else {
1778 if (i > width_) {
1779 if (!cur->jump() && db_->error() != kc::BasicDB::Error::NOREC) {
1780 dberrprint(db_, __LINE__, "Cursor::jump");
1781 err_ = true;
1782 }
1783 if (!cur->remove() && db_->error() != kc::BasicDB::Error::NOREC) {
1784 dberrprint(db_, __LINE__, "Cursor::remove");
1785 err_ = true;
1786 }
1787 }
1788 }
1789 if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
1790 oputchar('.');
1791 if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
1792 }
1793 }
1794 delete cur;
1795 }
1796 private:
1797 int32_t id_;
1798 kc::TreeDB* db_;
1799 int64_t rnum_;
1800 int32_t thnum_;
1801 bool rnd_;
1802 int64_t width_;
1803 bool err_;
1804 };
1805 int64_t width = rnum / 10;
1806 ThreadQueue threads[THREADMAX];
1807 if (thnum < 2) {
1808 threads[0].setparams(0, &db, rnum, thnum, rnd, width);
1809 threads[0].run();
1810 if (threads[0].error()) err = true;
1811 } else {
1812 for (int32_t i = 0; i < thnum; i++) {
1813 threads[i].setparams(i, &db, rnum, thnum, rnd, width);
1814 threads[i].start();
1815 }
1816 for (int32_t i = 0; i < thnum; i++) {
1817 threads[i].join();
1818 if (threads[i].error()) err = true;
1819 }
1820 }
1821 int64_t count = db.count();
1822 if (!rnd && itcnt == 1 && count != width * thnum) {
1823 dberrprint(&db, __LINE__, "DB::count");
1824 err = true;
1825 }
1826 if ((rnd ? (myrand(2) == 0) : itcnt == itnum) && count > 0) {
1827 kc::DB::Cursor* cur = db.cursor();
1828 if (!cur->jump()) {
1829 dberrprint(&db, __LINE__, "Cursor::jump");
1830 err = true;
1831 }
1832 for (int64_t i = 1; i <= count; i++) {
1833 if (!cur->remove()) {
1834 dberrprint(&db, __LINE__, "Cursor::remove");
1835 err = true;
1836 }
1837 if (rnum > 250 && i % (rnum / 250) == 0) {
1838 oputchar('.');
1839 if (i == rnum || i % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
1840 }
1841 }
1842 if (rnd) oprintf(" (end)\n");
1843 delete cur;
1844 if (db.count() != 0) {
1845 dberrprint(&db, __LINE__, "DB::count");
1846 err = true;
1847 }
1848 }
1849 dbmetaprint(&db, itcnt == itnum);
1850 if (!db.close()) {
1851 dberrprint(&db, __LINE__, "DB::close");
1852 err = true;
1853 }
1854 oprintf("time: %.3f\n", kc::time() - stime);
1855 }
1856 oprintf("%s\n\n", err ? "error" : "ok");
1857 return err ? 1 : 0;
1858 }
1859
1860
1861 // perform wicked command
procwicked(const char * path,int64_t rnum,int32_t thnum,int32_t itnum,int32_t oflags,int32_t apow,int32_t fpow,int32_t opts,int64_t bnum,int32_t psiz,int64_t msiz,int64_t dfunit,int64_t pccap,kc::Comparator * rcomp,bool lv)1862 static int32_t procwicked(const char* path, int64_t rnum, int32_t thnum, int32_t itnum,
1863 int32_t oflags, int32_t apow, int32_t fpow, int32_t opts, int64_t bnum,
1864 int32_t psiz, int64_t msiz, int64_t dfunit, int64_t pccap,
1865 kc::Comparator* rcomp, bool lv) {
1866 oprintf("<Wicked Test>\n seed=%u path=%s rnum=%lld thnum=%d itnum=%d"
1867 " oflags=%d apow=%d fpow=%d opts=%d bnum=%lld psiz=%d msiz=%lld"
1868 " dfunit=%lld pccap=%lld rcomp=%p lv=%d\n\n",
1869 g_randseed, path, (long long)rnum, thnum, itnum, oflags, apow, fpow, opts,
1870 (long long)bnum, psiz, (long long)msiz, (long long)dfunit, (long long)pccap,
1871 rcomp, lv);
1872 bool err = false;
1873 kc::TreeDB db;
1874 db.tune_logger(stdlogger(g_progname, &std::cout),
1875 lv ? kc::UINT32MAX : kc::BasicDB::Logger::WARN | kc::BasicDB::Logger::ERROR);
1876 if (apow >= 0) db.tune_alignment(apow);
1877 if (fpow >= 0) db.tune_fbp(fpow);
1878 if (opts > 0) db.tune_options(opts);
1879 if (bnum > 0) db.tune_buckets(bnum);
1880 if (psiz > 0) db.tune_page(psiz);
1881 if (msiz >= 0) db.tune_map(msiz);
1882 if (dfunit > 0) db.tune_defrag(dfunit);
1883 if (pccap > 0) db.tune_page_cache(pccap);
1884 if (rcomp) db.tune_comparator(rcomp);
1885 for (int32_t itcnt = 1; itcnt <= itnum; itcnt++) {
1886 if (itnum > 1) oprintf("iteration %d:\n", itcnt);
1887 double stime = kc::time();
1888 uint32_t omode = kc::TreeDB::OWRITER | kc::TreeDB::OCREATE;
1889 if (itcnt == 1) omode |= kc::TreeDB::OTRUNCATE;
1890 if (!db.open(path, omode | oflags)) {
1891 dberrprint(&db, __LINE__, "DB::open");
1892 err = true;
1893 }
1894 class ThreadWicked : public kc::Thread {
1895 public:
1896 void setparams(int32_t id, kc::TreeDB* db, int64_t rnum, int32_t thnum,
1897 const char* lbuf) {
1898 id_ = id;
1899 db_ = db;
1900 rnum_ = rnum;
1901 thnum_ = thnum;
1902 lbuf_ = lbuf;
1903 err_ = false;
1904 }
1905 bool error() {
1906 return err_;
1907 }
1908 void run() {
1909 kc::DB::Cursor* cur = db_->cursor();
1910 int64_t range = rnum_ * thnum_ / 2;
1911 for (int64_t i = 1; !err_ && i <= rnum_; i++) {
1912 bool tran = myrand(100) == 0;
1913 if (tran) {
1914 if (myrand(2) == 0) {
1915 if (!db_->begin_transaction(myrand(rnum_) == 0)) {
1916 dberrprint(db_, __LINE__, "DB::begin_transaction");
1917 tran = false;
1918 err_ = true;
1919 }
1920 } else {
1921 if (!db_->begin_transaction_try(myrand(rnum_) == 0)) {
1922 if (db_->error() != kc::BasicDB::Error::LOGIC) {
1923 dberrprint(db_, __LINE__, "DB::begin_transaction_try");
1924 err_ = true;
1925 }
1926 tran = false;
1927 }
1928 }
1929 }
1930 char kbuf[RECBUFSIZ];
1931 size_t ksiz = std::sprintf(kbuf, "%lld", (long long)(myrand(range) + 1));
1932 if (myrand(1000) == 0) {
1933 ksiz = myrand(RECBUFSIZ) + 1;
1934 if (myrand(2) == 0) {
1935 for (size_t j = 0; j < ksiz; j++) {
1936 kbuf[j] = j;
1937 }
1938 } else {
1939 for (size_t j = 0; j < ksiz; j++) {
1940 kbuf[j] = myrand(256);
1941 }
1942 }
1943 }
1944 const char* vbuf = kbuf;
1945 size_t vsiz = ksiz;
1946 if (myrand(10) == 0) {
1947 vbuf = lbuf_;
1948 vsiz = myrand(RECBUFSIZL) / (myrand(5) + 1);
1949 }
1950 do {
1951 switch (myrand(10)) {
1952 case 0: {
1953 if (!db_->set(kbuf, ksiz, vbuf, vsiz)) {
1954 dberrprint(db_, __LINE__, "DB::set");
1955 err_ = true;
1956 }
1957 break;
1958 }
1959 case 1: {
1960 if (!db_->add(kbuf, ksiz, vbuf, vsiz) &&
1961 db_->error() != kc::BasicDB::Error::DUPREC) {
1962 dberrprint(db_, __LINE__, "DB::add");
1963 err_ = true;
1964 }
1965 break;
1966 }
1967 case 2: {
1968 if (!db_->replace(kbuf, ksiz, vbuf, vsiz) &&
1969 db_->error() != kc::BasicDB::Error::NOREC) {
1970 dberrprint(db_, __LINE__, "DB::replace");
1971 err_ = true;
1972 }
1973 break;
1974 }
1975 case 3: {
1976 if (!db_->append(kbuf, ksiz, vbuf, vsiz)) {
1977 dberrprint(db_, __LINE__, "DB::append");
1978 err_ = true;
1979 }
1980 break;
1981 }
1982 case 4: {
1983 if (myrand(2) == 0) {
1984 int64_t num = myrand(rnum_);
1985 int64_t orig = myrand(10) == 0 ? kc::INT64MIN : myrand(rnum_);
1986 if (myrand(10) == 0) orig = orig == kc::INT64MIN ? kc::INT64MAX : -orig;
1987 if (db_->increment(kbuf, ksiz, num, orig) == kc::INT64MIN &&
1988 db_->error() != kc::BasicDB::Error::LOGIC) {
1989 dberrprint(db_, __LINE__, "DB::increment");
1990 err_ = true;
1991 }
1992 } else {
1993 double num = myrand(rnum_ * 10) / (myrand(rnum_) + 1.0);
1994 double orig = myrand(10) == 0 ? -kc::inf() : myrand(rnum_);
1995 if (myrand(10) == 0) orig = -orig;
1996 if (kc::chknan(db_->increment_double(kbuf, ksiz, num, orig)) &&
1997 db_->error() != kc::BasicDB::Error::LOGIC) {
1998 dberrprint(db_, __LINE__, "DB::increment_double");
1999 err_ = true;
2000 }
2001 }
2002 break;
2003 }
2004 case 5: {
2005 if (!db_->cas(kbuf, ksiz, kbuf, ksiz, vbuf, vsiz) &&
2006 db_->error() != kc::BasicDB::Error::LOGIC) {
2007 dberrprint(db_, __LINE__, "DB::cas");
2008 err_ = true;
2009 }
2010 break;
2011 }
2012 case 6: {
2013 if (!db_->remove(kbuf, ksiz) &&
2014 db_->error() != kc::BasicDB::Error::NOREC) {
2015 dberrprint(db_, __LINE__, "DB::remove");
2016 err_ = true;
2017 }
2018 break;
2019 }
2020 case 7: {
2021 if (myrand(2) == 0) {
2022 if (db_->check(kbuf, ksiz) < 0 && db_->error() != kc::BasicDB::Error::NOREC) {
2023 dberrprint(db_, __LINE__, "DB::check");
2024 err_ = true;
2025 }
2026 } else {
2027 size_t rsiz;
2028 char* rbuf = db_->seize(kbuf, ksiz, &rsiz);
2029 if (rbuf) {
2030 delete[] rbuf;
2031 } else if (db_->error() != kc::BasicDB::Error::NOREC) {
2032 dberrprint(db_, __LINE__, "DB::seize");
2033 err_ = true;
2034 }
2035 }
2036 break;
2037 }
2038 case 8: {
2039 if (myrand(10) == 0) {
2040 if (myrand(4) == 0) {
2041 if (!cur->jump_back(kbuf, ksiz) &&
2042 db_->error() != kc::BasicDB::Error::NOREC) {
2043 dberrprint(db_, __LINE__, "Cursor::jump_back");
2044 err_ = true;
2045 }
2046 } else {
2047 if (!cur->jump(kbuf, ksiz) &&
2048 db_->error() != kc::BasicDB::Error::NOREC) {
2049 dberrprint(db_, __LINE__, "Cursor::jump");
2050 err_ = true;
2051 }
2052 }
2053 } else {
2054 class VisitorImpl : public kc::DB::Visitor {
2055 public:
2056 explicit VisitorImpl(const char* lbuf) : lbuf_(lbuf) {}
2057 private:
2058 const char* visit_full(const char* kbuf, size_t ksiz,
2059 const char* vbuf, size_t vsiz, size_t* sp) {
2060 const char* rv = NOP;
2061 switch (myrand(3)) {
2062 case 0: {
2063 rv = lbuf_;
2064 *sp = myrand(RECBUFSIZL) / (myrand(5) + 1);
2065 break;
2066 }
2067 case 1: {
2068 rv = REMOVE;
2069 break;
2070 }
2071 }
2072 return rv;
2073 }
2074 const char* lbuf_;
2075 } visitor(lbuf_);
2076 if (!cur->accept(&visitor, true, myrand(2) == 0) &&
2077 db_->error() != kc::BasicDB::Error::NOREC) {
2078 dberrprint(db_, __LINE__, "Cursor::accept");
2079 err_ = true;
2080 }
2081 if (myrand(3) == 0 && !cur->step() &&
2082 db_->error() != kc::BasicDB::Error::NOREC) {
2083 dberrprint(db_, __LINE__, "Cursor::step");
2084 err_ = true;
2085 }
2086 if (myrand(3) == 0 && !cur->step_back() &&
2087 db_->error() != kc::BasicDB::Error::NOREC) {
2088 dberrprint(db_, __LINE__, "Cursor::step");
2089 err_ = true;
2090 }
2091 }
2092 break;
2093 }
2094 default: {
2095 size_t rsiz;
2096 char* rbuf = db_->get(kbuf, ksiz, &rsiz);
2097 if (rbuf) {
2098 delete[] rbuf;
2099 } else if (db_->error() != kc::BasicDB::Error::NOREC) {
2100 dberrprint(db_, __LINE__, "DB::get");
2101 err_ = true;
2102 }
2103 break;
2104 }
2105 }
2106 } while (myrand(100) == 0);
2107 if (myrand(100) == 0) {
2108 int32_t jnum = myrand(10);
2109 switch (myrand(4)) {
2110 case 0: {
2111 std::map<std::string, std::string> recs;
2112 for (int32_t j = 0; j < jnum; j++) {
2113 char jbuf[RECBUFSIZ];
2114 size_t jsiz = std::sprintf(jbuf, "%lld", (long long)(myrand(range) + 1));
2115 recs[std::string(jbuf, jsiz)] = std::string(kbuf, ksiz);
2116 }
2117 if (db_->set_bulk(recs, myrand(4)) != (int64_t)recs.size()) {
2118 dberrprint(db_, __LINE__, "DB::set_bulk");
2119 err_ = true;
2120 }
2121 break;
2122 }
2123 case 1: {
2124 std::vector<std::string> keys;
2125 for (int32_t j = 0; j < jnum; j++) {
2126 char jbuf[RECBUFSIZ];
2127 size_t jsiz = std::sprintf(jbuf, "%lld", (long long)(myrand(range) + 1));
2128 keys.push_back(std::string(jbuf, jsiz));
2129 }
2130 if (db_->remove_bulk(keys, myrand(4)) < 0) {
2131 dberrprint(db_, __LINE__, "DB::remove_bulk");
2132 err_ = true;
2133 }
2134 break;
2135 }
2136 default: {
2137 std::vector<std::string> keys;
2138 for (int32_t j = 0; j < jnum; j++) {
2139 char jbuf[RECBUFSIZ];
2140 size_t jsiz = std::sprintf(jbuf, "%lld", (long long)(myrand(range) + 1));
2141 keys.push_back(std::string(jbuf, jsiz));
2142 }
2143 std::map<std::string, std::string> recs;
2144 if (db_->get_bulk(keys, &recs, myrand(4)) < 0) {
2145 dberrprint(db_, __LINE__, "DB::get_bulk");
2146 err_ = true;
2147 }
2148 break;
2149 }
2150 }
2151 }
2152 if (i == rnum_ / 2) {
2153 if (myrand(thnum_ * 4) == 0) {
2154 if (myrand(2) == 0) {
2155 if (!db_->defrag(0)) {
2156 dberrprint(db_, __LINE__, "DB::defrag");
2157 err_ = true;
2158 }
2159 } else {
2160 if (!db_->clear()) {
2161 dberrprint(db_, __LINE__, "DB::clear");
2162 err_ = true;
2163 }
2164 }
2165 } else {
2166 class SyncProcessor : public kc::BasicDB::FileProcessor {
2167 private:
2168 bool process(const std::string& path, int64_t count, int64_t size) {
2169 yield();
2170 return true;
2171 }
2172 } syncprocessor;
2173 if (!db_->synchronize(false, &syncprocessor)) {
2174 dberrprint(db_, __LINE__, "DB::synchronize");
2175 err_ = true;
2176 }
2177 }
2178 }
2179 if (tran) {
2180 yield();
2181 if (!db_->end_transaction(myrand(10) > 0)) {
2182 dberrprint(db_, __LINE__, "DB::end_transactin");
2183 err_ = true;
2184 }
2185 }
2186 if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
2187 oputchar('.');
2188 if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
2189 }
2190 }
2191 delete cur;
2192 }
2193 private:
2194 int32_t id_;
2195 kc::TreeDB* db_;
2196 int64_t rnum_;
2197 int32_t thnum_;
2198 const char* lbuf_;
2199 bool err_;
2200 };
2201 char lbuf[RECBUFSIZL];
2202 std::memset(lbuf, '*', sizeof(lbuf));
2203 ThreadWicked threads[THREADMAX];
2204 if (thnum < 2) {
2205 threads[0].setparams(0, &db, rnum, thnum, lbuf);
2206 threads[0].run();
2207 if (threads[0].error()) err = true;
2208 } else {
2209 for (int32_t i = 0; i < thnum; i++) {
2210 threads[i].setparams(i, &db, rnum, thnum, lbuf);
2211 threads[i].start();
2212 }
2213 for (int32_t i = 0; i < thnum; i++) {
2214 threads[i].join();
2215 if (threads[i].error()) err = true;
2216 }
2217 }
2218 dbmetaprint(&db, itcnt == itnum);
2219 if (!db.close()) {
2220 dberrprint(&db, __LINE__, "DB::close");
2221 err = true;
2222 }
2223 oprintf("time: %.3f\n", kc::time() - stime);
2224 }
2225 oprintf("%s\n\n", err ? "error" : "ok");
2226 return err ? 1 : 0;
2227 }
2228
2229
2230 // perform tran command
proctran(const char * path,int64_t rnum,int32_t thnum,int32_t itnum,bool hard,int32_t oflags,int32_t apow,int32_t fpow,int32_t opts,int64_t bnum,int32_t psiz,int64_t msiz,int64_t dfunit,int64_t pccap,kc::Comparator * rcomp,bool lv)2231 static int32_t proctran(const char* path, int64_t rnum, int32_t thnum, int32_t itnum, bool hard,
2232 int32_t oflags, int32_t apow, int32_t fpow, int32_t opts, int64_t bnum,
2233 int32_t psiz, int64_t msiz, int64_t dfunit, int64_t pccap,
2234 kc::Comparator* rcomp, bool lv) {
2235 oprintf("<Transaction Test>\n seed=%u path=%s rnum=%lld thnum=%d itnum=%d hard=%d"
2236 " oflags=%d apow=%d fpow=%d opts=%d bnum=%lld psiz=%d msiz=%lld"
2237 " dfunit=%lld pccap=%lld rcomp=%p lv=%d\n\n",
2238 g_randseed, path, (long long)rnum, thnum, itnum, hard, oflags, apow, fpow, opts,
2239 (long long)bnum, psiz, (long long)msiz, (long long)dfunit, (long long)pccap,
2240 rcomp, lv);
2241 bool err = false;
2242 kc::TreeDB db;
2243 kc::TreeDB paradb;
2244 db.tune_logger(stdlogger(g_progname, &std::cout),
2245 lv ? kc::UINT32MAX : kc::BasicDB::Logger::WARN | kc::BasicDB::Logger::ERROR);
2246 paradb.tune_logger(stdlogger(g_progname, &std::cout), lv ? kc::UINT32MAX :
2247 kc::BasicDB::Logger::WARN | kc::BasicDB::Logger::ERROR);
2248 if (apow >= 0) db.tune_alignment(apow);
2249 if (fpow >= 0) db.tune_fbp(fpow);
2250 if (opts > 0) db.tune_options(opts);
2251 if (bnum > 0) db.tune_buckets(bnum);
2252 if (psiz > 0) db.tune_page(psiz);
2253 if (msiz >= 0) db.tune_map(msiz);
2254 if (dfunit > 0) db.tune_defrag(dfunit);
2255 if (pccap > 0) db.tune_page_cache(pccap);
2256 if (rcomp) db.tune_comparator(rcomp);
2257 for (int32_t itcnt = 1; itcnt <= itnum; itcnt++) {
2258 oprintf("iteration %d updating:\n", itcnt);
2259 double stime = kc::time();
2260 uint32_t omode = kc::TreeDB::OWRITER | kc::TreeDB::OCREATE;
2261 if (itcnt == 1) omode |= kc::TreeDB::OTRUNCATE;
2262 if (!db.open(path, omode | oflags)) {
2263 dberrprint(&db, __LINE__, "DB::open");
2264 err = true;
2265 }
2266 std::string parapath = db.path() + "-para";
2267 if (!paradb.open(parapath, omode)) {
2268 dberrprint(¶db, __LINE__, "DB::open");
2269 err = true;
2270 }
2271 class ThreadTran : public kc::Thread {
2272 public:
2273 void setparams(int32_t id, kc::TreeDB* db, kc::TreeDB* paradb, int64_t rnum,
2274 int32_t thnum, bool hard, const char* lbuf) {
2275 id_ = id;
2276 db_ = db;
2277 paradb_ = paradb;
2278 rnum_ = rnum;
2279 thnum_ = thnum;
2280 hard_ = hard;
2281 lbuf_ = lbuf;
2282 err_ = false;
2283 }
2284 bool error() {
2285 return err_;
2286 }
2287 void run() {
2288 kc::DB::Cursor* cur = db_->cursor();
2289 int64_t range = rnum_ * thnum_;
2290 char kbuf[RECBUFSIZ];
2291 size_t ksiz = std::sprintf(kbuf, "%lld", (long long)(myrand(range) + 1));
2292 if (!cur->jump(kbuf, ksiz) && db_->error() != kc::BasicDB::Error::NOREC) {
2293 dberrprint(db_, __LINE__, "Cursor::jump");
2294 err_ = true;
2295 }
2296 bool tran = true;
2297 if (!db_->begin_transaction(hard_)) {
2298 dberrprint(db_, __LINE__, "DB::begin_transaction");
2299 tran = false;
2300 err_ = true;
2301 }
2302 bool commit = myrand(10) > 0;
2303 for (int64_t i = 1; !err_ && i <= rnum_; i++) {
2304 ksiz = std::sprintf(kbuf, "%lld", (long long)(myrand(range) + 1));
2305 const char* vbuf = kbuf;
2306 size_t vsiz = ksiz;
2307 if (myrand(10) == 0) {
2308 vbuf = lbuf_;
2309 vsiz = myrand(RECBUFSIZL) / (myrand(5) + 1);
2310 }
2311 class VisitorImpl : public kc::DB::Visitor {
2312 public:
2313 explicit VisitorImpl(const char* vbuf, size_t vsiz, kc::BasicDB* paradb) :
2314 vbuf_(vbuf), vsiz_(vsiz), paradb_(paradb) {}
2315 private:
2316 const char* visit_full(const char* kbuf, size_t ksiz,
2317 const char* vbuf, size_t vsiz, size_t* sp) {
2318 return visit_empty(kbuf, ksiz, sp);
2319 }
2320 const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp) {
2321 const char* rv = NOP;
2322 switch (myrand(3)) {
2323 case 0: {
2324 rv = vbuf_;
2325 *sp = vsiz_;
2326 if (paradb_) paradb_->set(kbuf, ksiz, vbuf_, vsiz_);
2327 break;
2328 }
2329 case 1: {
2330 rv = REMOVE;
2331 if (paradb_) paradb_->remove(kbuf, ksiz);
2332 break;
2333 }
2334 }
2335 return rv;
2336 }
2337 const char* vbuf_;
2338 size_t vsiz_;
2339 kc::BasicDB* paradb_;
2340 } visitor(vbuf, vsiz, !tran || commit ? paradb_ : NULL);
2341 if (myrand(4) == 0) {
2342 if (!cur->accept(&visitor, true, myrand(2) == 0) &&
2343 db_->error() != kc::BasicDB::Error::NOREC) {
2344 dberrprint(db_, __LINE__, "Cursor::accept");
2345 err_ = true;
2346 }
2347 } else {
2348 if (!db_->accept(kbuf, ksiz, &visitor, true)) {
2349 dberrprint(db_, __LINE__, "DB::accept");
2350 err_ = true;
2351 }
2352 }
2353 if (myrand(1000) == 0) {
2354 ksiz = std::sprintf(kbuf, "%lld", (long long)(myrand(range) + 1));
2355 if (!cur->jump(kbuf, ksiz)) {
2356 if (db_->error() != kc::BasicDB::Error::NOREC) {
2357 dberrprint(db_, __LINE__, "Cursor::jump");
2358 err_ = true;
2359 } else if (!cur->jump() && db_->error() != kc::BasicDB::Error::NOREC) {
2360 dberrprint(db_, __LINE__, "Cursor::jump");
2361 err_ = true;
2362 }
2363 }
2364 std::vector<std::string> keys;
2365 keys.reserve(100);
2366 while (myrand(50) != 0) {
2367 std::string key;
2368 if (cur->get_key(&key)) {
2369 keys.push_back(key);
2370 if (!cur->get_value(&key) && db_->error() != kc::BasicDB::Error::NOREC) {
2371 dberrprint(db_, __LINE__, "Cursor::get_value");
2372 err_ = true;
2373 }
2374 } else {
2375 if (db_->error() != kc::BasicDB::Error::NOREC) {
2376 dberrprint(db_, __LINE__, "Cursor::get_key");
2377 err_ = true;
2378 }
2379 break;
2380 }
2381 if (!cur->step()) {
2382 if (db_->error() != kc::BasicDB::Error::NOREC) {
2383 dberrprint(db_, __LINE__, "Cursor::jump");
2384 err_ = true;
2385 }
2386 break;
2387 }
2388 }
2389 class Remover : public kc::DB::Visitor {
2390 public:
2391 explicit Remover(kc::BasicDB* paradb) : paradb_(paradb) {}
2392 private:
2393 const char* visit_full(const char* kbuf, size_t ksiz,
2394 const char* vbuf, size_t vsiz, size_t* sp) {
2395 if (myrand(200) == 0) return NOP;
2396 if (paradb_) paradb_->remove(kbuf, ksiz);
2397 return REMOVE;
2398 }
2399 kc::BasicDB* paradb_;
2400 } remover(!tran || commit ? paradb_ : NULL);
2401 std::vector<std::string>::iterator it = keys.begin();
2402 std::vector<std::string>::iterator end = keys.end();
2403 while (it != end) {
2404 if (myrand(50) == 0) {
2405 if (!cur->accept(&remover, true, false) &&
2406 db_->error() != kc::BasicDB::Error::NOREC) {
2407 dberrprint(db_, __LINE__, "Cursor::accept");
2408 err_ = true;
2409 }
2410 } else {
2411 if (!db_->accept(it->c_str(), it->size(), &remover, true)) {
2412 dberrprint(db_, __LINE__, "DB::accept");
2413 err_ = true;
2414 }
2415 }
2416 ++it;
2417 }
2418 }
2419 if (tran && myrand(100) == 0) {
2420 if (db_->end_transaction(commit)) {
2421 yield();
2422 if (!db_->begin_transaction(hard_)) {
2423 dberrprint(db_, __LINE__, "DB::begin_transaction");
2424 tran = false;
2425 err_ = true;
2426 }
2427 } else {
2428 dberrprint(db_, __LINE__, "DB::end_transaction");
2429 err_ = true;
2430 }
2431 }
2432 if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) {
2433 oputchar('.');
2434 if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i);
2435 }
2436 }
2437 if (tran && !db_->end_transaction(commit)) {
2438 dberrprint(db_, __LINE__, "DB::end_transaction");
2439 err_ = true;
2440 }
2441 delete cur;
2442 }
2443 private:
2444 int32_t id_;
2445 kc::TreeDB* db_;
2446 kc::TreeDB* paradb_;
2447 int64_t rnum_;
2448 int32_t thnum_;
2449 bool hard_;
2450 const char* lbuf_;
2451 bool err_;
2452 };
2453 char lbuf[RECBUFSIZL];
2454 std::memset(lbuf, '*', sizeof(lbuf));
2455 ThreadTran threads[THREADMAX];
2456 if (thnum < 2) {
2457 threads[0].setparams(0, &db, ¶db, rnum, thnum, hard, lbuf);
2458 threads[0].run();
2459 if (threads[0].error()) err = true;
2460 } else {
2461 for (int32_t i = 0; i < thnum; i++) {
2462 threads[i].setparams(i, &db, ¶db, rnum, thnum, hard, lbuf);
2463 threads[i].start();
2464 }
2465 for (int32_t i = 0; i < thnum; i++) {
2466 threads[i].join();
2467 if (threads[i].error()) err = true;
2468 }
2469 }
2470 oprintf("iteration %d checking:\n", itcnt);
2471 if (db.count() != paradb.count()) {
2472 dberrprint(&db, __LINE__, "DB::count");
2473 err = true;
2474 }
2475 class VisitorImpl : public kc::DB::Visitor {
2476 public:
2477 explicit VisitorImpl(int64_t rnum, kc::BasicDB* paradb) :
2478 rnum_(rnum), paradb_(paradb), err_(false), cnt_(0) {}
2479 bool error() {
2480 return err_;
2481 }
2482 private:
2483 const char* visit_full(const char* kbuf, size_t ksiz,
2484 const char* vbuf, size_t vsiz, size_t* sp) {
2485 cnt_++;
2486 size_t rsiz;
2487 char* rbuf = paradb_->get(kbuf, ksiz, &rsiz);
2488 if (rbuf) {
2489 delete[] rbuf;
2490 } else {
2491 dberrprint(paradb_, __LINE__, "DB::get");
2492 err_ = true;
2493 }
2494 if (rnum_ > 250 && cnt_ % (rnum_ / 250) == 0) {
2495 oputchar('.');
2496 if (cnt_ == rnum_ || cnt_ % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)cnt_);
2497 }
2498 return NOP;
2499 }
2500 int64_t rnum_;
2501 kc::BasicDB* paradb_;
2502 bool err_;
2503 int64_t cnt_;
2504 } visitor(rnum, ¶db), paravisitor(rnum, &db);
2505 if (!db.iterate(&visitor, false)) {
2506 dberrprint(&db, __LINE__, "DB::iterate");
2507 err = true;
2508 }
2509 oprintf(" (end)\n");
2510 if (visitor.error()) err = true;
2511 if (!paradb.iterate(¶visitor, false)) {
2512 dberrprint(&db, __LINE__, "DB::iterate");
2513 err = true;
2514 }
2515 oprintf(" (end)\n");
2516 if (paravisitor.error()) err = true;
2517 if (!paradb.close()) {
2518 dberrprint(¶db, __LINE__, "DB::close");
2519 err = true;
2520 }
2521 dbmetaprint(&db, itcnt == itnum);
2522 if (!db.close()) {
2523 dberrprint(&db, __LINE__, "DB::close");
2524 err = true;
2525 }
2526 oprintf("time: %.3f\n", kc::time() - stime);
2527 }
2528 oprintf("%s\n\n", err ? "error" : "ok");
2529 return err ? 1 : 0;
2530 }
2531
2532
2533
2534 // END OF FILE
2535