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 // nested txn straddles the recovery turn around point in the log
40 
41 #include <sys/stat.h>
42 #include "test.h"
43 
44 
45 const int envflags = DB_INIT_MPOOL|DB_CREATE|DB_THREAD |DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_TXN|DB_PRIVATE;
46 
47 const char *namea="a.db";
48 
run_test(void)49 static void run_test (void) {
50     int r;
51 
52     toku_os_recursive_delete(TOKU_TEST_FILENAME);
53     toku_os_mkdir(TOKU_TEST_FILENAME, S_IRWXU+S_IRWXG+S_IRWXO);
54 
55     DB_ENV *env;
56     r = db_env_create(&env, 0);                                                         CKERR(r);
57     r = env->open(env, TOKU_TEST_FILENAME, envflags, S_IRWXU+S_IRWXG+S_IRWXO);                      CKERR(r);
58 
59     DB *db;
60     r = db_create(&db, env, 0);                                                         CKERR(r);
61     r = db->open(db, NULL, namea, NULL, DB_BTREE, DB_AUTO_COMMIT|DB_CREATE, 0666);      CKERR(r);
62 
63     DB_TXN *atxn;
64     r = env->txn_begin(env, NULL, &atxn, 0);                                            CKERR(r);
65 
66     DB_TXN *btxn;
67     r = env->txn_begin(env, atxn, &btxn, 0);                                            CKERR(r);
68 
69     // create a live transaction so that recovery needs to come here
70     DB_TXN *livetxn;
71     r = env->txn_begin(env, NULL, &livetxn, 0);                                         CKERR(r);
72 
73     DBT k,v;
74     dbt_init(&k, "a", 2);
75     dbt_init(&v, "b", 2);
76     r = db->put(db, btxn, &k, &v, 0);                                     CKERR(r);
77     r = btxn->commit(btxn, 0);                                                          CKERR(r);
78 
79     r = atxn->abort(atxn);                                                              CKERR(r);
80 
81     r = db->close(db, 0);                                                               CKERR(r);
82 
83     r = env->txn_checkpoint(env, 0, 0, 0);                                              CKERR(r);
84 
85     // abort the process
86     toku_hard_crash_on_purpose();
87 }
88 
run_recover(void)89 static void run_recover (void) {
90     DB_ENV *env;
91     int r;
92 
93     // run recovery
94     r = db_env_create(&env, 0);                                                         CKERR(r);
95     r = env->open(env, TOKU_TEST_FILENAME, envflags + DB_RECOVER, S_IRWXU+S_IRWXG+S_IRWXO);         CKERR(r);
96 
97     // verify the data
98     DB *db;
99     r = db_create(&db, env, 0);                                                         CKERR(r);
100     r = db->open(db, NULL, namea, NULL, DB_UNKNOWN, DB_AUTO_COMMIT, 0666);              CKERR(r);
101 
102     DB_TXN *txn;
103     r = env->txn_begin(env, NULL, &txn, 0);                                             CKERR(r);
104     DBC *cursor;
105     r = db->cursor(db, txn, &cursor, 0);                                                CKERR(r);
106     DBT k, v;
107     r = cursor->c_get(cursor, dbt_init_malloc(&k), dbt_init_malloc(&v), DB_FIRST);
108     assert(r == DB_NOTFOUND);
109     r = cursor->c_close(cursor);                                                        CKERR(r);
110     r = txn->commit(txn, 0); CKERR(r);
111 
112     r = db->close(db, 0); CKERR(r);
113     r = env->close(env, 0);                                                             CKERR(r);
114     exit(0);
115 }
116 
run_no_recover(void)117 static void run_no_recover (void) {
118     DB_ENV *env;
119     int r;
120 
121     r = db_env_create(&env, 0);                                                         CKERR(r);
122     r = env->open(env, TOKU_TEST_FILENAME, envflags & ~DB_RECOVER, S_IRWXU+S_IRWXG+S_IRWXO);        CKERR(r);
123     r = env->close(env, 0);                                                             CKERR(r);
124     exit(0);
125 }
126 
127 const char *cmd;
128 
129 bool do_test=false, do_recover=false, do_recover_only=false, do_no_recover = false;
130 
test_parse_args(int argc,char * const argv[])131 static void test_parse_args (int argc, char * const argv[]) {
132     int resultcode;
133     cmd = argv[0];
134     argc--; argv++;
135     while (argc>0) {
136 	if (strcmp(argv[0], "-v") == 0) {
137 	    verbose++;
138 	} else if (strcmp(argv[0],"-q")==0) {
139 	    verbose--;
140 	    if (verbose<0) verbose=0;
141 	} else if (strcmp(argv[0], "--test")==0) {
142 	    do_test=true;
143         } else if (strcmp(argv[0], "--recover") == 0) {
144             do_recover=true;
145         } else if (strcmp(argv[0], "--recover-only") == 0) {
146             do_recover_only=true;
147         } else if (strcmp(argv[0], "--no-recover") == 0) {
148             do_no_recover=true;
149 	} else if (strcmp(argv[0], "-h")==0) {
150 	    resultcode=0;
151 	do_usage:
152 	    fprintf(stderr, "Usage:\n%s [-v|-q]* [-h] {--test | --recover } \n", cmd);
153 	    exit(resultcode);
154 	} else {
155 	    fprintf(stderr, "Unknown arg: %s\n", argv[0]);
156 	    resultcode=1;
157 	    goto do_usage;
158 	}
159 	argc--;
160 	argv++;
161     }
162 }
163 
test_main(int argc,char * const argv[])164 int test_main (int argc, char * const argv[]) {
165     test_parse_args(argc, argv);
166     if (do_test) {
167 	run_test();
168     } else if (do_recover) {
169         run_recover();
170     } else if (do_recover_only) {
171         run_recover();
172     } else if (do_no_recover) {
173         run_no_recover();
174     }
175     return 0;
176 }
177