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 // force a checkpoint to span multiple tokulog files. in other words, the begin checkpoint log entry and the
40 // end checkpoint log entry for the same checkpoint are in different log files.
41
42 #include <sys/stat.h>
43 #include "test.h"
44
45 const int envflags = DB_INIT_MPOOL|DB_CREATE|DB_THREAD |DB_INIT_LOCK|DB_INIT_LOG|DB_INIT_TXN|DB_PRIVATE;
46
test_checkpoint_callback(void * extra)47 static void test_checkpoint_callback(void *extra) {
48 int r;
49 DB_ENV *env = (DB_ENV *) extra;
50
51 // create and commit a bunch of transactions. the last commit fsync's the log. since the log is
52 // really small, a new log file is created before the end checkpoint is logged.
53 int i;
54 for (i=0; i<100; i++) {
55 DB_TXN *txn = NULL;
56 r = env->txn_begin(env, NULL, &txn, 0); CKERR(r);
57 r = txn->commit(txn, i == 99 ? DB_TXN_SYNC : 0); CKERR(r);
58 }
59 }
60
test_checkpoint_callback2(void * extra)61 static void test_checkpoint_callback2(void *extra) {
62 (void) extra;
63 }
64
run_test(bool do_commit,bool do_abort)65 static void run_test (bool do_commit, bool do_abort) {
66 int r;
67 toku_os_recursive_delete(TOKU_TEST_FILENAME);
68 toku_os_mkdir(TOKU_TEST_FILENAME, S_IRWXU+S_IRWXG+S_IRWXO);
69
70 DB_ENV *env = NULL;
71 r = db_env_create(&env, 0); CKERR(r);
72
73 db_env_set_checkpoint_callback(test_checkpoint_callback, env);
74 db_env_set_checkpoint_callback2(test_checkpoint_callback2, env);
75
76 r = env->set_lg_max(env, 1024); CKERR(r);
77 r = env->open(env, TOKU_TEST_FILENAME, envflags, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
78
79 DB_TXN *txn = NULL;
80 r = env->txn_begin(env, NULL, &txn, 0); CKERR(r);
81
82 r = env->txn_checkpoint(env, 0, 0, 0); CKERR(r);
83
84 if (do_commit) {
85 r = txn->commit(txn, 0); CKERR(r);
86 } else if (do_abort) {
87 r = txn->abort(txn); CKERR(r);
88
89 // force an fsync of the log
90 r = env->txn_begin(env, NULL, &txn, 0); CKERR(r);
91 r = txn->commit(txn, 0); CKERR(r);
92 }
93 //printf("shutdown\n");
94 toku_hard_crash_on_purpose();
95 }
96
run_recover(bool did_commit)97 static void run_recover (bool did_commit) {
98 (void) did_commit;
99 int r;
100 DB_ENV *env = NULL;
101 r = db_env_create(&env, 0); CKERR(r);
102 r = env->open(env, TOKU_TEST_FILENAME, envflags|DB_RECOVER, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
103 r = env->close(env, 0); CKERR(r);
104 }
105
run_recover_only(void)106 static void run_recover_only (void) {
107 int r;
108 DB_ENV *env = NULL;
109 r = db_env_create(&env, 0); CKERR(r);
110 r = env->open(env, TOKU_TEST_FILENAME, envflags|DB_RECOVER, S_IRWXU+S_IRWXG+S_IRWXO); CKERR(r);
111 r = env->close(env, 0); CKERR(r);
112 }
113
run_no_recover(void)114 static void run_no_recover (void) {
115 int r;
116 DB_ENV *env = NULL;
117 r = db_env_create(&env, 0); CKERR(r);
118 r = env->open(env, TOKU_TEST_FILENAME, envflags & ~DB_RECOVER, S_IRWXU+S_IRWXG+S_IRWXO);
119 assert(r == DB_RUNRECOVERY);
120 r = env->close(env, 0); CKERR(r);
121 }
122
123 const char *cmd;
124
125
126 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;
127
test_parse_args(int argc,char * const argv[])128 static void test_parse_args (int argc, char * const argv[]) {
129 int resultcode;
130 cmd = argv[0];
131 argc--; argv++;
132 while (argc>0) {
133 if (strcmp(argv[0], "-v") == 0) {
134 verbose++;
135 } else if (strcmp(argv[0],"-q")==0) {
136 verbose--;
137 if (verbose<0) verbose=0;
138 } else if (strcmp(argv[0], "--commit")==0 || strcmp(argv[0], "--test") == 0) {
139 do_commit=true;
140 } else if (strcmp(argv[0], "--abort")==0) {
141 do_abort=true;
142 } else if (strcmp(argv[0], "--explicit-abort")==0) {
143 do_explicit_abort=true;
144 } else if (strcmp(argv[0], "--recover-committed")==0 || strcmp(argv[0], "--recover") == 0) {
145 do_recover_committed=true;
146 } else if (strcmp(argv[0], "--recover-aborted")==0) {
147 do_recover_aborted=true;
148 } else if (strcmp(argv[0], "--recover-only") == 0) {
149 do_recover_only=true;
150 } else if (strcmp(argv[0], "--no-recover") == 0) {
151 do_no_recover=true;
152 } else if (strcmp(argv[0], "-h")==0) {
153 resultcode=0;
154 do_usage:
155 fprintf(stderr, "Usage:\n%s [-v|-q]* [-h] {--commit | --abort | --explicit-abort | --recover-committed | --recover-aborted } \n", cmd);
156 exit(resultcode);
157 } else {
158 fprintf(stderr, "Unknown arg: %s\n", argv[0]);
159 resultcode=1;
160 goto do_usage;
161 }
162 argc--;
163 argv++;
164 }
165 {
166 int n_specified=0;
167 if (do_commit) n_specified++;
168 if (do_abort) n_specified++;
169 if (do_explicit_abort) n_specified++;
170 if (do_recover_committed) n_specified++;
171 if (do_recover_aborted) n_specified++;
172 if (do_recover_only) n_specified++;
173 if (do_no_recover) n_specified++;
174 if (n_specified>1) {
175 printf("Specify only one of --commit or --abort or --recover-committed or --recover-aborted\n");
176 resultcode=1;
177 goto do_usage;
178 }
179 }
180 }
181
test_main(int argc,char * const argv[])182 int test_main (int argc, char * const argv[]) {
183 test_parse_args(argc, argv);
184 if (do_commit) {
185 run_test(true, false);
186 } else if (do_abort) {
187 run_test(false, true);
188 } else if (do_recover_committed) {
189 run_recover(true);
190 } else if (do_recover_aborted) {
191 run_recover(false);
192 } else if (do_recover_only) {
193 run_recover_only();
194 } else if (do_no_recover) {
195 run_no_recover();
196 }
197 return 0;
198 }
199