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 // verify that the comparison function get a valid db object pointer
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 const char *namea="a.db";
47 const char *nameb="b.db";
48 
my_compare(DB * UU (db),const DBT * a,const DBT * b)49 static int my_compare(DB *UU(db), const DBT *a, const DBT *b) {
50     assert(db);
51     assert(a->size == b->size);
52     return memcmp(a->data, b->data, a->size);
53 }
54 
55 static void
do_x1_shutdown(bool do_commit,bool do_abort)56 do_x1_shutdown (bool do_commit, bool do_abort) {
57     int r;
58     toku_os_recursive_delete(TOKU_TEST_FILENAME);
59     toku_os_mkdir(TOKU_TEST_FILENAME, S_IRWXU+S_IRWXG+S_IRWXO);
60     DB_ENV *env;
61     DB *dba, *dbb;
62     r = db_env_create(&env, 0);                                                         CKERR(r);
63     r = env->set_default_bt_compare(env, my_compare);                                   CKERR(r);
64     r = env->open(env, TOKU_TEST_FILENAME, envflags, S_IRWXU+S_IRWXG+S_IRWXO);                      CKERR(r);
65     r = db_create(&dba, env, 0);                                                        CKERR(r);
66     r = dba->open(dba, NULL, namea, NULL, DB_BTREE, DB_AUTO_COMMIT|DB_CREATE, 0666);    CKERR(r);
67     r = db_create(&dbb, env, 0);                                                        CKERR(r);
68     r = dbb->open(dbb, NULL, nameb, NULL, DB_BTREE, DB_AUTO_COMMIT|DB_CREATE, 0666);    CKERR(r);
69     DB_TXN *txn;
70     r = env->txn_begin(env, NULL, &txn, 0);                                             CKERR(r);
71     {
72         DBT a,b;
73         dbt_init(&a, "a", 2);
74         dbt_init(&b, "b", 2);
75 	r = dba->put(dba, txn, &a, &b, 0);                                              CKERR(r);
76 	r = env->txn_checkpoint(env, 0, 0, 0);                                          CKERR(r);
77 	r = dba->put(dba, txn, &b, &a, 0);                                              CKERR(r);
78 	r = dbb->put(dbb, txn, &b, &a, 0);                                              CKERR(r);
79     }
80     //printf("opened\n");
81     if (do_commit) {
82 	r = txn->commit(txn, 0);                                                        CKERR(r);
83     } else if (do_abort) {
84         r = txn->abort(txn);                                                            CKERR(r);
85 
86         // force an fsync of the log
87         r = env->txn_begin(env, NULL, &txn, 0);                                         CKERR(r);
88         r = txn->commit(txn, 0);                                                        CKERR(r);
89     }
90     //printf("shutdown\n");
91     toku_hard_crash_on_purpose();
92 }
93 
94 static void
do_x1_recover(bool did_commit)95 do_x1_recover (bool did_commit) {
96     DB_ENV *env;
97     DB *dba, *dbb;
98     int r;
99     r = db_env_create(&env, 0);                                                             CKERR(r);
100     r = env->set_default_bt_compare(env, my_compare);                                       CKERR(r);
101     r = env->open(env, TOKU_TEST_FILENAME, envflags|DB_RECOVER, S_IRWXU+S_IRWXG+S_IRWXO);               CKERR(r);
102     r = db_create(&dba, env, 0);                                                            CKERR(r);
103     r = dba->open(dba, NULL, namea, NULL, DB_BTREE, DB_AUTO_COMMIT|DB_CREATE, 0666);        CKERR(r);
104     r = db_create(&dbb, env, 0);                                                            CKERR(r);
105     r = dba->open(dbb, NULL, nameb, NULL, DB_BTREE, DB_AUTO_COMMIT|DB_CREATE, 0666);        CKERR(r);
106     DBT aa, ab;
107     dbt_init(&aa, NULL, 0);
108     dbt_init(&ab, NULL, 0);
109     DBT ba, bb;
110     dbt_init(&ba, NULL, 0);
111     dbt_init(&bb, NULL, 0);
112     DB_TXN *txn;
113     DBC *ca,*cb;
114     r = env->txn_begin(env, NULL, &txn, 0);                                                 CKERR(r);
115     r = dba->cursor(dba, txn, &ca, 0);                                                      CKERR(r);
116     r = dbb->cursor(dbb, txn, &cb, 0);                                                      CKERR(r);
117     int ra = ca->c_get(ca, &aa, &ab, DB_FIRST);                                             CKERR(r);
118     int rb = cb->c_get(cb, &ba, &bb, DB_FIRST);                                             CKERR(r);
119     if (did_commit) {
120 	assert(ra==0);
121 	assert(rb==0);
122 	// verify key-value pairs
123 	assert(aa.size==2);
124 	assert(ab.size==2);
125 	assert(ba.size==2);
126 	assert(bb.size==2);
127 	const char a[2] = "a";
128 	const char b[2] = "b";
129         assert(memcmp(aa.data, &a, 2)==0);
130         assert(memcmp(ab.data, &b, 2)==0);
131         assert(memcmp(ab.data, &b, 2)==0);
132         assert(memcmp(bb.data, &a, 2)==0);
133 	assert(ca->c_get(ca, &aa, &ab, DB_NEXT) == 0);
134         assert(aa.size == 2 && ab.size == 2 && memcmp(aa.data, b, 2) == 0 && memcmp(ab.data, a, 2) == 0);
135 	// make sure no other entries in DB
136 	assert(ca->c_get(ca, &aa, &ab, DB_NEXT) == DB_NOTFOUND);
137 	assert(cb->c_get(cb, &ba, &bb, DB_NEXT) == DB_NOTFOUND);
138 	fprintf(stderr, "Both verified. Yay!\n");
139     } else {
140 	// It wasn't committed (it also wasn't aborted), but a checkpoint happened.
141 	assert(ra==DB_NOTFOUND);
142 	assert(rb==DB_NOTFOUND);
143 	fprintf(stderr, "Neither present. Yay!\n");
144     }
145     r = ca->c_close(ca);                                                                    CKERR(r);
146     r = cb->c_close(cb);                                                                    CKERR(r);
147     r = txn->commit(txn, 0);                                                                CKERR(r);
148     r = dba->close(dba, 0);                                                                 CKERR(r);
149     r = dbb->close(dbb, 0);                                                                 CKERR(r);
150     r = env->close(env, 0);                                                                 CKERR(r);
151     exit(0);
152 }
153 
154 static void
do_x1_recover_only(void)155 do_x1_recover_only (void) {
156     DB_ENV *env;
157     int r;
158 
159     r = db_env_create(&env, 0);                                                             CKERR(r);
160     r = env->open(env, TOKU_TEST_FILENAME, envflags|DB_RECOVER, S_IRWXU+S_IRWXG+S_IRWXO);                          CKERR(r);
161     r = env->close(env, 0);                                                                 CKERR(r);
162     exit(0);
163 }
164 
165 static void
do_x1_no_recover(void)166 do_x1_no_recover (void) {
167     DB_ENV *env;
168     int r;
169 
170     r = db_env_create(&env, 0);                                                             CKERR(r);
171     r = env->open(env, TOKU_TEST_FILENAME, envflags & ~DB_RECOVER, S_IRWXU+S_IRWXG+S_IRWXO);
172     assert(r == DB_RUNRECOVERY);
173     r = env->close(env, 0);                                                                 CKERR(r);
174     exit(0);
175 }
176 
177 const char *cmd;
178 
179 #if 0
180 
181 static void
182 do_test_internal (bool commit)
183 {
184     pid_t pid;
185     if (0 == (pid=fork())) {
186 	int r=execl(cmd, verbose ? "-v" : "-q", commit ? "--commit" : "--abort", NULL);
187 	assert(r==-1);
188 	printf("execl failed: %d (%s)\n", errno, strerror(errno));
189 	assert(0);
190     }
191     {
192 	int r;
193 	int status;
194 	r = waitpid(pid, &status, 0);
195 	//printf("signaled=%d sig=%d\n", WIFSIGNALED(status), WTERMSIG(status));
196 	assert(WIFSIGNALED(status) && WTERMSIG(status)==SIGABRT);
197     }
198     // Now find out what happend
199 
200     if (0 == (pid = fork())) {
201 	int r=execl(cmd, verbose ? "-v" : "-q", commit ? "--recover-committed" : "--recover-aborted", NULL);
202 	assert(r==-1);
203 	printf("execl failed: %d (%s)\n", errno, strerror(errno));
204 	assert(0);
205     }
206     {
207 	int r;
208 	int status;
209 	r = waitpid(pid, &status, 0);
210 	//printf("recovery exited=%d\n", WIFEXITED(status));
211 	assert(WIFEXITED(status) && WEXITSTATUS(status)==0);
212     }
213 }
214 
215 static void
216 do_test (void) {
217     do_test_internal(true);
218     do_test_internal(false);
219 }
220 
221 #endif
222 
223 
224 bool do_commit=false, do_abort=false, do_explicit_abort=false, do_recover_committed=false,  do_recover_aborted=false, do_recover_only=false, do_no_recover = false;
225 
226 static void
x1_parse_args(int argc,char * const argv[])227 x1_parse_args (int argc, char * const argv[]) {
228     int resultcode;
229     cmd = argv[0];
230     argc--; argv++;
231     while (argc>0) {
232 	if (strcmp(argv[0], "-v") == 0) {
233 	    verbose++;
234 	} else if (strcmp(argv[0],"-q")==0) {
235 	    verbose--;
236 	    if (verbose<0) verbose=0;
237 	} else if (strcmp(argv[0], "--commit")==0 || strcmp(argv[0], "--test") == 0) {
238 	    do_commit=true;
239 	} else if (strcmp(argv[0], "--abort")==0) {
240 	    do_abort=true;
241 	} else if (strcmp(argv[0], "--explicit-abort")==0) {
242 	    do_explicit_abort=true;
243 	} else if (strcmp(argv[0], "--recover-committed")==0 || strcmp(argv[0], "--recover") == 0) {
244 	    do_recover_committed=true;
245 	} else if (strcmp(argv[0], "--recover-aborted")==0) {
246 	    do_recover_aborted=true;
247         } else if (strcmp(argv[0], "--recover-only") == 0) {
248             do_recover_only=true;
249         } else if (strcmp(argv[0], "--no-recover") == 0) {
250             do_no_recover=true;
251 	} else if (strcmp(argv[0], "-h")==0) {
252 	    resultcode=0;
253 	do_usage:
254 	    fprintf(stderr, "Usage:\n%s [-v|-q]* [-h] {--commit | --abort | --explicit-abort | --recover-committed | --recover-aborted } \n", cmd);
255 	    exit(resultcode);
256 	} else {
257 	    fprintf(stderr, "Unknown arg: %s\n", argv[0]);
258 	    resultcode=1;
259 	    goto do_usage;
260 	}
261 	argc--;
262 	argv++;
263     }
264     {
265 	int n_specified=0;
266 	if (do_commit)            n_specified++;
267 	if (do_abort)             n_specified++;
268 	if (do_explicit_abort)    n_specified++;
269 	if (do_recover_committed) n_specified++;
270 	if (do_recover_aborted)   n_specified++;
271 	if (do_recover_only)      n_specified++;
272 	if (do_no_recover)        n_specified++;
273 	if (n_specified>1) {
274 	    printf("Specify only one of --commit or --abort or --recover-committed or --recover-aborted\n");
275 	    resultcode=1;
276 	    goto do_usage;
277 	}
278     }
279 }
280 
281 int
test_main(int argc,char * const argv[])282 test_main (int argc, char * const argv[])
283 {
284     x1_parse_args(argc, argv);
285     if (do_commit) {
286 	do_x1_shutdown (true, false);
287     } else if (do_abort) {
288 	do_x1_shutdown (false, false);
289     } else if (do_explicit_abort) {
290         do_x1_shutdown(false, true);
291     } else if (do_recover_committed) {
292 	do_x1_recover(true);
293     } else if (do_recover_aborted) {
294 	do_x1_recover(false);
295     } else if (do_recover_only) {
296         do_x1_recover_only();
297     } else if (do_no_recover) {
298         do_x1_no_recover();
299     }
300 #if 0
301     else {
302 	do_test();
303     }
304 #endif
305     return 0;
306 }
307