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