1 | /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ |
2 | // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4: |
3 | #ident "$Id$" |
4 | /*====== |
5 | This file is part of PerconaFT. |
6 | |
7 | |
8 | Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved. |
9 | |
10 | PerconaFT is free software: you can redistribute it and/or modify |
11 | it under the terms of the GNU General Public License, version 2, |
12 | as published by the Free Software Foundation. |
13 | |
14 | PerconaFT is distributed in the hope that it will be useful, |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | GNU General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU General Public License |
20 | along with PerconaFT. If not, see <http://www.gnu.org/licenses/>. |
21 | |
22 | ---------------------------------------- |
23 | |
24 | PerconaFT is free software: you can redistribute it and/or modify |
25 | it under the terms of the GNU Affero General Public License, version 3, |
26 | as published by the Free Software Foundation. |
27 | |
28 | PerconaFT is distributed in the hope that it will be useful, |
29 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
30 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
31 | GNU Affero General Public License for more details. |
32 | |
33 | You should have received a copy of the GNU Affero General Public License |
34 | along with PerconaFT. If not, see <http://www.gnu.org/licenses/>. |
35 | ======= */ |
36 | |
37 | #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved." |
38 | |
39 | #include <db.h> |
40 | |
41 | #include <toku_stdlib.h> |
42 | #include <toku_stdint.h> |
43 | #include <toku_portability.h> |
44 | #include <toku_assert.h> |
45 | #include <stdio.h> |
46 | #include <sys/types.h> |
47 | #include <unistd.h> |
48 | #include <string.h> |
49 | #include <ctype.h> |
50 | #include <errno.h> |
51 | #include <getopt.h> |
52 | #include <signal.h> |
53 | #include <memory.h> |
54 | |
55 | typedef struct { |
56 | bool leadingspace; |
57 | bool plaintext; |
58 | bool ; |
59 | bool ; |
60 | bool is_private; |
61 | bool recovery_and_txn; |
62 | char* progname; |
63 | char* homedir; |
64 | char* database; |
65 | char* subdatabase; |
66 | int exitcode; |
67 | int recover_flags; |
68 | DBTYPE dbtype; |
69 | DBTYPE opened_dbtype; |
70 | DB* db; |
71 | DB_ENV* dbenv; |
72 | } dump_globals; |
73 | |
74 | dump_globals g; |
75 | |
76 | #define SET_BITS(bitvector, bits) ((bitvector) |= (bits)) |
77 | #define REMOVE_BITS(bitvector, bits) ((bitvector) &= ~(bits)) |
78 | #define IS_SET_ANY(bitvector, bits) ((bitvector) & (bits)) |
79 | #define IS_SET_ALL(bitvector, bits) (((bitvector) & (bits)) == (bits)) |
80 | |
81 | #define IS_POWER_OF_2(num) ((num) > 0 && ((num) & ((num) - 1)) == 0) |
82 | |
83 | //DB_ENV->err disabled since it does not use db_strerror |
84 | #define PRINT_ERROR(retval, ...) \ |
85 | do { \ |
86 | if (0) g.dbenv->err(g.dbenv, retval, __VA_ARGS__); \ |
87 | else { \ |
88 | fprintf(stderr, "\tIn %s:%d %s()\n", __FILE__, __LINE__, __FUNCTION__); \ |
89 | fprintf(stderr, "%s: %s:", g.progname, db_strerror(retval)); \ |
90 | fprintf(stderr, __VA_ARGS__); \ |
91 | fprintf(stderr, "\n"); \ |
92 | fflush(stderr); \ |
93 | } \ |
94 | } while (0) |
95 | |
96 | //DB_ENV->err disabled since it does not use db_strerror, errx does not exist. |
97 | #define PRINT_ERRORX(...) \ |
98 | do { \ |
99 | if (0) g.dbenv->err(g.dbenv, 0, __VA_ARGS__); \ |
100 | else { \ |
101 | fprintf(stderr, "\tIn %s:%d %s()\n", __FILE__, __LINE__, __FUNCTION__); \ |
102 | fprintf(stderr, "%s: ", g.progname); \ |
103 | fprintf(stderr, __VA_ARGS__); \ |
104 | fprintf(stderr, "\n"); \ |
105 | fflush(stderr); \ |
106 | } \ |
107 | } while (0) |
108 | |
109 | int strtoint32 (char* str, int32_t* num, int32_t min, int32_t max, int base); |
110 | int strtouint32 (char* str, uint32_t* num, uint32_t min, uint32_t max, int base); |
111 | int strtoint64 (char* str, int64_t* num, int64_t min, int64_t max, int base); |
112 | int strtouint64 (char* str, uint64_t* num, uint64_t min, uint64_t max, int base); |
113 | |
114 | /* |
115 | * Convert a string to an integer of type "type". |
116 | * |
117 | * |
118 | * Sets errno and returns: |
119 | * EINVAL: str == NULL, num == NULL, or string not of the form [ \t]*[+-]?[0-9]+ |
120 | * ERANGE: value out of range specified. (Range of [min, max]) |
121 | * |
122 | * *num is unchanged on error. |
123 | * Returns: |
124 | * |
125 | */ |
126 | #define DEF_STR_TO(name, type, bigtype, strtofunc, frmt) \ |
127 | int name(char* str, type* num, type min, type max, int base) \ |
128 | { \ |
129 | char* test; \ |
130 | bigtype value; \ |
131 | \ |
132 | assert(str); \ |
133 | assert(num); \ |
134 | assert(min <= max); \ |
135 | assert(g.dbenv || g.progname); \ |
136 | assert(base == 0 || (base >= 2 && base <= 36)); \ |
137 | \ |
138 | errno = 0; \ |
139 | while (isspace(*str)) str++; \ |
140 | value = strtofunc(str, &test, base); \ |
141 | if ((*test != '\0' && *test != '\n') || test == str) { \ |
142 | PRINT_ERRORX("%s: Invalid numeric argument\n", str); \ |
143 | errno = EINVAL; \ |
144 | goto error; \ |
145 | } \ |
146 | if (errno != 0) { \ |
147 | PRINT_ERROR(errno, "%s\n", str); \ |
148 | } \ |
149 | if (value < min) { \ |
150 | PRINT_ERRORX("%s: Less than minimum value (%" frmt ")\n", str, min); \ |
151 | goto error; \ |
152 | } \ |
153 | if (value > max) { \ |
154 | PRINT_ERRORX("%s: Greater than maximum value (%" frmt ")\n", str, max); \ |
155 | goto error; \ |
156 | } \ |
157 | *num = value; \ |
158 | return EXIT_SUCCESS; \ |
159 | error: \ |
160 | return errno; \ |
161 | } |
162 | |
163 | DEF_STR_TO(strtoint32, int32_t, int64_t, strtoll, PRId32) |
164 | DEF_STR_TO(strtouint32, uint32_t, uint64_t, strtoull, PRIu32) |
165 | DEF_STR_TO(strtoint64, int64_t, int64_t, strtoll, PRId64) |
166 | DEF_STR_TO(strtouint64, uint64_t, uint64_t, strtoull, PRIu64) |
167 | |
168 | static inline void |
169 | outputbyte(uint8_t ch) |
170 | { |
171 | if (g.plaintext) { |
172 | if (ch == '\\') printf("\\\\" ); |
173 | else if (isprint(ch)) printf("%c" , ch); |
174 | else printf("\\%02x" , ch); |
175 | } |
176 | else printf("%02x" , ch); |
177 | } |
178 | |
179 | static inline void |
180 | outputstring(char* str) |
181 | { |
182 | char* p; |
183 | |
184 | for (p = str; *p != '\0'; p++) { |
185 | outputbyte((uint8_t)*p); |
186 | } |
187 | } |
188 | |
189 | static inline void |
190 | outputplaintextstring(char* str) |
191 | { |
192 | bool old_plaintext = g.plaintext; |
193 | g.plaintext = true; |
194 | outputstring(str); |
195 | g.plaintext = old_plaintext; |
196 | } |
197 | |
198 | static inline int |
199 | verify_library_version(void) |
200 | { |
201 | int major; |
202 | int minor; |
203 | |
204 | db_version(&major, &minor, NULL); |
205 | if (major != DB_VERSION_MAJOR || minor != DB_VERSION_MINOR) { |
206 | PRINT_ERRORX("version %d.%d doesn't match library version %d.%d\n" , |
207 | DB_VERSION_MAJOR, DB_VERSION_MINOR, major, minor); |
208 | return EXIT_FAILURE; |
209 | } |
210 | return EXIT_SUCCESS; |
211 | } |
212 | |
213 | static int last_caught = 0; |
214 | |
215 | static void catch_signal(int which_signal) { |
216 | last_caught = which_signal; |
217 | if (last_caught == 0) last_caught = SIGINT; |
218 | } |
219 | |
220 | static inline void |
221 | init_catch_signals(void) { |
222 | signal(SIGINT, catch_signal); |
223 | signal(SIGTERM, catch_signal); |
224 | #ifdef SIGHUP |
225 | signal(SIGHUP, catch_signal); |
226 | #endif |
227 | #ifdef SIGPIPE |
228 | signal(SIGPIPE, catch_signal); |
229 | #endif |
230 | } |
231 | |
232 | static inline int |
233 | caught_any_signals(void) { |
234 | return last_caught != 0; |
235 | } |
236 | |
237 | static inline void |
238 | resend_signals(void) { |
239 | if (last_caught) { |
240 | signal(last_caught, SIG_DFL); |
241 | raise(last_caught); |
242 | } |
243 | } |
244 | |
245 | static int usage (void); |
246 | static int create_init_env(void); |
247 | static int dump_database (void); |
248 | static int open_database (void); |
249 | static int dump_pairs (void); |
250 | static int dump_footer (void); |
251 | static int dump_header (void); |
252 | static int close_database (void); |
253 | |
254 | int main(int argc, char *const argv[]) { |
255 | int ch; |
256 | int retval; |
257 | |
258 | /* Set up the globals. */ |
259 | memset(&g, 0, sizeof(g)); |
260 | g.leadingspace = true; |
261 | //TODO: Uncomment when DB_UNKNOWN + db->get_type are implemented. |
262 | g.dbtype = DB_UNKNOWN; |
263 | //g.dbtype = DB_BTREE; |
264 | g.progname = argv[0]; |
265 | g.header = true; |
266 | g.footer = true; |
267 | g.recovery_and_txn = true; |
268 | |
269 | if (verify_library_version() != 0) goto error; |
270 | |
271 | while ((ch = getopt(argc, argv, "d:f:h:klNP:ps:RrVTx" )) != EOF) { |
272 | switch (ch) { |
273 | case ('d'): { |
274 | PRINT_ERRORX("-%c option not supported.\n" , ch); |
275 | goto error; |
276 | } |
277 | case ('f'): { |
278 | if (freopen(optarg, "w" , stdout) == NULL) { |
279 | fprintf(stderr, |
280 | "%s: %s: reopen: %s\n" , |
281 | g.progname, optarg, strerror(errno)); |
282 | goto error; |
283 | } |
284 | break; |
285 | } |
286 | case ('h'): { |
287 | g.homedir = optarg; |
288 | break; |
289 | } |
290 | case ('k'): { |
291 | PRINT_ERRORX("-%c option not supported.\n" , ch); |
292 | goto error; |
293 | } |
294 | case ('l'): { |
295 | //TODO: Implement (Requires master database support) |
296 | PRINT_ERRORX("-%c option not supported.\n" , ch); //YET! |
297 | goto error; |
298 | } |
299 | case ('N'): { |
300 | PRINT_ERRORX("-%c option not supported.\n" , ch); |
301 | goto error; |
302 | } |
303 | case ('P'): { |
304 | /* Clear password. */ |
305 | memset(optarg, 0, strlen(optarg)); |
306 | PRINT_ERRORX("-%c option not supported.\n" , ch); |
307 | goto error; |
308 | } |
309 | case ('p'): { |
310 | g.plaintext = true; |
311 | break; |
312 | } |
313 | case ('R'): { |
314 | //TODO: Uncomment when DB_SALVAGE,DB_AGGRESSIVE are implemented. |
315 | /*g.recover_flags |= DB_SALVAGE | DB_AGGRESSIVE;*/ |
316 | |
317 | //TODO: Implement aggressive recovery (requires db->verify()) |
318 | PRINT_ERRORX("-%c option not supported.\n" , ch); |
319 | goto error; |
320 | } |
321 | case ('r'): { |
322 | //TODO: Uncomment when DB_SALVAGE,DB_AGGRESSIVE are implemented. |
323 | /*g.recover_flags |= DB_SALVAGE;*/ |
324 | |
325 | //TODO: Implement recovery (requires db->verify()) |
326 | PRINT_ERRORX("-%c option not supported.\n" , ch); |
327 | goto error; |
328 | } |
329 | case ('s'): { |
330 | g.subdatabase = optarg; |
331 | break; |
332 | } |
333 | case ('V'): { |
334 | printf("%s\n" , db_version(NULL, NULL, NULL)); |
335 | goto cleanup; |
336 | } |
337 | case ('T'): { |
338 | g.plaintext = true; |
339 | g.leadingspace = false; |
340 | g.header = false; |
341 | g.footer = false; |
342 | break; |
343 | } |
344 | case ('x'): { |
345 | g.recovery_and_txn = false; |
346 | break; |
347 | } |
348 | case ('?'): |
349 | default: { |
350 | g.exitcode = usage(); |
351 | goto cleanup; |
352 | } |
353 | } |
354 | } |
355 | argc -= optind; |
356 | argv += optind; |
357 | |
358 | //TODO: Uncomment when DB_SALVAGE,DB_AGGRESSIVE,DB_PRINTABLE,db->verify are implemented. |
359 | /* |
360 | if (g.plaintext) g.recover_flags |= DB_PRINTABLE; |
361 | |
362 | if (g.subdatabase != NULL && IS_SET_ALL(g.recover_flags, DB_SALVAGE)) { |
363 | if (IS_SET_ALL(g.recover_flags, DB_AGGRESSIVE)) { |
364 | PRINT_ERRORX("The -s and -R options may not both be specified.\n"); |
365 | goto error; |
366 | } |
367 | PRINT_ERRORX("The -s and -r options may not both be specified.\n"); |
368 | goto error; |
369 | |
370 | } |
371 | */ |
372 | |
373 | if (argc != 1) { |
374 | g.exitcode = usage(); |
375 | goto cleanup; |
376 | } |
377 | |
378 | init_catch_signals(); |
379 | |
380 | g.database = argv[0]; |
381 | if (caught_any_signals()) goto cleanup; |
382 | if (create_init_env() != 0) goto error; |
383 | if (caught_any_signals()) goto cleanup; |
384 | if (dump_database() != 0) goto error; |
385 | if (false) { |
386 | error: |
387 | g.exitcode = EXIT_FAILURE; |
388 | fprintf(stderr, "%s: Quitting out due to errors.\n" , g.progname); |
389 | } |
390 | cleanup: |
391 | if (g.dbenv && (retval = g.dbenv->close(g.dbenv, 0)) != 0) { |
392 | g.exitcode = EXIT_FAILURE; |
393 | fprintf(stderr, "%s: %s: dbenv->close\n" , g.progname, db_strerror(retval)); |
394 | } |
395 | // if (g.subdatabase) free(g.subdatabase); |
396 | resend_signals(); |
397 | |
398 | return g.exitcode; |
399 | } |
400 | |
401 | int dump_database() |
402 | { |
403 | int retval; |
404 | |
405 | /* Create a database handle. */ |
406 | retval = db_create(&g.db, g.dbenv, 0); |
407 | if (retval != 0) { |
408 | PRINT_ERROR(retval, "db_create" ); |
409 | return EXIT_FAILURE; |
410 | } |
411 | |
412 | /* |
413 | TODO: If/when supporting encryption |
414 | if (g.password && (retval = db->set_flags(db, DB_ENCRYPT))) { |
415 | PRINT_ERROR(ret, "DB->set_flags: DB_ENCRYPT"); |
416 | goto error; |
417 | } |
418 | */ |
419 | if (open_database() != 0) goto error; |
420 | if (caught_any_signals()) goto cleanup; |
421 | if (g.header && dump_header() != 0) goto error; |
422 | if (caught_any_signals()) goto cleanup; |
423 | if (dump_pairs() != 0) goto error; |
424 | if (caught_any_signals()) goto cleanup; |
425 | if (g.footer && dump_footer() != 0) goto error; |
426 | |
427 | if (false) { |
428 | error: |
429 | g.exitcode = EXIT_FAILURE; |
430 | } |
431 | cleanup: |
432 | |
433 | if (close_database() != 0) g.exitcode = EXIT_FAILURE; |
434 | |
435 | return g.exitcode; |
436 | } |
437 | |
438 | int usage() |
439 | { |
440 | fprintf(stderr, |
441 | "usage: %s [-pVT] [-x] [-f output] [-h home] [-s database] db_file\n" , |
442 | g.progname); |
443 | return EXIT_FAILURE; |
444 | } |
445 | |
446 | int create_init_env() |
447 | { |
448 | int retval; |
449 | DB_ENV* dbenv; |
450 | int flags; |
451 | //TODO: Experiments to determine right cache size for tokudb, or maybe command line argument. |
452 | |
453 | retval = db_env_create(&dbenv, 0); |
454 | if (retval) { |
455 | fprintf(stderr, "%s: db_dbenv_create: %s\n" , g.progname, db_strerror(retval)); |
456 | goto error; |
457 | } |
458 | ///TODO: UNCOMMENT/IMPLEMENT dbenv->set_errfile(dbenv, stderr); |
459 | dbenv->set_errpfx(dbenv, g.progname); |
460 | /* |
461 | TODO: Anything for encryption? |
462 | */ |
463 | |
464 | /* Open the dbenvironment. */ |
465 | g.is_private = false; |
466 | //flags = DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_USE_ENVIRON; |
467 | flags = DB_INIT_LOCK | DB_INIT_MPOOL; ///TODO: UNCOMMENT/IMPLEMENT | DB_USE_ENVIRON; |
468 | if (g.recovery_and_txn) { |
469 | SET_BITS(flags, DB_INIT_LOG | DB_INIT_TXN | DB_RECOVER); |
470 | } |
471 | |
472 | /* |
473 | ///TODO: UNCOMMENT/IMPLEMENT Notes: We require DB_PRIVATE |
474 | if (!dbenv->open(dbenv, g.homedir, flags, 0)) goto success; |
475 | */ |
476 | |
477 | /* |
478 | ///TODO: UNCOMMENT/IMPLEMENT |
479 | retval = dbenv->set_cachesize(dbenv, 0, cache, 1); |
480 | if (retval) { |
481 | PRINT_ERROR(retval, "DB_ENV->set_cachesize"); |
482 | goto error; |
483 | } |
484 | */ |
485 | g.is_private = true; |
486 | //TODO: Do we want to support transactions even in single-process mode? |
487 | //Logging is not necessary.. this is read-only. |
488 | //However, do we need to use DB_INIT_LOG to join a logging environment? |
489 | //REMOVE_BITS(flags, DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN); |
490 | SET_BITS(flags, DB_CREATE | DB_PRIVATE); |
491 | |
492 | retval = dbenv->open(dbenv, g.homedir, flags, 0); |
493 | if (retval) { |
494 | PRINT_ERROR(retval, "DB_ENV->open" ); |
495 | goto error; |
496 | } |
497 | g.dbenv = dbenv; |
498 | return EXIT_SUCCESS; |
499 | |
500 | error: |
501 | return EXIT_FAILURE; |
502 | } |
503 | |
504 | #define DUMP_FLAG(bit, dump) if (IS_SET_ALL(flags, bit)) printf(dump); |
505 | |
506 | #define DUMP_IGNORED_FLAG(bit, dump) |
507 | |
508 | |
509 | int () |
510 | { |
511 | uint32_t flags; |
512 | int retval; |
513 | DB* db = g.db; |
514 | |
515 | assert(g.header); |
516 | printf("VERSION=3\n" ); |
517 | printf("format=%s\n" , g.plaintext ? "print" : "bytevalue" ); |
518 | //TODO: Uncomment when DB_UNKNOWN + db->get_type are implemented. |
519 | /*assert(g.dbtype == DB_BTREE || (g.dbtype == DB_UNKNOWN && g.opened_dbtype == DB_BTREE));*/ |
520 | printf("type=btree\n" ); |
521 | //TODO: Get page size from db. Currently tokudb does not support db->get_pagesize. |
522 | //Don't print this out //printf("db_pagesize=4096\n"); |
523 | if (g.subdatabase) { |
524 | printf("subdatabase=" ); |
525 | outputplaintextstring(g.subdatabase); |
526 | printf("\n" ); |
527 | } |
528 | //TODO: Uncomment when db->get_flags is implemented |
529 | if ((retval = db->get_flags(db, &flags)) != 0) { |
530 | PRINT_ERROR(retval, "DB->get_flags" ); |
531 | goto error; |
532 | } |
533 | DUMP_IGNORED_FLAG(DB_CHKSUM, "chksum=1\n" ); |
534 | DUMP_IGNORED_FLAG(DB_RECNUM, "recnum=1\n" ); |
535 | printf("HEADER=END\n" ); |
536 | |
537 | if (ferror(stdout)) goto error; |
538 | return EXIT_SUCCESS; |
539 | |
540 | error: |
541 | return EXIT_FAILURE; |
542 | } |
543 | |
544 | int () |
545 | { |
546 | printf("DATA=END\n" ); |
547 | if (ferror(stdout)) goto error; |
548 | |
549 | return EXIT_SUCCESS; |
550 | error: |
551 | return EXIT_FAILURE; |
552 | } |
553 | |
554 | int open_database() |
555 | { |
556 | DB* db = g.db; |
557 | int retval; |
558 | |
559 | int open_flags = 0;//|DB_RDONLY; |
560 | //TODO: Transaction auto commit stuff |
561 | SET_BITS(open_flags, DB_AUTO_COMMIT); |
562 | |
563 | retval = db->open(db, NULL, g.database, g.subdatabase, g.dbtype, open_flags, 0666); |
564 | if (retval != 0) { |
565 | PRINT_ERROR(retval, "DB->open: %s" , g.database); |
566 | goto error; |
567 | } |
568 | //TODO: Uncomment when DB_UNKNOWN + db->get_type are implemented. |
569 | /* |
570 | retval = db->get_type(db, &g.opened_dbtype); |
571 | if (retval != 0) { |
572 | PRINT_ERROR(retval, "DB->get_type"); |
573 | goto error; |
574 | } |
575 | if (g.opened_dbtype != DB_BTREE) { |
576 | PRINT_ERRORX("Unsupported db type %d\n", g.opened_dbtype); |
577 | goto error; |
578 | } |
579 | if (g.dbtype != DB_UNKNOWN && g.opened_dbtype != g.dbtype) { |
580 | PRINT_ERRORX("DBTYPE %d does not match opened DBTYPE %d.\n", g.dbtype, g.opened_dbtype); |
581 | goto error; |
582 | }*/ |
583 | return EXIT_SUCCESS; |
584 | error: |
585 | fprintf(stderr, "Quitting out due to errors.\n" ); |
586 | return EXIT_FAILURE; |
587 | } |
588 | |
589 | static int dump_dbt(DBT* dbt) |
590 | { |
591 | char* str; |
592 | uint32_t idx; |
593 | |
594 | assert(dbt); |
595 | str = (char*)dbt->data; |
596 | if (g.leadingspace) printf(" " ); |
597 | if (dbt->size > 0) { |
598 | assert(dbt->data); |
599 | for (idx = 0; idx < dbt->size; idx++) { |
600 | outputbyte(str[idx]); |
601 | if (ferror(stdout)) { |
602 | perror("stdout" ); |
603 | goto error; |
604 | } |
605 | } |
606 | } |
607 | printf("\n" ); |
608 | if (false) { |
609 | error: |
610 | g.exitcode = EXIT_FAILURE; |
611 | } |
612 | return g.exitcode; |
613 | } |
614 | |
615 | int dump_pairs() |
616 | { |
617 | int retval; |
618 | DBT key; |
619 | DBT data; |
620 | DB* db = g.db; |
621 | DBC* dbc = NULL; |
622 | |
623 | memset(&key, 0, sizeof(key)); |
624 | memset(&data, 0, sizeof(data)); |
625 | |
626 | DB_TXN* txn = NULL; |
627 | if (g.recovery_and_txn) { |
628 | retval = g.dbenv->txn_begin(g.dbenv, NULL, &txn, 0); |
629 | if (retval) { |
630 | PRINT_ERROR(retval, "DB_ENV->txn_begin" ); |
631 | goto error; |
632 | } |
633 | } |
634 | |
635 | if ((retval = db->cursor(db, txn, &dbc, 0)) != 0) { |
636 | PRINT_ERROR(retval, "DB->cursor" ); |
637 | goto error; |
638 | } |
639 | while ((retval = dbc->c_get(dbc, &key, &data, DB_NEXT)) == 0) { |
640 | if (caught_any_signals()) goto cleanup; |
641 | if (dump_dbt(&key) != 0) goto error; |
642 | if (dump_dbt(&data) != 0) goto error; |
643 | } |
644 | if (retval != DB_NOTFOUND) { |
645 | PRINT_ERROR(retval, "DBC->c_get" ); |
646 | goto error; |
647 | } |
648 | |
649 | |
650 | if (false) { |
651 | error: |
652 | g.exitcode = EXIT_FAILURE; |
653 | } |
654 | cleanup: |
655 | if (dbc && (retval = dbc->c_close(dbc)) != 0) { |
656 | PRINT_ERROR(retval, "DBC->c_close" ); |
657 | g.exitcode = EXIT_FAILURE; |
658 | } |
659 | if (txn) { |
660 | if (retval) { |
661 | int r2 = txn->abort(txn); |
662 | if (r2) PRINT_ERROR(r2, "DB_TXN->abort" ); |
663 | } |
664 | else { |
665 | retval = txn->commit(txn, 0); |
666 | if (retval) PRINT_ERROR(retval, "DB_TXN->abort" ); |
667 | } |
668 | } |
669 | return g.exitcode; |
670 | } |
671 | |
672 | int close_database() |
673 | { |
674 | DB* db = g.db; |
675 | int retval; |
676 | |
677 | assert(db); |
678 | if ((retval = db->close(db, 0)) != 0) { |
679 | PRINT_ERROR(retval, "DB->close" ); |
680 | goto error; |
681 | } |
682 | return EXIT_SUCCESS; |
683 | error: |
684 | return EXIT_FAILURE; |
685 | } |
686 | |